{"id":28946266,"url":"https://github.com/riccardoperra/vite-plugin-import-maps","last_synced_at":"2026-02-04T23:04:35.574Z","repository":{"id":291294333,"uuid":"976583774","full_name":"riccardoperra/vite-plugin-import-maps","owner":"riccardoperra","description":"A vite plugin that automatically manages native import maps in your host vite application. Useful for micro frontend architectures and dynamic plugin systems","archived":false,"fork":false,"pushed_at":"2025-05-23T05:13:03.000Z","size":166,"stargazers_count":3,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-19T03:03:40.040Z","etag":null,"topics":["import-maps","mfe","microfrontend","plugin-architecture","typescript","vite-plugin","vitejs"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/riccardoperra.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-05-02T11:21:12.000Z","updated_at":"2025-06-05T06:36:18.000Z","dependencies_parsed_at":null,"dependency_job_id":"5e2a70ba-e523-46c6-b9e1-e36bf17671ea","html_url":"https://github.com/riccardoperra/vite-plugin-import-maps","commit_stats":null,"previous_names":["riccardoperra/vite-plugin-native-import-maps","riccardoperra/vite-plugin-import-maps"],"tags_count":4,"template":false,"template_full_name":null,"purl":"pkg:github/riccardoperra/vite-plugin-import-maps","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/riccardoperra%2Fvite-plugin-import-maps","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/riccardoperra%2Fvite-plugin-import-maps/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/riccardoperra%2Fvite-plugin-import-maps/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/riccardoperra%2Fvite-plugin-import-maps/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/riccardoperra","download_url":"https://codeload.github.com/riccardoperra/vite-plugin-import-maps/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/riccardoperra%2Fvite-plugin-import-maps/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261441435,"owners_count":23158480,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["import-maps","mfe","microfrontend","plugin-architecture","typescript","vite-plugin","vitejs"],"created_at":"2025-06-23T08:05:29.301Z","updated_at":"2026-02-04T23:04:35.569Z","avatar_url":"https://github.com/riccardoperra.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003ch1 align=\"center\"\u003evite-plugin-native-import-maps\u003c/h1\u003e\n\u003cbr/\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://npmjs.com/package/vite-plugin-native-import-maps\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/vite-plugin-native-import-maps.svg\" alt=\"npm package\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://github.com/riccardoperra/vite-plugin-import-maps/actions/workflows/ci.yml\"\u003e\u003cimg src=\"https://github.com/riccardoperra/vite-plugin-import-maps/actions/workflows/release.yml/badge.svg?branch=main\" alt=\"build status\"\u003e\u003c/a\u003e\n\u003c/p\u003e\n\nA Vite plugin that generates and keeps **browser import maps** in sync with your Vite dev server and production build.\n\nIt's aimed at **micro-frontends**, **plugin systems**, and any setup where you load ESM modules at runtime and want to:\n\n- Share dependencies (React, Solid, etc.) **without relying on CDNs**\n- Avoid bundling multiple copies of the same library\n- Expose npm packages or **your own local entry modules** through an import map\n- Keep **remote modules truly \"native\"**: remotes can be plain ESM files **without requiring a build step or special\n  plugins**\n\n---\n\n## Table of Contents\n\n- [Install](#install)\n- [Setup](#setup)\n- [Configuration](#configuration)\n- [Do You Need This Plugin?](#do-you-need-this-plugin)\n- [Recipes](#recipes)\n- [Troubleshooting](#troubleshooting)\n- [How It Works](#how-it-works)\n- [Examples](#examples)\n- [License](#license)\n\n---\n\n## Install\n\n```shell\n# pnpm\npnpm add -D vite-plugin-native-import-maps\n\n# npm\nnpm add -D vite-plugin-native-import-maps\n\n# yarn\nyarn add -D vite-plugin-native-import-maps\n```\n\n## Setup\n\n```ts\nimport {defineConfig} from \"vite\";\nimport {vitePluginNativeImportMaps} from \"vite-plugin-native-import-maps\";\n\nexport default defineConfig({\n    plugins: [\n        vitePluginNativeImportMaps({\n            shared: [\n                \"react\",\n                \"react-dom\",\n                // Expose a custom/local entry under a public specifier\n                {name: \"react/jsx-runtime\", entry: \"./src/custom-jsx-runtime.ts\"},\n            ],\n        }),\n    ],\n});\n```\n\n---\n\n## Configuration\n\n### Options\n\n- `shared` — List of modules to expose via the import map. Each entry can be a string (the specifier to expose, e.g.\n  `\"react\"`) or an object with `name` (the specifier), `entry` (the local path or package to resolve), and optionally\n  `integrity` (enable SRI hash for that dependency).\n\n- `sharedOutDir` — Directory prefix for emitted shared chunks in production. Defaults to `\"\"` (root of output\n  directory).\n\n- `integrity` —\n  Enable [Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/script/type/importmap#integrity_metadata_map)\n  for all shared dependencies. Set to `true`, `\"sha256\"`, `\"sha384\"`, or `\"sha512\"`. This adds an `integrity` map to the\n  import map so browsers can verify module contents. Can also be configured per-dependency via the object form in\n  `shared`.\n\n- `log` — Enable debug logging. Defaults to `false`.\n\n- `injectImportMapsToHtml` — Automatically inject a `\u003cscript type=\"importmap\"\u003e` into the HTML `\u003chead\u003e`. Defaults to\n  `true`. Set to `false` for SSR apps and use the `virtual:importmap` module instead.\n\n- `importMapHtmlTransformer` — A function to transform the resolved `imports` object before injecting into HTML. Useful\n  for adding a base path prefix, rewriting URLs to a CDN, or filtering entries.\n\n- `outputAsFile` — Emit the import map as a standalone JSON file. Set to `true` for `/import-map.json`, or provide a\n  custom name (e.g. `\"my-map\"` → `/my-map.json`). The file is served by Vite in dev and emitted as an asset in build.\n\n---\n\n## Do You Need This Plugin?\n\nIf you're considering [import maps](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/script/type/importmap),\nyou're likely building one of the following:\n\n- **Micro-frontend architecture** — A host app loads remote modules at runtime, and all parts need to share the same dependency instances (React, Solid, etc.)\n- **Plugin system** — Your app dynamically loads user-provided or third-party modules that rely on shared libraries\n- **Self-hosted dependency sharing** — You want to share dependencies across apps without relying on external CDN services like esm.sh or jspm.io\n\n### Why Not Third-Party Services?\n\nServices like [esm.sh](https://esm.sh) or [jspm.io](https://jspm.io) are convenient, but they come with trade-offs:\n\n- **External dependency** — Your app relies on a third-party service you don't control. If it goes down or changes, your app breaks.\n- **Network restrictions** — Many corporate environments, VPNs, and air-gapped networks block connections to public services. Your app simply won't work.\n- **Version alignment** — Ensuring host and remotes use the exact same dependency version from an external source can be error-prone.\n- **Limited flexibility** — You can't easily expose modified builds, subsets of exports, or local wrapper modules.\n\nWith this plugin, **your host app becomes the source of truth**. Shared dependencies are built and served from your own infrastructure.\n\n### Why This Plugin?\n\n**Works in both development and production**\n\nMost import map solutions only work at build time. This plugin keeps the import map in sync with Vite's dev server *and* production builds. During development, it resolves to Vite's optimized deps; in production, it points to the correct hashed chunk filenames. No manual updates, no mismatches.\n\n**No build step required for remotes**\n\nRemote modules can be plain ESM files—no bundler, no plugins, no special conventions. They just `import \"your-lib\"` and the browser resolves it via the import map provided by the host.\n\n**Single dependency instance**\n\nHost and all remotes share the exact same module instances.\n\n**Full control over what you share**\n\nExpose npm packages as-is, or provide custom wrapper modules, modified builds, or local files. You decide exactly what each specifier resolves to.\n\n\u003e **Note:** If a remote *does* use a bundler, shared dependencies must be marked as **external**.\n\u003e Otherwise the remote bundles its own copy and you lose the single-instance benefit.\n\nImport maps are simple in concept, but keeping them in sync with your build is tedious:\n\n- In dev, Vite serves optimized deps from `node_modules/.vite/deps` with cache-busting hashes\n- In production, chunks have content hashes in their filenames\n- Manually updating the import map every time something changes is error-prone\n\nThis plugin handles all of that. You declare what to share, and it generates the correct import map for both dev and build—automatically.\n\n**Example output:**\n\n```html\n\u003cscript type=\"importmap\"\u003e\n  {\n    \"imports\": {\n      \"react\": \"/shared/react-DyndEn3u.js\",\n      \"react/jsx-runtime\": \"/shared/react_jsx-runtime-CAvv468t.js\"\n    }\n  }\n\u003c/script\u003e\n```\n\n---\n\n## Recipes\n\n### Expose Local Entry Points (Custom ESM Wrappers)\n\nExpose a local file that re-exports a dependency, giving you full control over what gets shared:\n\n```ts\nvitePluginNativeImportMaps({\n    shared: [\n        {name: \"react\", entry: \"./src/react-esm.ts\"},\n        {name: \"react/jsx-runtime\", entry: \"./src/react-jsx-runtime.ts\"},\n        \"react-dom\",\n    ],\n    sharedOutDir: \"shared\",\n});\n```\n\n---\n\n### Enable Integrity Checks\n\nAdd SRI hashes to verify module integrity:\n\n```ts\nvitePluginNativeImportMaps({\n    shared: [\"react\", \"react-dom\"],\n    integrity: \"sha384\", // applies to all\n});\n\n// Or per-dependency:\nvitePluginNativeImportMaps({\n    shared: [\n        {name: \"react\", entry: \"react\", integrity: \"sha384\"},\n        {name: \"react-dom\", entry: \"react-dom\", integrity: false},\n    ],\n});\n```\n\n---\n\n### Mark Shared Deps as `external` in Remote Builds\n\nIf a remote module uses a bundler, configure shared dependencies as `external` to prevent bundling them:\n\n**tsdown example:**\n\n```ts\nimport {defineConfig} from \"tsdown\";\n\nexport default defineConfig({\n    external: [\"react\", \"react-dom\", \"react/jsx-runtime\"],\n});\n```\n\n**Vite (library mode) example:**\n\n```ts\nimport {defineConfig} from \"vite\";\n\nexport default defineConfig({\n    build: {\n        lib: {\n            entry: \"./src/index.ts\",\n            formats: [\"es\"],\n        },\n        rollupOptions: {\n            external: [\"react\", \"react-dom\", \"react/jsx-runtime\"],\n        },\n    },\n});\n```\n\n---\n\n### Serve Import Map as JSON File\n\n```ts\nvitePluginNativeImportMaps({\n    shared: [\"react\"],\n    outputAsFile: true, // /import-map.json\n});\n```\n\n---\n\n## Troubleshooting\n\n### SSR App Doesn't Show the Import Map\n\nSet `injectImportMapsToHtml: false` and inject the import map yourself using `virtual:importmap`:\n\n```ts\nimport importMap from \"virtual:importmap\";\n// Inject into your SSR HTML template\n```\n\n---\n\n### Specifier Resolves to the Wrong Module\n\nEnsure the specifier matches exactly what your code imports:\n\n- `react/jsx-runtime` ≠ `react`\n- `solid-js/web` ≠ `solid-js`\n\n---\n\n### Import Maps Not Supported in Target Browser\n\nImport maps require modern browsers. For broader support, use a polyfill\nlike [es-module-shims](https://github.com/guybedford/es-module-shims).\n\nSee the example: [`./examples/react-host-es-module-shims`](./examples/react-host-es-module-shims)\n\n---\n\n## How It Works\n\n1. **Collects** the `shared` entries from your config\n2. **In dev:** Resolves corresponding Vite dev-server URLs\n3. **In build:** Adds extra Rollup inputs so shared deps get dedicated output chunks, then records the final chunk URLs\n4. **Exposes** the mapping via:\n    - HTML injection (optional)\n    - `virtual:importmap` module (always)\n    - JSON file (optional)\n\n**Build snapshot:**\n\n- [`./test/fixture/basic`](./test/fixture/basic)\n- [`./test/__snapshot__/build-project-with-right-import-maps`](./test/__snapshot__/build-project-with-right-import-maps)\n\n---\n\n## Examples\n\n| Example                                                               | Description                              |\n|-----------------------------------------------------------------------|------------------------------------------|\n| [`solidjs-host`](./examples/solidjs-host)                             | Solid.js host app                        |\n| [`solidjs-remote-counter`](./examples/solidjs-remote-counter)         | Solid.js remote module                   |\n| [`react-host-custom`](./examples/react-host-custom)                   | React host with custom ESM wrappers      |\n| [`react-host-es-module-shims`](./examples/react-host-es-module-shims) | React host with es-module-shims polyfill |\n| [`react-remote-counter`](./examples/react-remote-counter)             | React remote module                      |\n| [`react-tanstack-start-ssr`](./examples/react-tanstack-start-ssr)     | SSR example with TanStack Start          |\n\n---\n\n## License\n\nMIT. See [LICENSE](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Friccardoperra%2Fvite-plugin-import-maps","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Friccardoperra%2Fvite-plugin-import-maps","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Friccardoperra%2Fvite-plugin-import-maps/lists"}