@nonnajs/vite-plugin
v1.1.1
Published
Vite plugin for @nonnajs/di - aliases the handful of Node.js builtins @nonnajs/di's published bundle statically imports (async_hooks, fs/promises, path, url) to minimal browser-safe shims, so browser apps (React, Vue, ...) can bundle @nonnajs/di without a
Maintainers
Readme
@nonnajs/vite-plugin
Vite plugin for
@nonnajs/di- aliases the handful of Node.js builtins@nonnajs/di's published dist bundle statically imports to minimal, browser-safe shims, so a browser app (React, Vue, or anything else Vite bundles) can resolve@nonnajs/diat all.
The Problem
@nonnajs/di's default request-scope storage (AsyncLocalStorage, from node:async_hooks) and injector.loadBeans() (node:fs/promises, node:path, node:url) are Node-only features. Most browser apps never touch either - no runInScope()/request-scoped providers, .scan() instead of loadBeans() - but @nonnajs/di's published bundle still statically imports those four builtins (tsup's platform: "neutral" build strips the node: prefix, so both the bare and prefixed specifiers show up), and a real browser bundler like Rollup can't resolve either form on its own. Without this plugin, building @nonnajs/di into a browser bundle fails at bundle time with an unresolved-import error.
Installation
npm install --save-dev @nonnajs/vite-pluginvite is a peer dependency - bring your own version (>=4).
Usage
// vite.config.ts
import {defineConfig} from "vite";
import {nonna} from "@nonnajs/vite-plugin";
export default defineConfig({
plugins: [nonna()],
});That's it - @nonnajs/di (and anything built on top of it, like @nonnajs/react or @nonnajs/vue) now bundles cleanly for the browser.
What The Shims Actually Do
None of the four shims provide real Node semantics - they exist purely so the bundler has something to resolve:
async_hooks- a minimalAsyncLocalStoragestand-in with single-slotrun()/getStore(). Not real async-context isolation across concurrent calls. Only exercised if your app callsinjector.runInScope()without supplying its owncontextStorage.fs/promises- areadFile()that always throws. Only exercised if your app callsinjector.loadBeans().path/url- minimalisAbsolute/dirname/resolveandpathToFileURL()implementations. Also only exercised byloadBeans().
If your app needs real request scoping in the browser, supply your own ContextStorage via Nonna.injector().withContextStorage(...) instead of relying on the shimmed default.
API
nonna(options?: NonnaPluginOptions): Plugin
options.shims?: NonnaShimName[]- which of"async_hooks" | "fs/promises" | "path" | "url"to shim. Defaults to all four; narrow this only if you've audited your app and know it never reaches the feature a given shim backs.
License
MIT © Manuel Santos
