unenv

repository·main·Indexed 21 days ago

https://github.com/unjs/unenv

unenv provides polyfills to add Node.js compatibility for any JavaScript runtime, including browsers and edge workers. It includes the `defineEnv` utility to generate environment configurations (aliases, injections, and polyfills) for build tools like Vite, Rollup, esbuild, Webpack, and Rspack. The library also provides direct access to mocks, Node.js built-in module polyfills (such as assert and Buffer), and NPM package shims.

Tokens
10.4K
Snippets
34
Records
47
Agent score
72%

What's inside unenv

  1. Use the `unenv-nightly` release channel

    main

    To use the latest changes from the main branch, you can install unenv-nightly.

    If using unenv directly in your project:

    {
      "devDependencies": {
        "unenv": "npm:unenv-nightly"
      }
    }

    If using unenv via another tool (like Nuxt or Nitro):

    {
      "resolutions": {
        "unenv": "npm:unenv-nightly"
      }
    }
  2. Use the Node.js assert polyfill

    main

    The unenv Node.js assert polyfill provides a subset of the Node.js assert module, including assertion functions and the AssertionError class. It is designed to provide compatibility for code expecting the Node.js assertion API in non-Node environments. The module exports a default assert object containing all standard assertion methods, as well as a strict sub-object for strict equality assertions.

    import assert from 'unenv/runtime/node/assert';
    
    // Standard assertions
    assert.ok(true);
    assert.strictEqual(1, 1);
    
    // Strict sub-module
    assert.strict.equal(1, 1);
  3. How defineEnv() merges presets

    main

    When multiple presets are provided to defineEnv(), they are merged following a specific priority order:

    1. The default unenv preset is created first.
    2. User-provided presets are appended.
    3. User-provided overrides are appended last.

    Merging Logic

    • Alias: Aliases are merged by iterating through keys from most specific to most general (e.g., fs/promises is processed before fs). Later presets in the list will overwrite aliases from earlier presets if they share the same key.
    • Inject: Global injections are merged. If a value is an array, it replaces the previous value. If a value is false, the injection for that global is removed. Otherwise, the value is updated to the new string.
    • Polyfill: Polyfills from all presets are collected into a single array. The list is deduplicated and supports negation (items prefixed with ! are removed from the set).
    • External: External dependencies are collected into a single array and deduplicated.
  4. Identify unimplemented Node.js crypto features

    main

    This polyfill only implements a subset of the Node.js crypto module. Many functions and classes are exported but will throw an error if called because they are not implemented.

    Implemented:

    • webcrypto (Proxy to globalThis.crypto)
    • randomBytes (and aliases rng, prng)

    Not Implemented (will throw):

    • Hashing: createHash, hash
    • Symmetric Encryption: createCipheriv, createDecipheriv, Cipheriv, Decipheriv
    • Key Management: generateKeyPair, createPrivateKey, createPublicKey, KeyObject
    • Diffie-Hellman: createDiffieHellman, ECDH
    • PBKDF2/Scrypt: pbkdf2, scrypt
    • Sign/Verify: sign, verify, createSign, createVerify
    • Other: randomInt, timingSafeEqual, getCurves, etc.

    Deprecated/Undefined:

    • createCipher and createDecipher are explicitly undefined.
  5. Understand the Environment and ResolvedEnvironment structures

    main

    An Environment defines the mapping for a runtime. It consists of:

    • alias: A record of module aliases (Record<string, string>).
    • inject: A record of globals to inject (Record<string, string | string[] | false>). A value of false is used to drop an injection entry from a parent environment.
    • polyfill: An array of polyfill strings.
    • external: An array of external module strings.

    A ResolvedEnvironment is the final object returned by defineEnv. It extends Environment but guarantees that the inject map contains only valid injection strings and never contains false values.

  6. Perform manual mocking with `MockProxy`

    main

    You can use unenv/mock/proxy to create a magic proxy that replaces unknown APIs, or use __createMock__ to create specific named mocks for libraries.

    // Magic proxy to replace any unknown API
    import MockProxy from "unenv/mock/proxy";
    
    // You can also create named mocks
    const lib = MockProxy.__createMock__("lib", {
      /* overrides */
    });
  7. Generate environment configuration with `defineEnv`

    main

    The defineEnv utility generates a configuration object used to provide Node.js compatibility in non-Node environments (like browsers or edge workers). The resulting env object contains alias, inject, external, and polyfill properties that can be integrated into various build tools.

    Configuration Options

    • nodeCompat (default: true): Adds alias entries for Node.js builtins (e.g., <id> and node:<id>) and inject entries for globals like global, Buffer, and process.
    • npmShims (default: false): Adds alias entries to replace heavy npm packages with lighter shims (e.g., replacing node-fetch).
    • resolve (default: false): Resolves configuration values to absolute paths.
    • overrides: An object containing additional overrides for the environment configuration.
    • presets: An array of additional presets (e.g., ['@cloudflare/unenv-preset']).
    import { defineEnv } from "unenv";
    
    const { env } = defineEnv({
      nodeCompat: true,
      npmShims: true,
      resolve: true,
      overrides: {},
      presets: [],
    });
    
    const { alias, inject, external, polyfill } = env;
  8. Import `unenv/` polyfills directly

    main

    If you do not want to use the defineEnv utility, you can import specific polyfills and mocks directly from the unenv/ entry points:

    • unenv/mock/*: Mocking utilities.
    • unenv/node/*: APIs compatible with Node.js built-in modules.
    • unenv/npm/*: Shims for common NPM packages.
    • unenv/polyfill/*: Global polyfills.
    • unenv/web/*: A subset of Web APIs.
  9. Convert a file path to a URL with pathToFileURL()

    main

    Use pathToFileURL() to convert a local file system path into a file: protocol URL. This is useful when you need to pass file paths to APIs that expect a WHATWG URL.

    Options:

    • windows (boolean): If true, the function treats the path as a Windows path (handling drive letters and UNC paths). If false (default), it treats it as a POSIX path.

    Behavior:

    • On Windows, it correctly handles UNC paths (e.g., \\server\share\resource) and extended UNC paths (e.g., \\?\UNC\...).
    • It resolves the path before conversion.
    • It handles special characters like ? and # by percent-encoding them to ensure they are treated as part of the pathname rather than URL delimiters.
    import { pathToFileURL } from 'unenv/runtime/node/internal/url/url';
    
    // POSIX example
    const url = pathToFileURL('/home/user/file.txt');
    // Result: file:///home/user/file.txt
    
    // Windows example
    const winUrl = pathToFileURL('C:\\Users\file.txt', { windows: true });
    // Result: file:///C:/Users/file.txt
  10. Define custom environments using Presets

    main

    A Preset allows you to define a partial Environment that can be used during environment creation. It can also include metadata:

    • alias, inject, polyfill, external: Partial definitions of an Environment.
    • meta: An optional object containing:
      • name: The preset name.
      • version: The preset version.
      • url: The path or URL to the preset entry (used for resolving absolute paths).
  11. Manipulate Buffer byte order with swap methods

    main

    You can change the endianness of the data within a Buffer in-place using the following methods:

    • buf.swap16(): Swaps 16-bit words.
    • buf.swap32(): Swaps 32-bit words.
    • buf.swap64(): Swaps 64-bit words.

    Warning: These methods throw a RangeError if the Buffer length is not a multiple of the swap size (e.g., swap16 requires an even length).

    const buf = Buffer.from([0x01, 0x02, 0x03, 0x04]);
    buf.swap16(); // [0x02, 0x01, 0x04, 0x03]