{"id":18561176,"url":"https://github.com/apostrophecms/vite","last_synced_at":"2025-07-07T14:36:05.392Z","repository":{"id":258167910,"uuid":"869407671","full_name":"apostrophecms/vite","owner":"apostrophecms","description":"Vite build flow for Apostrophe CMS projects","archived":false,"fork":false,"pushed_at":"2025-06-11T16:06:31.000Z","size":57,"stargazers_count":0,"open_issues_count":1,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-06-30T14:08:53.584Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/apostrophecms.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.md","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":"2024-10-08T08:44:08.000Z","updated_at":"2025-06-11T16:06:28.000Z","dependencies_parsed_at":"2024-10-26T13:41:36.008Z","dependency_job_id":"b263b6e7-5eb8-4304-ac85-ffc0d1153331","html_url":"https://github.com/apostrophecms/vite","commit_stats":null,"previous_names":["apostrophecms/vite"],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/apostrophecms/vite","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apostrophecms%2Fvite","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apostrophecms%2Fvite/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apostrophecms%2Fvite/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apostrophecms%2Fvite/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/apostrophecms","download_url":"https://codeload.github.com/apostrophecms/vite/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/apostrophecms%2Fvite/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264092796,"owners_count":23556382,"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-11-06T22:06:03.423Z","updated_at":"2025-07-07T14:36:05.373Z","avatar_url":"https://github.com/apostrophecms.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\n\u003cdiv align=\"center\"\u003e\n  \u003cimg src=\"https://raw.githubusercontent.com/apostrophecms/apostrophe/main/logo.svg\" alt=\"ApostropheCMS logo\" width=\"80\" height=\"80\"\u003e\n\n  \u003ch1\u003eApostrophe Vite Bundling And HMR\u003c/h1\u003e\n  \u003cp\u003e\n    \u003ca aria-label=\"Apostrophe logo\" href=\"https://docs.apostrophecms.org\"\u003e\n      \u003cimg src=\"https://img.shields.io/badge/MADE%20FOR%20ApostropheCMS-000000.svg?style=for-the-badge\u0026logo=Apostrophe\u0026labelColor=6516dd\"\u003e\n    \u003c/a\u003e\n    \u003ca aria-label=\"Join the community on Discord\" href=\"http://chat.apostrophecms.org\"\u003e\n      \u003cimg alt=\"\" src=\"https://img.shields.io/discord/517772094482677790?color=5865f2\u0026label=Join%20the%20Discord\u0026logo=discord\u0026logoColor=fff\u0026labelColor=000\u0026style=for-the-badge\u0026logoWidth=20\"\u003e\n    \u003c/a\u003e\n    \u003ca aria-label=\"License\" href=\"https://github.com/apostrophecms/vite/blob/main/LICENSE.md\"\u003e\n      \u003cimg alt=\"\" src=\"https://img.shields.io/static/v1?style=for-the-badge\u0026labelColor=000000\u0026label=License\u0026message=MIT\u0026color=3DA639\"\u003e\n    \u003c/a\u003e\n  \u003c/p\u003e\n\u003c/div\u003e\n\nThis extension provides Vite integration for ApostropheCMS projects, enabling module bundling and hot module replacement (HMR) during development.\n\n## Installation\n\nTo install the module, use the command line to run this command in an Apostrophe project's root directory:\n\n```\nnpm install @apostrophecms/vite\n```\n\n## Usage\n\nAdd the module in the `app.js` file:\n\n```javascript\nrequire('apostrophe')({\n  shortName: 'my-project',\n  modules: {\n    '@apostrophecms/vite': {},\n  }\n});\n```\n\n## Configuration\n\n## Hot Module Replacement Configuration\n\nBy default, HMR is enabled for your project's public UI code. All configuration is handled through ApostropheCMS's core asset module options, simplifying setup and maintenance.\n\n### Enable Admin UI HMR\n\nFor development work on the ApostropheCMS admin interface, you can switch HMR to target the admin UI instead of public-facing components:\n\n```javascript\nrequire('apostrophe')({\n  shortName: 'my-project',\n  modules: {\n    '@apostrophecms/vite': {},\n    '@apostrophecms/asset': {\n      options: {\n        hmr: 'apos', // 'public' targets the project UI (default)\n      },\n    },\n  }\n});\n```\n\n### Disable HMR\n\nYou can disable hot module replacement when it is not needed or desired, while still using Vite for builds:\n\n```javascript\nrequire('apostrophe')({\n  shortName: 'my-project',\n  modules: {\n    '@apostrophecms/vite': {},\n    '@apostrophecms/asset': {\n      options: {\n        hmr: false,\n      },\n    },\n  }\n});\n```\n\n## Change the underlying Websocket server port\nDuring development, the hot module reload (HMR) server uses WebSocket and runs on the same port as your ApostropheCMS instance. For advanced configurations, you can run the development server as a standalone HTTP server on a different port by setting the `hmrPort` option. This can be useful when you need to avoid port conflicts or work with specific network configurations:\n\n```javascript\nrequire('apostrophe')({\n  shortName: 'my-project',\n  modules: {\n    '@apostrophecms/vite': {},\n    '@apostrophecms/asset': {\n      options: {\n        hmrPort: 3001,\n      },\n    },\n  }\n});\n```\n\n## Enable Source Maps in Production\n\nYou can enable source maps in production to help debug minified code and view original source files in the browser DevTools. While this slightly increases the initial download size, it's valuable for debugging production issues.\n\n```javascript\nrequire('apostrophe')({\n  shortName: 'my-project',\n  modules: {\n    '@apostrophecms/vite': {},\n    '@apostrophecms/asset': {\n      options: {\n        productionSourceMaps: true,\n      },\n    },\n  }\n});\n```\n\n## Inject code only when HMR is enabled\n\nIf you want to inject some code in your site only when in development mode and HMR is enabled, you can use the Apostrophe nunjucks components.\n\n```njk\n{# module-name/views/myComponent.html #}\n\u003c!-- Shown only when HMR is enabled and in development mode. --\u003e\n```\n\n```js\n// module-name/index.js\nmodule.exports = {\n  components(self) {\n    return {\n      myComponent(req, data) {\n        return {};\n      }\n    };\n  },\n  init(self) {\n    self.apos.template.prepend({\n      where: 'head',\n      when: 'hmr',\n      bundler: 'vite',\n      component: 'module-name:myComponent'\n    });\n  }\n};\n```\nThe when option controls when your component appears:\n\n```javascript\nwhen: 'hmr'   // Only visible when HMR is active\nwhen: 'dev'   // Visible in any development mode\nwhen: 'prod'  // Only visible in production\n```\n\nThe bundler option allows you to specify which bundler must be active for the component to appear:\n\n```javascript\nbundler: 'vite'    // Only visible when using Vite\nbundler: 'webpack' // Only visible when using webpack\n```\n\nYou can combine these options to precisely control when your component appears. For example, to show a component only when using Vite with HMR active, you would use both `when: 'hmr'` and `bundler: 'vite'`.\n\n## Provided Vite Configuration\n\nWhile the `apos` build (the code living in the`ui/apos/` directory of every module) is fully preconfigured and doesn't allow for customization, the `public` build (the code imported within `ui/src/` ) is fully customizable and contains a minimal configuration to get you started:\n- A PostCSS plugin to handle core features such as \"Breakpoint Preview\" (when enabled)\n- `Modules/` alias to simplify module within the same build \n- `@/` alias to allow easy access to cross-module and cross-build source code\n\n### Pre-configured Aliases\n\nThe `Modules/` alias is available for both public and admin UI builds and allows you to import modules in your project without worrying about the relative path, but restricts you to only sources inside of `ui/src/` directories.\n\n```javascript\n// Current file: modules/another-module/ui/src/index.js\n// Actual import path: modules/some-module/ui/src/lib/utils.js\nimport utils from 'Modules/some-module/lib/utils.js';\n```\n\n`@/` alias is available for both public and admin UI builds and allows you to import files from the entire project source code. It follows the same path as your orignal source code, but skips the `ui/` part of the path.\n\n```javascript\n// Current file: any file in any module inside of the `ui/` folder\n// Actual path: modules/some-module/ui/src/lib/utils.js\nimport utils from '@/some-module/src/lib/utils.js';\n\n// Actual path: modules/some-module/ui/apos/mixins/SomeMixin.js\nimport SomeMixin from '@/some-module/apos/mixins/SomeMixin.js';\n```\n\n\u003e Warning: You gain access to `public` builds from within the `apos` build, and vice versa, when using the `@/` alias. You should use it with caution, because it might lead to situations where imports are not resolved correctly. This would happen if the imported file (or its deep imports) contains `Modules/` aliased imports. On the other hand, `@/` is more developer friendly, allows auto-completion, and is more intuitive and readable. Be sure to include mostly sources from your current build and ensure no imported sources contain `Modules/` aliased imports when cross-importing from another build.\n\n### Importing Static Assets and Sass\n\nThe way we integrate Vite with ApostropheCMS allows now direct imports (including dynamic imports) of assets like images, fonts, and other files. You can import them directly in your vanilla JS/JS framework code:\n\n```javascript\n// You can use aliases to import assets or a relative path when in the same module.\n// Actual path: modules/some-module/ui/assets/logo.svg\nimport logo from '@/some-module/assets/logo.svg';\n// Logo now cotains the path to the image and will be normallized and correctly\n// injected when building the project for production.\n```\nYou can import Sass as well:\n\n```scss\n/* You can use aliases to import assets */\n/* Actual path: modules/some-module/ui/scss/_styles.scss */\n@use '@/some-module/scss/styles';\n```\n\nVue JS supports importing assets directly in the template:\n\n```vue\n\u003ctemplate\u003e\n  \u003cimg src=\"@/some-module/assets/logo.svg\" alt=\"My logo\" /\u003e\n\u003c/template\u003e\n```\n\nIn other frameworks (but also in Vue), you can use the `import` statement to reference the asset:\n\n```jsx\nimport logo from '@/some-module/assets/logo.svg';\n\nfunction MyComponent() {\n  return \u003cimg src={logo} alt=\"My logo\" /\u003e;\n}\n```\n\nCSS URL can be resolved in two ways. You can use the documented in the Apostrophe docs `some-module/public` folder and `/modules/some-module/font.ttf` URL where your file is located in `./modules/some-module/public/font.ttf`\n\n```css\n@font-face {\n  font-family: MyFont;\n  src: url(\"/modules/some-module/font.ttf\") format(\"truetype\");\n}\n```\n\nOr you can use the absolute sources root path `/src/some-module/fonts/font.ttf` where your file is located in `./modules/some-module/ui/fonts/font.ttf`. You can inspect the sources of your project that are copied in the central location `apos-build/@postrophecms/vite/default` directory. This is the root that Vite uses to resolve the paths and build the project.\n\n```css\n@font-face {\n  font-family: Inter;\n  src: url(\"/src/some-module/fonts/font.ttf\") format(\"truetype\");\n}\n```\n\nThe same rules apply to paths in the `url()` function in CSS files.\n\n## Configuring Your Code Editor\n\nEvery editor, that understands the `jsconfig.json` or `tsconfig.json` file, can be configured to understand the `@/` alias provided by this module. Here is an example of a `jsconfig.json` file that you can place in your project root:\n\n```json\n{\n  \"compilerOptions\": {\n    \"baseUrl\": \"./apos-build/@apostrophecms/vite/default\",\n    \"paths\": {\n      \"@/*\": [\"./src/*\"]\n    },\n    \"module\": \"ESNext\",\n    \"moduleResolution\": \"bundler\"\n  },\n  \"exclude\": [\n    \"apos-build/@apostrophecms/vite/default/dist\",\n    \"node_modules\",\n    \"public\",\n    \"data\"\n  ]\n}\n```\n\n\u003e Note: If you change your project asset namespace you have to adjust the `baseUrl` and `exclude` path accordingly. For example, if your project namespace is `my-namespace`, the `baseUrl` should be `./apos-build/@apostrophecms/vite/my-namespace` and the `exclude` path - `apos-build/@apostrophecms/vite/my-namespace/dist`.\n\n\u003e Note: If you follow the import in your editor (e.g. Ctrl + Click in VSCode) it will lead to the `apos-build` directory and NOT the original source code. This is because the `apos-build` directory contains a copy of the entire project source code (including Admin UI) from all modules (local and npm) and is the actual source directory used by Vite to build the project.\n\n## Extending the Vite Configuration\n\nYou can customize the Vite configuration for your ApostropheCMS project in two ways:\n\n### 1. Via Any Module `build.vite` Property\n\nUse this approach to configure Vite settings within individual ApostropheCMS modules:\n\n```javascript\n// modules/some-module/index.js\nmodule.exports = {\n  build: {\n    vite: {\n      myViteConfig: {\n        // Standard Vite configuration\n        define: {\n          __MY_ENV__: '1',\n        },\n      }\n    },\n  },\n};\n```\n\n### 2. Via Project Configuration File\n\nFor project-wide Vite configuration, create one of these files in your project root:\n- `apos.vite.config.js` (for ESM projects)\n- `apos.vite.config.mjs` (for CommonJS projects)\n\nThis method supports the full Vite configuration API and applies to your project's UI build. You can import Vite's configuration utilities directly from the ApostropheCMS Vite module:\n\n```javascript\n// apos.vite.config.js\nimport { defineConfig } from '@apostrophecms/vite/vite';\nimport vue from '@vitejs/plugin-vue'\n\nexport default defineConfig({\n  plugins: [ vue() ]\n});\n```\n\nThe configuration format follows the standard [Vite configuration options](https://vitejs.dev/config/). Common use cases include adding plugins, defining environment variables, and customizing build settings.\n\n\u003e Note: All Vite configurations are merged sequentially - first across modules (following module registration order, with later modules taking precedence), and finally with the project configuration file, which takes ultimate precedence.\n\n## Limitations and Known Issues\n\n### Hot Module Replacement\n- HMR only monitors existing `anyModule/ui` directories. If you add a new `ui` directory to a module, restart the server to enable HMR for that module. With default ApostropheCMS starter kits using `nodemon`, simply type `rs` in the terminal and press Enter.\n- The `apos` HMR won't work when the `public` build contains Vue sources (transformed by the `@vitejs/plugin-vue` plugin). The HMR for the `public` build should still work as expected. The problem is related to the fact that the page would contain two Vue instances (core and reactive) instances, which is not currently supported. We are researching solutions to this issue.\n\n### Public Assets\n- Changes to `ui/public` directories don't trigger HMR or page reloads as they require a process restart\n- Workaround: Add `ui/public/` folders to your `nodemon` watch list in either `nodemon.json` or `package.json`\n- Future support for this feature will depend on user needs\n\n### Vite Alias Resolution\n- When setting custom `resolve.alias` in Vite configuration, paths must resolve to the appropriate `apos-build/...` source code rather than the original source\n- Future enhancement planned: We will provide templating (e.g., `{srcRoot}`) or function arguments (e.g., `aposRoot`) to simplify correct path resolution\n\n## Code Migration Guidelines\n\n### Import Paths\n- Remove all `~` prefixes from CSS/Sass imports\n  ```css\n  /* Instead of: @import \"~normalize.css\" */\n  @import \"normalize.css\"\n  ```\n\n### ApostropheCMS Module Imports\n- **Recommended**: Use the `Modules/module-name/components/...` alias instead of direct paths like `apostrophe/modules/module-name/ui/apos/components/...`\n- This alias is available only for `apos` source code; project code can define its own aliases\n\n### Module System\n- Use only ESM syntax in UI source code:\n  - ✅ `import abc from 'xxx'` or `const abc = await import('xxx')`\n  - ✅ `export default ...` or `export something`\n  - ❌ No CommonJS: `require()`, `module.exports`, `exports.xxx`\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapostrophecms%2Fvite","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fapostrophecms%2Fvite","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fapostrophecms%2Fvite/lists"}