Working with Bundlers#
When using Pyodide with bundlers, there are two main approaches:
Loading from a CDN - This is the simplest approach and sufficient for most use cases
Bundling Pyodide files - For applications that need to work offline or have specific hosting requirements
Using Pyodide from a CDN#
For most applications, the simplest approach is to use Pyodide from a CDN by setting the indexURL parameter:
import { loadPyodide, version as pyodideVersion } from "pyodide";
async function initPyodide() {
const pyodide = await loadPyodide({
indexURL: `https://cdn.jsdelivr.net/pyodide/v${pyodideVersion}/full/`,
});
return pyodide;
}
This approach works with most bundlers without additional configuration and is recommended for most users.
Bundling Pyodide Files#
If you need to bundle all Pyodide files with your application (for offline use or self-hosting), follow the instructions below for your specific bundler.
Webpack#
There is a Pyodide Webpack Plugin to load Pyodide from a local bundle in a Webpack project.
Vite#
Note
The following instructions have been tested with Pyodide 0.26.2, Vite 5.4.9, and vite-plugin-static-copy 2.0.0.
First, install the Pyodide and vite-plugin-static-copy npm packages:
$ npm install pyodide vite-plugin-static-copy
Then, in your vite.config.mjs file, exclude Pyodide from Vite’s dependency
pre-bundling by setting optimizeDeps.exclude and ensure that
all Pyodide files will be available in dist/assets for production builds by
using a Vite plugin:
import { defineConfig } from "vite";
import { viteStaticCopy } from "vite-plugin-static-copy";
import { dirname, join } from "path";
import { fileURLToPath } from "url";
const PYODIDE_EXCLUDE = [
"!**/*.{md,html}",
"!**/*.d.ts",
"!**/*.whl",
"!**/pyodide/node_modules",
];
export function viteStaticCopyPyodide() {
const pyodideDir = dirname(fileURLToPath(import.meta.resolve("pyodide")));
return viteStaticCopy({
targets: [
{
src: [join(pyodideDir, "*").replace(/\\/g, "/")].concat(
PYODIDE_EXCLUDE
),
dest: "assets",
},
],
});
}
export default defineConfig({
optimizeDeps: { exclude: ["pyodide"] },
plugins: [viteStaticCopyPyodide()],
});
You can test your setup with this index.html file:
<!DOCTYPE html>
<html lang="en">
<head>
<title>Vite + Pyodide</title>
<script type="module" src="main.mjs"></script>
</head>
</html>
And this src/main.mjs file:
import { loadPyodide } from "pyodide";
async function hello_python() {
let pyodide = await loadPyodide();
return pyodide.runPythonAsync("1+1");
}
hello_python().then((result) => {
console.log("Python says that 1+1 =", result);
});
Handling Packages#
Since .whl package files are excluded from the bundle, you have two options:
Option 1: Load packages from CDN#
Add a packageBaseUrl pointing to the CDN when loading Pyodide:
import { loadPyodide, version } from "pyodide";
const pyodide = await loadPyodide({
indexURL: `${import.meta.env.BASE_URL}assets/pyodide`,
packageBaseUrl: `https://cdn.jsdelivr.net/pyodide/v${version}/full/`,
});
Option 2: Bundle specific packages locally#
Extract the .whl files you need from the full Pyodide distribution, define the packages you want, then add two entries to the viteStaticCopy targets in vite.config.mjs.
Note
Specify exact .whl filenames rather than using a glob like *.whl, to avoid copying all unused packages into your build.
const PYODIDE_PACKAGES = new Set(['micropip', /* add other packages here */]);
viteStaticCopy({
targets: [
// Copy only the specific .whl files you need
{
src: [
join(pyodideDir, 'micropip-*-py3-none-any.whl'),
// add other specific wheel files here
],
dest: 'assets/pyodide',
},
// Transform lockfile to only include selected packages
{
src: join(pyodideDir, 'pyodide-lock.json'),
dest: 'assets/pyodide',
transform: (content) => {
const lockfile = JSON.parse(content.toString());
lockfile.packages = Object.fromEntries(
Object.entries(lockfile.packages).filter(([name]) =>
PYODIDE_PACKAGES.has(name)
)
);
return JSON.stringify(lockfile);
},
},
],
});
If you need to specify a specific path for the bundled files, you can set the indexURL parameter:
let pyodide = await loadPyodide({
indexURL: "/assets", // Path to the directory containing pyodide.js and other files
});
Make sure this works both in Vite’s dev mode:
npx vite
And as a production build:
npx vite build
npx vite preview