<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Pyodide и TypeScript: запускаем Python в браузере]]></title><description><![CDATA[<p dir="auto"><img src="/assets/uploads/files/85/8c/5e/1774075044655-generated_1774075020715.webp" alt="Обложка: Как интегрировать Pyodide с TypeScript для запуска Python в браузере: гайд по Transcrypt и PyNode 2026" class=" img-fluid img-markdown" /></p>
<p dir="auto">Представьте, что вы пишете веб-приложение и вам нужно выполнить сложные расчёты или обработку данных прямо в браузере, без обращения к серверу. Python идеально подходит для таких задач, но как его туда засунуть? Тут на сцену выходит Pyodide - штука, которая позволяет запускать полноценный Python внутри браузера через WebAssembly.</p>
<p dir="auto">Если вы разработчик, пишущий на TypeScript, то интеграция Pyodide открывает кучу возможностей: обработка данных на клиенте, запуск NumPy и Pandas, автоматизация рутинных операций. Статья расскажет, как это всё настроить и заставить работать, не прибегая к магии и не теряя прическу.</p>
<h2>Что такое Pyodide и почему это вообще нужно</h2>
<p dir="auto">Pyodide - это порт Python на WebAssembly, который позволяет запускать Python код прямо в браузере. Звучит нереально? На самом деле это работает благодаря Emscripten, который компилирует код из C в WebAssembly. Pyodide уже идёт с большим стандартным набором библиотек и поддерживает установку чистых Python пакетов через micropip.</p>
<p dir="auto">Почему это полезно? Во-первых, вы экономите нагрузку на сервер - тяжёлые вычисления делаются на машине пользователя. Во-вторых, пользователь получает результаты быстрее, потому что не нужно ждать ответа от сервера. В-третьих, это просто мощный инструмент для создания интерактивных приложений с поддержкой Python.</p>
<p dir="auto"><strong>Основные возможности Pyodide:</strong></p>
<ul>
<li>Запуск любого Python кода в браузере</li>
<li>Поддержка чистых Python пакетов (NumPy, Pandas, SciPy и другие)</li>
<li>Двусторонняя интеграция между Python и JavaScript</li>
<li>Полная поддержка async/await для асинхронных операций</li>
<li>Доступ ко всем Web API из Python кода</li>
</ul>
<h2>Первые шаги: загружаем Pyodide в браузер</h2>
<p dir="auto">Загрузить Pyodide в проект - это проще простого. Нужно подключить скрипт с CDN и дождаться инициализации. Звучит как две строки кода, и это почти правда, но есть пара нюансов, которые стоит знать с самого начала.</p>
<p dir="auto">Прежде всего, инициализация Pyodide асинхронная, поэтому вы не можете просто взять и запустить Python код сразу после загрузки скрипта. Нужно дождаться, пока <code>loadPyodide()</code> выполнится. Это важно, потому что под капотом происходит загрузка и распаковка больших файлов (WebAssembly бинарники, стандартная библиотека Python).</p>
<p dir="auto"><strong>Минимальная настройка в HTML:</strong></p>
<pre><code class="language-html">&lt;!doctype html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;script src="https://cdn.jsdelivr.net/pyodide/v0.29.3/full/pyodide.js"&gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;input id="code" value="sum([1, 2, 3, 4, 5])" /&gt;
  &lt;button onclick="evaluatePython()"&gt;Run&lt;/button&gt;
  &lt;textarea id="output" disabled&gt;&lt;/textarea&gt;

  &lt;script&gt;
    let pyodideReadyPromise = loadPyodide();

    async function evaluatePython() {
      let pyodide = await pyodideReadyPromise;
      try {
        let result = pyodide.runPython(
          document.getElementById("code").value
        );
        document.getElementById("output").value = result;
      } catch (err) {
        document.getElementById("output").value = err;
      }
    }
  &lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p dir="auto">Видите? Мы создаём промис <code>pyodideReadyPromise</code> один раз при загрузке страницы, а потом просто ждём его перед каждым запуском Python кода. Это гораздо эффективнее, чем инициализировать Pyodide заново каждый раз.</p>
<p dir="auto"><strong>Что происходит под капотом:</strong></p>
<ul>
<li>Загружается <code>pyodide.js</code> - обёртка над WebAssembly</li>
<li>Скачиваются <code>pyodide.asm.js</code> и <code>pyodide.asm.wasm</code> файлы</li>
<li>Инициализируется Python интерпретатор</li>
<li>Становится доступна функция <code>runPython()</code></li>
</ul>
<h2>Интеграция с TypeScript: типизируем Pyodide</h2>
<p dir="auto">Если вы уже пишете на TypeScript, то понимаете, что работать без типов - это как ездить вслепую. Pyodide поставляется с TypeScript типами, что уже хорошо, но есть нюанс: типы для Python объектов требуют особого внимания.</p>
<p dir="auto">Pyodide предоставляет интерфейсы для работы с Python кодом из JavaScript. Есть <code>PyProxy</code> - обёртка над Python объектом, которая позволяет вызывать методы и получать результаты. Есть <code>JsProxy</code> - зеркальное отображение для доступа к JavaScript из Python. Оба работают с типами, но нужно понимать, как они себя ведут.</p>
<p dir="auto">Одна из ключевых фишек в свежих версиях - методы <code>asJsJson()</code> и планируемый <code>as_py_json()</code>, которые позволяют конвертировать объекты между языками без заморочек с кодировкой.</p>
<p dir="auto"><strong>Установка типов и базовая конфигурация:</strong></p>
<p dir="auto">Если вы используете npm, просто добавьте Pyodide в проект:</p>
<pre><code class="language-bash">npm install "pyodide@&gt;=0.21.0-alpha.2"
</code></pre>
<p dir="auto">А дальше в TypeScript файле:</p>
<pre><code class="language-typescript">import { loadPyodide } from 'pyodide';

async function initPyodide() {
  const pyodide = await loadPyodide();
  const result = pyodide.runPython('1 + 1');
  console.log(result); // 2
}
</code></pre>
<p dir="auto">Типы уже будут подтягиваться автоматически. IDE подскажет вам доступные методы и их сигнатуры. Это намного удобнее, чем работать с <code>any</code> или какими-то угадываниями.</p>
<p dir="auto"><strong>Часто используемые типы в Pyodide:</strong></p>
<ul>
<li><code>PyProxy</code> - Python объект, доступный из JavaScript</li>
<li><code>JsProxy</code> - JavaScript объект, видимый из Python</li>
<li><code>PyCallable</code> - Python функция, которую можно вызвать</li>
<li><code>PyDict</code>, <code>PyList</code> - специфичные типы контейнеров</li>
</ul>
<h2>Двусторонняя интеграция: Python вызывает JavaScript</h2>
<p dir="auto">Так, мы научились запускать Python код из браузера. Но что, если нам нужно из Python вызвать JavaScript функцию? Например, нужно обновить DOM, отправить запрос на сервер или использовать браузерное API.</p>
<p dir="auto">Pyodide позволяет добавлять JavaScript функции в глобальное пространство Python. Это делается через <code>pyodide.globals.set()</code>. Магия в том, что функции работают как обычно, но можно передавать между языками данные и даже обрабатывать ошибки кроссязычно.</p>
<p dir="auto">Есть важный момент с асинхронностью. Если вы хотите из Python кода вызвать асинхронную JavaScript функцию (например, fetch), нужно использовать <code>async def</code> и await. Pyodide это поддерживает, но нужно помнить о том, что runPython синхронный, а для асинхронного кода есть <code>runPythonAsync()</code>.</p>
<p dir="auto"><strong>Пример: вызов fetch из Python:</strong></p>
<pre><code class="language-python">from js import fetch, Object
from pyodide.ffi import to_js

async def python_fetch(url: str, options: dict):
    response = await fetch(url, to_js(options, dict_converter=Object.fromEntries))
    return response
</code></pre>
<p dir="auto">А вот как добавить функцию в Python глобальное пространство из JavaScript:</p>
<pre><code class="language-typescript">const pyodide = await loadPyodide();

// Добавляем функцию
pyodide.globals.set('alert', alert);
pyodide.globals.set('square', (x: number) =&gt; x * x);

// Вызываем из Python
pyodide.runPython('square(5)'); // 25
</code></pre>
<p dir="auto"><strong>Конверсия типов при передаче данных:</strong></p>
<ul>
<li>Python <code>int</code> <img src="https://forum.exlends.ru/assets/plugins/nodebb-plugin-emoji/emoji/android/2194.png?v=a1e94250dac" class="not-responsive emoji emoji-android emoji--left_right_arrow" style="height:23px;width:auto;vertical-align:middle" title="↔" alt="↔" /> JavaScript <code>number</code></li>
<li>Python <code>str</code> <img src="https://forum.exlends.ru/assets/plugins/nodebb-plugin-emoji/emoji/android/2194.png?v=a1e94250dac" class="not-responsive emoji emoji-android emoji--left_right_arrow" style="height:23px;width:auto;vertical-align:middle" title="↔" alt="↔" /> JavaScript <code>string</code></li>
<li>Python <code>list</code> <img src="https://forum.exlends.ru/assets/plugins/nodebb-plugin-emoji/emoji/android/2194.png?v=a1e94250dac" class="not-responsive emoji emoji-android emoji--left_right_arrow" style="height:23px;width:auto;vertical-align:middle" title="↔" alt="↔" /> JavaScript <code>Array</code></li>
<li>Python <code>dict</code> <img src="https://forum.exlends.ru/assets/plugins/nodebb-plugin-emoji/emoji/android/2194.png?v=a1e94250dac" class="not-responsive emoji emoji-android emoji--left_right_arrow" style="height:23px;width:auto;vertical-align:middle" title="↔" alt="↔" /> JavaScript <code>Object</code></li>
<li>Python <code>None</code> <img src="https://forum.exlends.ru/assets/plugins/nodebb-plugin-emoji/emoji/android/2194.png?v=a1e94250dac" class="not-responsive emoji emoji-android emoji--left_right_arrow" style="height:23px;width:auto;vertical-align:middle" title="↔" alt="↔" /> JavaScript <code>undefined</code></li>
</ul>
<p dir="auto">Для сложных объектов используйте <code>to_js()</code> и получайте <code>asJsJson()</code> для безопасной конверсии.</p>
<h2>Node.js и SSR: Pyodide на сервере</h2>
<p dir="auto">А вот интересный момент - Pyodide работает не только в браузере, но и в Node.js. Да, это звучит странно, но работает. Это может быть полезно для тестирования, Server-Side Rendering или просто для того, чтобы иметь одну кодовую базу для фронта и бека.</p>
<p dir="auto">На Node.js Pyodide работает медленнее, чем встроенный Python, поэтому это не замена нативному Python интерпретатору. Но если вам нужно запустить какой-то специфичный код, который работает в браузере, то это отличный способ тестировать его локально перед развёртыванием.</p>
<p dir="auto">Установка в Node.js идентична браузеру - через npm, затем просто импортируете и используете. Есть даже REPL для экспериментов прямо в терминале.</p>
<p dir="auto"><strong>Запуск Python в Node.js:</strong></p>
<pre><code class="language-typescript">const { loadPyodide } = require('pyodide');

async function runPythonInNode() {
  const pyodide = await loadPyodide();
  const result = await pyodide.runPythonAsync('import numpy as np; np.array([1,2,3])'); 
  console.log(result);
}

runPythonInNode();
</code></pre>
<p dir="auto">Отметим, что в Node.js нужно использовать <code>runPythonAsync()</code> вместо <code>runPython()</code>, потому что асинхронность в Node.js работает по-другому.</p>
<h2>Установка пакетов: micropip и готовые wheels</h2>
<p dir="auto">Стандартная библиотека Python уже идёт с Pyodide, но что, если вам нужен NumPy, Pandas или какой-то другой пакет? Тут в дело вступает micropip - менеджер пакетов для Pyodide.</p>
<p dir="auto">micropip может установить любой чистый Python пакет (то есть без C расширений). Пакеты с C код вроде NumPy и SciPy уже скомпилированы в WebAssembly и идут в составе Pyodide по умолчанию. Некоторые популярные пакеты предкомпилированы, а остальные можно установить, если у них есть wheel на PyPi.</p>
<p dir="auto">Процесс установки простой - импортируете micropip, вызываете <code>install()</code> и ждёте. Это может занять пару секунд, потому что скачиваются файлы, поэтому лучше показать пользователю спиннер или прогресс.</p>
<p dir="auto"><strong>Пример установки пакетов:</strong></p>
<pre><code class="language-python">import micropip

await micropip.install('requests')
await micropip.install('beautifulsoup4')

import requests
import bs4
</code></pre>
<p dir="auto"><strong>Предустановленные пакеты в Pyodide:</strong></p>
<ul>
<li>NumPy</li>
<li>Pandas</li>
<li>SciPy</li>
<li>Matplotlib</li>
<li>scikit-learn</li>
<li>PIL (Pillow)</li>
<li>И многие другие</li>
</ul>
<p dir="auto">Если пакета нет в списке предустановленных, но он доступен на PyPi как чистый Python, micropip установит его автоматически при первом импорте (если вы предварительно вызовите <code>micropip.install()</code>).</p>
<h2>Практический пример: расчётчик с интерфейсом</h2>
<p dir="auto">Давайте соберём всё вместе и создадим простой пример - калькулятор, который принимает выражение Python, выполняет его и выводит результат. Добавим к этому обработку ошибок и TypeScript типизацию.</p>
<p dir="auto"><strong>HTML структура:</strong></p>
<pre><code class="language-html">&lt;!DOCTYPE html&gt;
&lt;html&gt;
&lt;head&gt;
  &lt;script src="https://cdn.jsdelivr.net/pyodide/v0.29.3/full/pyodide.js"&gt;&lt;/script&gt;
  &lt;style&gt;
    body { font-family: sans-serif; padding: 20px; }
    input, button { padding: 10px; }
    textarea { width: 100%; height: 200px; margin-top: 10px; }
  &lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
  &lt;h1&gt;Python калькулятор в браузере&lt;/h1&gt;
  &lt;input id="expression" placeholder="Введите выражение Python" value="2 ** 10" /&gt;
  &lt;button onclick="calculate()"&gt;Вычислить&lt;/button&gt;
  &lt;textarea id="output" readonly&gt;&lt;/textarea&gt;
  &lt;script src="calculator.js"&gt;&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;
</code></pre>
<p dir="auto"><strong>TypeScript код:</strong></p>
<pre><code class="language-typescript">import { loadPyodide, PyProxy } from 'pyodide';

let pyodideReady: Promise&lt;any&gt;;

async function initPyodide() {
  pyodideReady = loadPyodide();
  const pyodide = await pyodideReady;
  
  // Добавляем встроенные функции из браузера
  pyodide.globals.set('console_log', console.log);
  
  // Загружаем NumPy если нужно
  await pyodide.loadPackage('numpy');
  
  console.log('Pyodide инициализирован');
}

async function calculate() {
  const pyodide = await pyodideReady;
  const expression = (document.getElementById('expression') as HTMLInputElement).value;
  const output = document.getElementById('output') as HTMLTextAreaElement;
  
  try {
    output.value = 'Выполняем...\n';
    
    const result = pyodide.runPython(`
result = ${expression}
print(f'Результат: {result}')
result
    `);
    
    output.value += `✓ ${result}\n`;
  } catch (err) {
    output.value = `✗ Ошибка: ${err}\n`;
  }
}

// Инициализируем при загрузке
initPyodide();
(window as any).calculate = calculate;
</code></pre>
<p dir="auto">Вот так просто - у вас есть полнофункциональный интерпретатор Python в браузере с TypeScript типизацией.</p>
<h2>Откуда бежать после первого запуска</h2>
<p dir="auto">Если вы начали разбираться с Pyodide, то понимаете, что это мощный инструмент, но не панацея. Во-первых, производительность Pyodide медленнее нативного Python примерно в 2-3 раза, потому что это WebAssembly. Для большинства web-приложений этого хватает, но если нужны serious вычисления, можно подумать о Worker API или делегировать часть работы на сервер.</p>
<p dir="auto">Во-вторых, не все Python библиотеки работают в браузере - только те, которые написаны на чистом Python или уже скомпилированы под WebAssembly. Если вам нужна какая-то специфичная библиотека с C расширениями, придётся либо ждать, пока её скомпилируют для Pyodide, либо искать альтернативу.</p>
<p dir="auto">А что насчёт будущего? TypeScript интеграция становится всё лучше, генерируются типы для Python стандартной библиотеки, развивается поддержка SSR сценариев. В целом экосистема живая и движется в правильном направлении.</p>
]]></description><link>https://forum.exlends.ru/topic/1794/pyodide-i-typescript-zapuskaem-python-v-brauzere</link><generator>RSS for Node</generator><lastBuildDate>Sat, 17 Oct 2026 03:25:51 GMT</lastBuildDate><atom:link href="https://forum.exlends.ru/topic/1794.rss" rel="self" type="application/rss+xml"/><pubDate>Sat, 21 Mar 2026 06:37:24 GMT</pubDate><ttl>60</ttl></channel></rss>