{"id":13880822,"url":"https://github.com/divriots/browser-vite","last_synced_at":"2025-07-16T17:31:12.528Z","repository":{"id":40655915,"uuid":"381287936","full_name":"divriots/browser-vite","owner":"divriots","description":"Vite in the browser.","archived":false,"fork":true,"pushed_at":"2022-03-31T14:16:08.000Z","size":14790,"stargazers_count":597,"open_issues_count":1,"forks_count":27,"subscribers_count":10,"default_branch":"browser-vite","last_synced_at":"2025-07-03T20:17:01.112Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"vitejs/vite","license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/divriots.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2021-06-29T08:08:30.000Z","updated_at":"2025-07-02T07:20:13.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/divriots/browser-vite","commit_stats":null,"previous_names":[],"tags_count":100,"template":false,"template_full_name":null,"purl":"pkg:github/divriots/browser-vite","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/divriots%2Fbrowser-vite","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/divriots%2Fbrowser-vite/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/divriots%2Fbrowser-vite/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/divriots%2Fbrowser-vite/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/divriots","download_url":"https://codeload.github.com/divriots/browser-vite/tar.gz/refs/heads/browser-vite","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/divriots%2Fbrowser-vite/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":265527545,"owners_count":23782480,"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":[],"created_at":"2024-08-06T08:03:31.108Z","updated_at":"2025-07-16T17:31:10.875Z","avatar_url":"https://github.com/divriots.png","language":"TypeScript","funding_links":[],"categories":["TypeScript"],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"https://raw.github.com/divriots/browser-vite/master/browser-vite.svg\" height=\"200px\"\u003e\n\u003c/p\u003e\n\u003cbr/\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://npmjs.com/package/browser-vite\"\u003e\u003cimg src=\"https://img.shields.io/npm/v/browser-vite.svg\" alt=\"npm package\"\u003e\u003c/a\u003e\n  \u003ca href=\"https://nodejs.org/en/about/releases/\"\u003e\u003cimg src=\"https://img.shields.io/node/v/browser-vite.svg\" alt=\"node compatibility\"\u003e\u003c/a\u003e\n  \u003cbr/\u003e\n\u003c/p\u003e\n\u003cp align=\"center\"\u003e\n  \u003ca href=\"https://divRIOTS.com\"\u003eBrought to you by\u003cbr/\u003e\u003c/a\u003e\n  \u003ca href=\"https://divRIOTS.com#gh-light-mode-only\" target=\"_blank\"\u003e\n        \u003cimg width=\"150\" height=\"40\" src=\"https://divRIOTS.com/divriots.svg#gh-light-mode-only\" alt=\"‹div›RIOTS\" /\u003e\n        \u003c/a\u003e\n        \u003ca href=\"https://divRIOTS.com#gh-dark-mode-only\" target=\"_blank\"\u003e\n        \u003cimg width=\"150\" height=\"40\" src=\"https://divRIOTS.com/divriots-dark.svg#gh-dark-mode-only\" alt=\"‹div›RIOTS\" /\u003e\n        \u003c/a\u003e\n\u003c/p\u003e\n\u003cbr/\u003e\n\n# Vite for Browser ⚡\n\nThis is a fork of vite which aims at being used in a browser (served by service worker).\n\n- [Introduction blog post](https://divriots.com/blog/vite-in-the-browser)\n\nUsed in [Backlight.dev](https://backlight.dev) and in the upcoming [Replic.dev](https://replic.dev)\n\n---\n\nHere are the changes made, required to run it in the Browser:\n- Generate an un-bundled `browser` build: [rollup.config.js#L218-L274](https://github.com/divriots/vite/blob/browser-vite/packages/vite/rollup.config.js#L218-L274)\n  - avoids duplicate dependencies in App using it\n  - prefers browser alternatives for dependencies\n- Shim CLI-only dependencies (chalk,debug...): [rollup.config.js#L470-L477](https://github.com/divriots/vite/blob/browser-vite/packages/vite/rollup.config.js#L470-L477)\n- Limit FS dependency\n  - remove watch/glob/config\n  - but keep resolving project files through FS (will be shimmed in-App)\n- Remove serve\n- Remove dependency handling/optimizing/resolving\n  - handled in-App through custom plugins\n  - using a service to generate/serve optimized dependencies (see below)\n\nAnother change was made to support running the dependency optimizer as a service:\n- Parse CJS exports (using cjs-module-lexer) to avoid the es-interop transform (further de-coupling vite \u0026 optimizer): [#8e80d8](https://github.com/divriots/vite/commit/8e80d88372b4ea287b502ceec7edf52a4c3026b3)\n\n# Usage\n\nA full sample is left as an exercise to the reader, but here are the bits you'll need:\n\n## Installation\n\nPrefer installing as vite alias, so that official vite plugins will work OOB.\nWhen importing `vite` below, all imports will be resolved in `browser-vite`.\n\n```\n$ npm install --save vite@npm:browser-vite\n```\n\nPackage has 2 entry points:\n- `vite/node/node`: regular vite node bundle\n- `vite/node/browser`: browser build -\u003e make sure to use this one, either explicitely or having your bundle use the package.json `browser` field\n\n## Service worker\n\nYou'll need a service worker which will intercept all requests from your vite iframe, so that they get served by vite.\ne.g. with workbox:\n\n```js\nworkbox.routing.registerRoute(\n  /^https?:\\/\\/HOST/BASE_URL\\/(\\/.*)$/,\n  async ({\n    request,\n    params,\n    url,\n  }: import('workbox-routing/types/RouteHandler').RouteHandlerCallbackContext): Promise\u003cResponse\u003e =\u003e {\n    const req = request?.url || url.toString();\n    const [pathname] = params as string[];\n    // send the request to vite worker\n    const response = await postToViteWorker(pathname)\n    return response;\n  }\n);\n```\n\n## Vite worker\n\nNote: You need to alias `fs` builtin to a VFS implementation (e.g. `memfs`), you may also need other node builtins browserified, for reference we've been running these aliases:\n\n```\nfs: memfs,\npath: path-browserify,\nquerystring: querystring-es3,\nurl: url/url.js,\ncrypto: crypto-browserify,\nstream: readable-stream-no-circular,\nreadable-stream: readable-stream-no-circular,\nsafe-buffer: buffer,\ntimers: timers-browserify,\nos: os-browserify,\ntty: tty-browserify,\nreadline: EMPTY,\nfsevents: EMPTY,\nchokidar: EMPTY,\nreaddirp: EMPTY,\nconsolidate: EMPTY,\npnpapi: EMPTY,\n// esm-browser version fails to parse HTML in worker, due to DOM (document) reference\n// AFAICT node version works in web worker\n@vue/compiler-dom: @vue/compiler-dom/dist/compiler-dom.cjs.js\n```\n\nThe vite worker will load `browser-vite` and instanciate a custom `ViteDevServer`:\n\n```js\nimport {\n  transformWithEsbuild,\n  ModuleGraph,\n  transformRequest,\n  createPluginContainer,\n  createDevHtmlTransformFn,\n  resolveConfig,\n  generateCodeFrame,\n  ssrTransform,\n  ssrLoadModule,\n  ViteDevServer,\n  PluginOption\n} from 'vite';\n\nexport async function createServer(\n  const config = await resolveConfig(\n    {\n      plugins: [\n        // virtual plugin to provide vite client/env special entries (see below)\n        viteClientPlugin,\n        // virtual plugin to resolve NPM dependencies, e.g. using unpkg, skypack or another provider (browser-vite only handles project files)\n        nodeResolvePlugin,\n        // add vite plugins you need here (e.g. vue, react, astro ...)\n      ]\n      base: BASE_URL, // as hooked in service worker\n      // not really used, but needs to be defined to enable dep optimizations\n      cacheDir: 'browser',\n      root: VFS_ROOT,\n      // any other configuration (e.g. resolve alias)\n    },\n    'serve'\n  );\n  const plugins = config.plugins;\n  const pluginContainer = await createPluginContainer(config);\n  const moduleGraph = new ModuleGraph((url) =\u003e pluginContainer.resolveId(url));\n\n  const watcher: any = {\n    on(what: string, cb: any) {\n      return watcher;\n    },\n    add() {},\n  };\n  const server: ViteDevServer = {\n    config,\n    pluginContainer,\n    moduleGraph,\n    transformWithEsbuild,\n    transformRequest(url, options) {\n      return transformRequest(url, server, options);\n    },\n    ssrTransform,\n    printUrls() {},\n    _globImporters: {},\n    ws: {\n      send(data) {\n        // send HMR data to vite client in iframe however you want (post/broadcast-channel ...)\n      },\n      async close() {},\n      on() {},\n      off() {},\n    },\n    watcher,\n    async ssrLoadModule(url) {\n      return ssrLoadModule(url, server, loadModule);\n    },\n    ssrFixStacktrace() {},\n    async close() {},\n    async restart() {},\n    _optimizeDepsMetadata: null,\n    _isRunningOptimizer: false,\n    _ssrExternals: [],\n    _restartPromise: null,\n    _forceOptimizeOnRestart: false,\n    _pendingRequests: new Map(),\n  };\n\n  server.transformIndexHtml = createDevHtmlTransformFn(server);\n\n  // apply server configuration hooks from plugins\n  const postHooks: ((() =\u003e void) | void)[] = [];\n  for (const plugin of plugins) {\n    if (plugin.configureServer) {\n      postHooks.push(await plugin.configureServer(server));\n    }\n  }\n\n  // run post config hooks\n  // This is applied before the html middleware so that user middleware can\n  // serve custom content instead of index.html.\n  postHooks.forEach((fn) =\u003e fn \u0026\u0026 fn());\n\n  await pluginContainer.buildStart({});\n  await runOptimize(server);\n  \n  return server;\n}\n```\n\nIf you want to optimize (bundle) the npm deps, you can do so:\n\n```js\nimport {\n  scanImports,\n  flattenId,\n  createMissingImporterRegisterFn,\n  ResolvedConfig,\n  DepOptimizationMetadata,\n  ViteDevServer,\n} from 'vite';\n\nexport async function runOptimize(server: ViteDevServer) {\n  const optimizeConfig = {\n    ...server.config,\n    build: {\n      ...server.config.build,\n      rollupOptions: {\n        ...server.config.build.rollupOptions,\n        input: ENTRY_FILES,\n      },\n    },\n  };\n\n  try {\n    server._isRunningOptimizer = true;\n    server._optimizeDepsMetadata = null;\n    server._optimizeDepsMetadata = await optimizeDeps(\n      server,\n      optimizeConfig,\n    );\n  } finally {\n    server._isRunningOptimizer = false;\n  }\n  server._registerMissingImport = createMissingImporterRegisterFn(\n    server,\n    (_config, _force, _asCommand, newDeps) =\u003e\n      optimizeDeps(server, optimizeConfig, newDeps)\n  );\n}\n\nasync function optimizeDeps(\n  server: ViteDevServer,\n  config: ResolvedConfig,\n  deps?: Record\u003cstring, string\u003e\n): Promise\u003cDepOptimizationMetadata\u003e {\n  const mainHash = '0';\n  const data: StudioDepOptimizationMetadata = {\n    hash: mainHash,\n    browserHash: mainHash,\n    optimized: {},\n  };\n\n  if (deps) {\n    console.log('New dependencies: ', Object.keys(deps));\n  } else {\n    const { missing } = await scanImports(config);\n    deps = missing;\n    console.log('Scanned dependencies: ', Object.keys(deps));\n  }\n  // Optimize dependency set using a bundler service, e.g. esm.sh\n  return data;\n}\n```\n\nVite client plugin (while env works as is, you probably need a different bundle for the client, so that you can inject HMR messages).\n\n```js\nimport { CLIENT_ENTRY, CLIENT_DIR, ENV_ENTRY, Plugin } from 'vite';\nimport vite_client from 'vite/dist/client/browser.mjs?raw';\nimport vite_client_env from 'vite/dist/client/env.mjs?raw';\n\nconst viteClientPlugin: Plugin = {\n  name: 'vite:browser:hmr',\n  enforce: 'pre',\n  resolveId(id) {\n    if (id.startsWith(CLIENT_DIR)) {\n      return {\n        id: /\\.mjs$/.test(id) ? id : `${id}.mjs`,\n        external: true,\n      };\n    }\n  },\n  load(id) {\n    if (id === CLIENT_ENTRY) {\n      return vite_client;\n    }\n    if (id === ENV_ENTRY) {\n      return vite_client_env;\n    }\n  },\n};\n\nexport { viteClientPlugin };\n\n\n```\n\n\n---\n\n**That's all folks ! Below is upstream README !**\n\n---\n\n# Vite ⚡\n\n\u003e Next Generation Frontend Tooling\n\n- 💡 Instant Server Start\n- ⚡️ Lightning Fast HMR\n- 🛠️ Rich Features\n- 📦 Optimized Build\n- 🔩 Universal Plugin Interface\n- 🔑 Fully Typed APIs\n\nVite (French word for \"quick\", pronounced [`/vit/`](https://cdn.jsdelivr.net/gh/vitejs/vite@main/docs/public/vite.mp3), like \"veet\") is a new breed of frontend build tool that significantly improves the frontend development experience. It consists of two major parts:\n\n- A dev server that serves your source files over [native ES modules](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Modules), with [rich built-in features](https://vitejs.dev/guide/features.html) and astonishingly fast [Hot Module Replacement (HMR)](https://vitejs.dev/guide/features.html#hot-module-replacement).\n\n- A [build command](https://vitejs.dev/guide/build.html) that bundles your code with [Rollup](https://rollupjs.org), pre-configured to output highly optimized static assets for production.\n\nIn addition, Vite is highly extensible via its [Plugin API](https://vitejs.dev/guide/api-plugin.html) and [JavaScript API](https://vitejs.dev/guide/api-javascript.html) with full typing support.\n\n[Read the Docs to Learn More](https://vitejs.dev).\n\n## Migrating from 1.x\n\nCheck out the [Migration Guide](https://vitejs.dev/guide/migration.html) if you are upgrading from 1.x.\n\n## Packages\n\n| Package                                           | Version (click for changelogs)                                                                                                       |\n| ------------------------------------------------- | :----------------------------------------------------------------------------------------------------------------------------------- |\n| [vite](packages/vite)                             | [![vite version](https://img.shields.io/npm/v/vite.svg?label=%20)](packages/vite/CHANGELOG.md)                                       |\n| [@vitejs/plugin-vue](packages/plugin-vue)         | [![plugin-vue version](https://img.shields.io/npm/v/@vitejs/plugin-vue.svg?label=%20)](packages/plugin-vue/CHANGELOG.md)             |\n| [@vitejs/plugin-vue-jsx](packages/plugin-vue-jsx) | [![plugin-vue-jsx version](https://img.shields.io/npm/v/@vitejs/plugin-vue-jsx.svg?label=%20)](packages/plugin-vue-jsx/CHANGELOG.md) |\n| [@vitejs/plugin-react](packages/plugin-react)     | [![plugin-react version](https://img.shields.io/npm/v/@vitejs/plugin-react.svg?label=%20)](packages/plugin-react/CHANGELOG.md)       |\n| [@vitejs/plugin-legacy](packages/plugin-legacy)   | [![plugin-legacy version](https://img.shields.io/npm/v/@vitejs/plugin-legacy.svg?label=%20)](packages/plugin-legacy/CHANGELOG.md)    |\n| [create-vite](packages/create-vite)               | [![create-vite version](https://img.shields.io/npm/v/create-vite.svg?label=%20)](packages/create-vite/CHANGELOG.md)                  |\n\n## Contribution\n\nSee [Contributing Guide](https://github.com/vitejs/vite/blob/main/CONTRIBUTING.md).\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdivriots%2Fbrowser-vite","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdivriots%2Fbrowser-vite","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdivriots%2Fbrowser-vite/lists"}