教程·阅读约 3 分钟·
Pyodide 314.0 发布:Python 包可直接发布 WebAssembly wheels 到 PyPI

Pyodide 314.0 发布:Python 包可直接发布 WebAssembly wheels 到 PyPI

Pyodide 314.0 迎来里程碑式更新:PEP 783 被正式采纳,Python 包维护者现在可以将 Emscripten 平台的 WebAssembly wheels 直接发布到 PyPI,无需经过 Pyodide 核心团队的手动构建。

原文来源:Pyodide 官方博客 — Pyodide 314.0 正式发布,PEP 783 让 Python 包可直接发布 WebAssembly wheels 到 PyPI,版本号与 Python 3.14 对齐,恢复了 ssl/sqlite3/lzma 标准库,新增原生 ES Module 支持和实验性 Node.js Socket 支持。

发生了什么?

Pyodide 314.0 刚刚发布了。这可不是一次普通的版本号递增——这是 Pyodide 历史上最重要的一次平台升级

如果你还不熟悉 Pyodide,简单说它就是一个把 CPython 编译到 WebAssembly 的项目,让你能在浏览器里直接运行 Python,不需要任何服务器端。NumPy、Pandas、Matplotlib、SciPy 这些重量级科学计算库,全都能在浏览器里跑。

而 314.0 版本的核心变化是:PEP 783 被 Python 指导委员会正式采纳了

—— 广告 ——

PEP 783 到底意味着什么?

这是本次更新最值得关注的事情。

以前是什么样?

在过去,如果你的 Python 包包含 C 扩展(比如说你用 Cython 写了一些加速代码),想要在 Pyodide 里运行,你得走这条路:

  1. 你的包必须被 Pyodide 核心团队收录到他们的「300+ 内置包列表」里
  2. Pyodide 团队手动用 Emscripten 交叉编译你的包
  3. 用户通过 pyodide.loadPackage('你的包名') 才能加载

这意味着你的包的发布节奏完全受制于 Pyodide 的发布周期。你修了个 bug,发布了新版本,但用户要等到下一个 Pyodide 版本才能用上。

现在呢?

PEP 783 定义了一个新的 Python 平台标签:pyemscripten_2026_0(对应 Python 3.14 / Pyodide 314.x)和 pyemscripten_2025_0(对应 Python 3.13 / Pyodide 0.29.x)。

这意味着:

你作为包维护者,可以直接用 pyodide-build 或 cibuildwheel 编译出带 pyemscripten 标签的 wheel,把它上传到 PyPI。用户在 Pyodide 里用 micropip.install('你的包') 就能安装了。

简单说:从 Pyodide 内置 → 发布到 PyPI,从「等官方收录」变成「自己发布」

cibuildwheel 已经支持了

如果你已经在用 cibuildwheel 做 CI 自动化构建,好消息是 cibuildwheel v4.0 已经支持 PyEmscripten 2025 和 2026 ABI(2026 版目前是 prerelease,v4.1.0 会稳定化)。

这意味着你在 CI 配置里加上 Emscripten 平台,就能在每次发布时自动构建跨平台的 wheel,包括 WebAssembly 版本。整个流程和发布一个 Linux x86_64 wheel 没有本质区别。

动手:如何构建你的第一个 WebAssembly wheel

纯 Python 包(无需额外操作)

如果你的包是纯 Python(没有 C 扩展),你什么都不用做。标准 wheel(用 python -m buildhatchflit 等工具构建)已经在 Pyodide 中兼容。用户直接:

code
import micropip
await micropip.install("your-package")

带 C 扩展的包

如果你的包包含 C 扩展,需要用到 pyodide-build——它是 PEP 783 的参考构建工具链。

安装:

code
pip install pyodide-build

构建:

code
pyodide build .

这会生成一个像这样的 wheel 文件:

code
your_package-1.0-cp314-cp314-pyemscripten_2026_0_wasm32.whl

这个 wheel 可以直接上传到 PyPI:

code
twine upload dist/*pyemscripten*

pyodide-build 的工作原理是包装了标准的 pypa/build,加上一个交叉编译层。当你运行 pyodide build 时,它:

  1. 设置 Emscripten 编译环境(包含 CPython 头文件)
  2. 拦截编译器调用(gccemccg++em++ld → 对应 Emscripten 链接器)
  3. 将编译器标志转换为 WebAssembly 兼容格式
  4. 输出带正确平台标签的标准 wheel

你的 setup.pypyproject.tomlCMakeLists.txtmeson.build 都不需要改动——pyodide-build 透明地处理交叉编译。

更详细指引见 pyodide-build 官方文档

版本号变了:314.x = Python 3.14

Pyodide 314.0 带来了一个新的版本号方案:

Pyodide 的版本号直接对应 Python 的版本号。314.0 = Python 3.14 的第一个兼容版本。

以前 Pyodide 用 0.x 版本号(比如 0.29.x),用户很难一眼看出它对应哪个 Python 版本。现在一目了然:如果 Pyodide 发布 314.5,那它肯定对应 Python 3.14.5。

这个版本对应 Python 3.14.2Emscripten 5.0.3。以后每年一个主版本,跟着 CPython 的发布节奏走。

标准库变化:三大回归

这个版本恢复了三个之前被剥离的标准库模块:

  • ssl — 虽然不再基于 OpenSSL(OpenSSL 已从 Pyodide 中移除),但实现了一个自定义版本,保留了大部分非加密功能。真正的 SSL/TLS 功能在浏览器环境中本来就不起作用,所以实际影响有限
  • sqlite3 — SQLite 数据库支持完全恢复正常
  • lzma — LZMA 压缩库回来了

这三个库的回归意味着更大的初始下载体积,但用户不再需要单独安装它们。对于用 SQLite 做本地存储、用 lzma 解压数据的应用来说,这是实实在在的便利。

顺便提一句,由于移除了 OpenSSL,hashlib 也失去了部分依赖 OpenSSL 的加密哈希函数。如果你在浏览器中需要完整密码学功能,建议通过 Web Crypto API 来补充。

同时,Python 3.14 新自带的 compression.zstd 模块在 Pyodide 中也可用,开箱即用。

ES Module 迁移:告别 .js 后缀

pyodide.asm.js 被重命名为 pyodide.asm.mjs。如果你在项目中直接引用这个文件,需要更新引用路径:

code
// 旧方式(不再支持)
// import createPyodideModule from "./pyodide.asm.js";
 
// 新方式
import createPyodideModule from "./pyodide.asm.mjs";
import { loadPyodide } from "./pyodide.mjs";
 
loadPyodide({ createPyodideModule }).then((pyodide) => {
  // 你的 Python 代码
});

需要注意:classic(非 module)worker 模式不再支持。所有 worker 代码必须使用 type: "module"

Node.js 也能用了:实验性 Socket 支持

这是一个很多人期待的功能——Pyodide 现在可以在 Node.js 中创建 TCP 套接字了。

code
const pyodide = await loadPyodide();
await pyodide.useNodeSockFS();

启用后,你就可以在 Node.js 的 Pyodide 环境中连接数据库了。官方已测试兼容:

  • pymysql — 连接 MySQL
  • pg8000 — 连接 PostgreSQL
  • redis-py — 连接 Redis

支持 TCP 带 TLS、异步套接字函数和非阻塞模式。如果你用的是 Node.js v24 或更早版本,需要加 --experimental-wasm-stack-switching 参数来启用 JSPI。

JavaScript 互操作的大升级

JsBigInt:不再丢失精度

pyodide.ffi.JsBigInt 是一个新的 int 子类,专门用来保留 JavaScript 的 bigint 类型。当你把 JavaScript 的 BigInt 传给 Python 时,不会因为精度丢失变成普通的 Python int。对于需要处理 2^53 以上大数的应用来说,这个功能很关键。

资源管理:using / with

JavaScript 端PyProxyPyBufferView 现在实现了 [Symbol.dispose],你可以用 JavaScript 的 using 关键字来自动清理:

code
{
  using proxy = pyodide.runPython("some_object()");
  // proxy 在代码块结束时自动销毁
}

Python 端:任何实现了 [Symbol.dispose]() 的 JavaScript 对象都可以在 Python 中当上下文管理器用:

code
with js_object as x:
    ...  # 退出时自动调用 x[Symbol.dispose]()

异步版本([Symbol.asyncDispose])也支持,适用于需要 await 清理的场景。

更好的类数组支持

以前,JavaScript 的类数组对象(有 length 属性且可迭代)在 Python 中只能通过循环访问元素。现在它们支持下标操作了:

code
proxy[1:4]   # 返回索引 1 到 3 的切片
proxy[::2]   # 每隔一个元素

这对于处理 JavaScript 的 TypedArray、NodeList 等类数组对象非常方便。

这对开发者意味着什么?

如果你在用 Pyodide 做浏览器端 Python 开发:

  1. sqlite3 回归让你可以直接在浏览器里用 SQLite 做本地存储,不用再自己找替代方案
  2. cibuildwheel 支持意味着你可以把 WebAssembly 纳入你的 CI/CD 工作流,每次发布自动构建
  3. ES Module 支持让 Pyodide 更好地融入现代前端工具链
  4. Node.js Socket 支持让你能把 Pyodide 用在后端场景,比如 Edge Function 或 Serverless 环境

如果你只是想在浏览器里跑 Python 代码:

  • 访问 pyodide.org 的官方 REPL
  • 在你的 HTML 页面中引入 Pyodide:<script src="https://cdn.jsdelivr.net/pyodide/v0.29.0/full/pyodide.js"></script>
  • await micropip.install("包名") 加载你需要的数据科学包

Pyodide 314.0 最令人兴奋的地方,不是它新增了多少功能,而是它让 Python 生态和 WebAssembly 生态的融合变得更加顺畅。当包维护者可以像发布普通 wheel 一样发布 WebAssembly wheel 时,浏览器里的 Python 就不再是一个需要额外维护的「二等公民」,而是 Python 生态真正的扩展。

分享到
微博Twitter

© 2026 四月 · CC BY-NC-SA 4.0

原文链接:https://aprilzz.com/tutorials/pyodide-314-wasm-wheels