Unenv: Platform-Agnostic JavaScript Environment
Unenv is a framework-agnostic system designed to convert JavaScript code for platform-agnostic execution across various environments, including browsers, Web Workers, Node.js, and other JavaScript runtimes. The current stable version is `1.10.0`, though active development is focused on v2.0.0-rc, with frequent release candidates. Its key differentiators include providing comprehensive polyfills for Node.js built-in modules and common npm packages, and offering an auto-mocking proxy for APIs that are not natively supported or fully implemented in a target runtime. Unenv provides configurable presets for specific environments like Node, Nodeless, Deno, Cloudflare Workers, and Vercel Edge Functions, allowing seamless integration with popular bundlers such as Rollup, Webpack, Esbuild, and Rspack through alias, inject, and external configurations.
Common errors
-
Could not resolve "events"
cause An npm package attempting to import a Node.js built-in module (like `events`, `path`, `fs`) in a non-Node.js environment (e.g., browser, worker) without `unenv` properly shimming or aliasing it.fixEnsure `unenv` is correctly configured in your build pipeline to provide shims and aliases for Node.js built-ins. For `defineEnv`, set `nodeCompat: true`. If using a specific preset like `nodeless` or `cloudflare`, ensure it's applied. -
[unenv] <method name> is not implemented yet!
cause Calling a method of a Node.js API (e.g., `fs.readFileSync`) that `unenv` has provided a mock implementation for, but the actual functionality is not available or polyfilled in the target runtime.fixIdentify the unsupported Node.js API. If the functionality is critical, you may need to implement a custom shim using `unenv`'s `overrides` option or find an alternative, platform-agnostic library. Review `unenv`'s documentation for supported API coverage per runtime.
Warnings
- breaking The `env` utility from v1.x has been replaced by `defineEnv` in `unenv` v2.x. While v1.x is stable, new projects or migrations should use `defineEnv` for enhanced configuration options and future compatibility.
- gotcha Some Node.js APIs are not fully implemented by `unenv` for all target runtimes. Instead, `unenv` might provide 'mock' implementations that throw errors or do nothing when called. This prevents silent failures but requires developers to be aware of unsupported APIs.
- gotcha When targeting Cloudflare Workers, ensure that the `nodejs_compat` or `nodejs_compat_v2` compatibility flag is enabled in your `wrangler.toml` configuration. Without this, Node.js API polyfills might not function correctly or be included.
- deprecated Presets like `deno` and `cloudflare` in `unenv` v2.x are explicitly marked as 'experimental' and their behavior or API might change in future release candidates or stable versions. Use with caution in production environments.
Install
-
npm install unenv -
yarn add unenv -
pnpm add unenv
Imports
- defineEnv
const { defineEnv } = require('unenv')import { defineEnv } from 'unenv' - env
import { env } from 'unenv' - nodeless, cloudflare
import { presets } from 'unenv' // Presets are named exportsimport { nodeless, cloudflare } from 'unenv' - Buffer
import { Buffer } from 'buffer'import { Buffer } from 'unenv/node/buffer'
Quickstart
import { defineEnv, nodeless, cloudflare } from 'unenv';
import fs from 'node:fs'; // Example of a Node.js built-in that will be shimmed
// Configure unenv for a Cloudflare Workers environment, enabling Node.js compatibility
// and auto-mocking for unimplemented APIs.
const { alias, inject, polyfill, external } = defineEnv({
nodeCompat: true, // Enable shims for Node.js built-ins and globals
npmShims: true, // Enable shims for common npm packages
presets: [
nodeless, // Base preset for non-Node.js environments
cloudflare // Cloudflare Workers specific compatibility
],
overrides: {
// Custom overrides if needed, e.g., to replace specific modules
'node:fs': 'unenv/mock/proxy-cjs' // Ensure fs is fully mocked or aliased
}
});
console.log('Generated Aliases:', alias);
console.log('Injected Globals:', inject);
console.log('Required Polyfills:', polyfill);
console.log('Externalized Modules:', external);
// This output can then be used in a bundler configuration (e.g., Vite, Webpack, Rollup)
// to apply the environment transformations.
// Example: How a bundler might use 'alias' output
// const viteConfig = {
// resolve: {
// alias: Object.entries(alias).map(([find, replacement]) => ({ find, replacement }))
// }
// };
// console.log(viteConfig);
// Example: Demonstrate an unimplemented API call with a mock
try {
fs.readFileSync('./test.txt', 'utf8');
} catch (e) {
console.log(`
Attempted to use fs.readFileSync: ${e.message}`);
console.log('This demonstrates how unenv mocks unimplemented APIs by throwing an error, indicating it is not available in the target runtime.');
}