# Vite > Vite's JavaScript APIs are fully typed, and it's recommended to use TypeScript or enable JS type checking in VS Code to leverage the intellisense and validation. --- # Source: https://vite.dev/guide/api-javascript.md --- url: /guide/api-javascript.md --- # JavaScript API Vite's JavaScript APIs are fully typed, and it's recommended to use TypeScript or enable JS type checking in VS Code to leverage the intellisense and validation. ## `createServer` **Type Signature:** ```ts async function createServer(inlineConfig?: InlineConfig): Promise ``` **Example Usage:** ```ts twoslash import { fileURLToPath } from 'node:url' import { createServer } from 'vite' const __dirname = fileURLToPath(new URL('.', import.meta.url)) const server = await createServer({ // any valid user config options, plus `mode` and `configFile` configFile: false, root: __dirname, server: { port: 1337, }, }) await server.listen() server.printUrls() server.bindCLIShortcuts({ print: true }) ``` ::: tip NOTE When using `createServer` and `build` in the same Node.js process, both functions rely on `process.env.NODE_ENV` to work properly, which also depends on the `mode` config option. To prevent conflicting behavior, set `process.env.NODE_ENV` or the `mode` of the two APIs to `development`. Otherwise, you can spawn a child process to run the APIs separately. ::: ::: tip NOTE When using [middleware mode](/config/server-options.html#server-middlewaremode) combined with [proxy config for WebSocket](/config/server-options.html#server-proxy), the parent http server should be provided in `middlewareMode` to bind the proxy correctly. ```ts twoslash import http from 'http' import { createServer } from 'vite' const parentServer = http.createServer() // or express, koa, etc. const vite = await createServer({ server: { // Enable middleware mode middlewareMode: { // Provide the parent http server for proxy WebSocket server: parentServer, }, proxy: { '/ws': { target: 'ws://localhost:3000', // Proxying WebSocket ws: true, }, }, }, }) // @noErrors: 2339 parentServer.use(vite.middlewares) ``` ## `InlineConfig` The `InlineConfig` interface extends `UserConfig` with additional properties: * `configFile`: specify config file to use. If not set, Vite will try to automatically resolve one from project root. Set to `false` to disable auto resolving. ## `ResolvedConfig` The `ResolvedConfig` interface has all the same properties of a `UserConfig`, except most properties are resolved and non-undefined. It also contains utilities like: * `config.assetsInclude`: A function to check if an `id` is considered an asset. * `config.logger`: Vite's internal logger object. ## `ViteDevServer` ```ts interface ViteDevServer { /** * The resolved Vite config object. */ config: ResolvedConfig /** * A connect app instance * - Can be used to attach custom middlewares to the dev server. * - Can also be used as the handler function of a custom http server * or as a middleware in any connect-style Node.js frameworks. * * https://github.com/senchalabs/connect#use-middleware */ middlewares: Connect.Server /** * Native Node http server instance. * Will be null in middleware mode. */ httpServer: http.Server | null /** * Chokidar watcher instance. If `config.server.watch` is set to `null`, * it will not watch any files and calling `add` or `unwatch` will have no effect. * https://github.com/paulmillr/chokidar/tree/3.6.0#api */ watcher: FSWatcher /** * WebSocket server with `send(payload)` method. */ ws: WebSocketServer /** * Rollup plugin container that can run plugin hooks on a given file. */ pluginContainer: PluginContainer /** * Module graph that tracks the import relationships, url to file mapping * and hmr state. */ moduleGraph: ModuleGraph /** * The resolved urls Vite prints on the CLI (URL-encoded). Returns `null` * in middleware mode or if the server is not listening on any port. */ resolvedUrls: ResolvedServerUrls | null /** * Programmatically resolve, load and transform a URL and get the result * without going through the http request pipeline. */ transformRequest( url: string, options?: TransformOptions, ): Promise /** * Apply Vite built-in HTML transforms and any plugin HTML transforms. */ transformIndexHtml( url: string, html: string, originalUrl?: string, ): Promise /** * Load a given URL as an instantiated module for SSR. */ ssrLoadModule( url: string, options?: { fixStacktrace?: boolean }, ): Promise> /** * Fix ssr error stacktrace. */ ssrFixStacktrace(e: Error): void /** * Triggers HMR for a module in the module graph. You can use the `server.moduleGraph` * API to retrieve the module to be reloaded. If `hmr` is false, this is a no-op. */ reloadModule(module: ModuleNode): Promise /** * Start the server. */ listen(port?: number, isRestart?: boolean): Promise /** * Restart the server. * * @param forceOptimize - force the optimizer to re-bundle, same as --force cli flag */ restart(forceOptimize?: boolean): Promise /** * Stop the server. */ close(): Promise /** * Bind CLI shortcuts */ bindCLIShortcuts(options?: BindCLIShortcutsOptions): void /** * Calling `await server.waitForRequestsIdle(id)` will wait until all static imports * are processed. If called from a load or transform plugin hook, the id needs to be * passed as a parameter to avoid deadlocks. Calling this function after the first * static imports section of the module graph has been processed will resolve immediately. * @experimental */ waitForRequestsIdle: (ignoredId?: string) => Promise } ``` :::info `waitForRequestsIdle` is meant to be used as a escape hatch to improve DX for features that can't be implemented following the on-demand nature of the Vite dev server. It can be used during startup by tools like Tailwind to delay generating the app CSS classes until the app code has been seen, avoiding flashes of style changes. When this function is used in a load or transform hook, and the default HTTP1 server is used, one of the six http channels will be blocked until the server processes all static imports. Vite's dependency optimizer currently uses this function to avoid full-page reloads on missing dependencies by delaying loading of pre-bundled dependencies until all imported dependencies have been collected from static imported sources. Vite may switch to a different strategy in a future major release, setting `optimizeDeps.crawlUntilStaticImports: false` by default to avoid the performance hit in large applications during cold start. ::: ## `build` **Type Signature:** ```ts async function build( inlineConfig?: InlineConfig, ): Promise ``` **Example Usage:** ```ts twoslash [vite.config.js] import path from 'node:path' import { fileURLToPath } from 'node:url' import { build } from 'vite' const __dirname = fileURLToPath(new URL('.', import.meta.url)) await build({ root: path.resolve(__dirname, './project'), base: '/foo/', build: { rollupOptions: { // ... }, }, }) ``` ## `preview` **Type Signature:** ```ts async function preview(inlineConfig?: InlineConfig): Promise ``` **Example Usage:** ```ts twoslash import { preview } from 'vite' const previewServer = await preview({ // any valid user config options, plus `mode` and `configFile` preview: { port: 8080, open: true, }, }) previewServer.printUrls() previewServer.bindCLIShortcuts({ print: true }) ``` ## `PreviewServer` ```ts interface PreviewServer { /** * The resolved vite config object */ config: ResolvedConfig /** * A connect app instance. * - Can be used to attach custom middlewares to the preview server. * - Can also be used as the handler function of a custom http server * or as a middleware in any connect-style Node.js frameworks * * https://github.com/senchalabs/connect#use-middleware */ middlewares: Connect.Server /** * native Node http server instance */ httpServer: http.Server /** * The resolved urls Vite prints on the CLI (URL-encoded). Returns `null` * if the server is not listening on any port. */ resolvedUrls: ResolvedServerUrls | null /** * Print server urls */ printUrls(): void /** * Bind CLI shortcuts */ bindCLIShortcuts(options?: BindCLIShortcutsOptions): void } ``` ## `resolveConfig` **Type Signature:** ```ts async function resolveConfig( inlineConfig: InlineConfig, command: 'build' | 'serve', defaultMode = 'development', defaultNodeEnv = 'development', isPreview = false, ): Promise ``` The `command` value is `serve` in dev and preview, and `build` in build. ## `mergeConfig` **Type Signature:** ```ts function mergeConfig( defaults: Record, overrides: Record, isRoot = true, ): Record ``` Deeply merge two Vite configs. `isRoot` represents the level within the Vite config which is being merged. For example, set `false` if you're merging two `build` options. ::: tip NOTE `mergeConfig` accepts only config in object form. If you have a config in callback form, you should call it before passing into `mergeConfig`. You can use the `defineConfig` helper to merge a config in callback form with another config: ```ts twoslash import { defineConfig, mergeConfig, type UserConfigFnObject, type UserConfig, } from 'vite' declare const configAsCallback: UserConfigFnObject declare const configAsObject: UserConfig // ---cut--- export default defineConfig((configEnv) => mergeConfig(configAsCallback(configEnv), configAsObject), ) ``` ::: ## `searchForWorkspaceRoot` **Type Signature:** ```ts function searchForWorkspaceRoot( current: string, root = searchForPackageRoot(current), ): string ``` **Related:** [server.fs.allow](/config/server-options.md#server-fs-allow) Search for the root of the potential workspace if it meets the following conditions, otherwise it would fallback to `root`: * contains `workspaces` field in `package.json` * contains one of the following file * `lerna.json` * `pnpm-workspace.yaml` ## `loadEnv` **Type Signature:** ```ts function loadEnv( mode: string, envDir: string, prefixes: string | string[] = 'VITE_', ): Record ``` **Related:** [`.env` Files](./env-and-mode.md#env-files) Load `.env` files within the `envDir`. By default, only env variables prefixed with `VITE_` are loaded, unless `prefixes` is changed. ## `normalizePath` **Type Signature:** ```ts function normalizePath(id: string): string ``` **Related:** [Path Normalization](./api-plugin.md#path-normalization) Normalizes a path to interoperate between Vite plugins. ## `transformWithEsbuild` **Type Signature:** ```ts async function transformWithEsbuild( code: string, filename: string, options?: EsbuildTransformOptions, inMap?: object, ): Promise ``` Transform JavaScript or TypeScript with esbuild. Useful for plugins that prefer matching Vite's internal esbuild transform. ## `loadConfigFromFile` **Type Signature:** ```ts async function loadConfigFromFile( configEnv: ConfigEnv, configFile?: string, configRoot: string = process.cwd(), logLevel?: LogLevel, customLogger?: Logger, ): Promise<{ path: string config: UserConfig dependencies: string[] } | null> ``` Load a Vite config file manually with esbuild. ## `preprocessCSS` * **Experimental:** [Give Feedback](https://github.com/vitejs/vite/discussions/13815) **Type Signature:** ```ts async function preprocessCSS( code: string, filename: string, config: ResolvedConfig, ): Promise interface PreprocessCSSResult { code: string map?: SourceMapInput modules?: Record deps?: Set } ``` Pre-processes `.css`, `.scss`, `.sass`, `.less`, `.styl` and `.stylus` files to plain CSS so it can be used in browsers or parsed by other tools. Similar to the [built-in CSS pre-processing support](/guide/features#css-pre-processors), the corresponding pre-processor must be installed if used. The pre-processor used is inferred from the `filename` extension. If the `filename` ends with `.module.{ext}`, it is inferred as a [CSS module](https://github.com/css-modules/css-modules) and the returned result will include a `modules` object mapping the original class names to the transformed ones. Note that pre-processing will not resolve URLs in `url()` or `image-set()`. --- # Source: https://vite.dev/guide/api-plugin.md --- url: /guide/api-plugin.md --- # Plugin API Vite plugins extends Rollup's well-designed plugin interface with a few extra Vite-specific options. As a result, you can write a Vite plugin once and have it work for both dev and build. **It is recommended to go through [Rollup's plugin documentation](https://rollupjs.org/plugin-development/) first before reading the sections below.** ## Authoring a Plugin Vite strives to offer established patterns out of the box, so before creating a new plugin make sure that you check the [Features guide](/guide/features) to see if your need is covered. Also review available community plugins, both in the form of a [compatible Rollup plugin](https://github.com/rollup/awesome) and [Vite Specific plugins](https://github.com/vitejs/awesome-vite#plugins) When creating a plugin, you can inline it in your `vite.config.js`. There is no need to create a new package for it. Once you see that a plugin was useful in your projects, consider sharing it to help others [in the ecosystem](https://chat.vite.dev). ::: tip When learning, debugging, or authoring plugins, we suggest including [vite-plugin-inspect](https://github.com/antfu/vite-plugin-inspect) in your project. It allows you to inspect the intermediate state of Vite plugins. After installing, you can visit `localhost:5173/__inspect/` to inspect the modules and transformation stack of your project. Check out install instructions in the [vite-plugin-inspect docs](https://github.com/antfu/vite-plugin-inspect). ![vite-plugin-inspect](/assets/vite-plugin-inspect.BSP8m2UZ.webp) ::: ## Conventions If the plugin doesn't use Vite specific hooks and can be implemented as a [Compatible Rollup Plugin](#rollup-plugin-compatibility), then it is recommended to use the [Rollup Plugin naming conventions](https://rollupjs.org/plugin-development/#conventions). * Rollup Plugins should have a clear name with `rollup-plugin-` prefix. * Include `rollup-plugin` and `vite-plugin` keywords in package.json. This exposes the plugin to be also used in pure Rollup or WMR based projects For Vite only plugins * Vite Plugins should have a clear name with `vite-plugin-` prefix. * Include `vite-plugin` keyword in package.json. * Include a section in the plugin docs detailing why it is a Vite only plugin (for example, it uses Vite specific plugin hooks). If your plugin is only going to work for a particular framework, its name should be included as part of the prefix * `vite-plugin-vue-` prefix for Vue Plugins * `vite-plugin-react-` prefix for React Plugins * `vite-plugin-svelte-` prefix for Svelte Plugins See also [Virtual Modules Convention](#virtual-modules-convention). ## Plugins Config Users will add plugins to the project `devDependencies` and configure them using the `plugins` array option. ```js [vite.config.js] import vitePlugin from 'vite-plugin-feature' import rollupPlugin from 'rollup-plugin-feature' export default defineConfig({ plugins: [vitePlugin(), rollupPlugin()], }) ``` Falsy plugins will be ignored, which can be used to easily activate or deactivate plugins. `plugins` also accepts presets including several plugins as a single element. This is useful for complex features (like framework integration) that are implemented using several plugins. The array will be flattened internally. ```js // framework-plugin import frameworkRefresh from 'vite-plugin-framework-refresh' import frameworkDevtools from 'vite-plugin-framework-devtools' export default function framework(config) { return [frameworkRefresh(config), frameworkDevTools(config)] } ``` ```js [vite.config.js] import { defineConfig } from 'vite' import framework from 'vite-plugin-framework' export default defineConfig({ plugins: [framework()], }) ``` ## Simple Examples :::tip It is common convention to author a Vite/Rollup plugin as a factory function that returns the actual plugin object. The function can accept options which allows users to customize the behavior of the plugin. ::: ### Transforming Custom File Types ```js const fileRegex = /\.(my-file-ext)$/ export default function myPlugin() { return { name: 'transform-file', transform(src, id) { if (fileRegex.test(id)) { return { code: compileFileToJS(src), map: null, // provide source map if available } } }, } } ``` ### Importing a Virtual File See the example in the [next section](#virtual-modules-convention). ## Virtual Modules Convention Virtual modules are a useful scheme that allows you to pass build time information to the source files using normal ESM import syntax. ```js export default function myPlugin() { const virtualModuleId = 'virtual:my-module' const resolvedVirtualModuleId = '\0' + virtualModuleId return { name: 'my-plugin', // required, will show up in warnings and errors resolveId(id) { if (id === virtualModuleId) { return resolvedVirtualModuleId } }, load(id) { if (id === resolvedVirtualModuleId) { return `export const msg = "from virtual module"` } }, } } ``` Which allows importing the module in JavaScript: ```js import { msg } from 'virtual:my-module' console.log(msg) ``` Virtual modules in Vite (and Rollup) are prefixed with `virtual:` for the user-facing path by convention. If possible the plugin name should be used as a namespace to avoid collisions with other plugins in the ecosystem. For example, a `vite-plugin-posts` could ask users to import a `virtual:posts` or `virtual:posts/helpers` virtual modules to get build time information. Internally, plugins that use virtual modules should prefix the module ID with `\0` while resolving the id, a convention from the rollup ecosystem. This prevents other plugins from trying to process the id (like node resolution), and core features like sourcemaps can use this info to differentiate between virtual modules and regular files. `\0` is not a permitted char in import URLs so we have to replace them during import analysis. A `\0{id}` virtual id ends up encoded as `/@id/__x00__{id}` during dev in the browser. The id will be decoded back before entering the plugins pipeline, so this is not seen by plugins hooks code. Note that modules directly derived from a real file, as in the case of a script module in a Single File Component (like a .vue or .svelte SFC) don't need to follow this convention. SFCs generally generate a set of submodules when processed but the code in these can be mapped back to the filesystem. Using `\0` for these submodules would prevent sourcemaps from working correctly. ## Universal Hooks During dev, the Vite dev server creates a plugin container that invokes [Rollup Build Hooks](https://rollupjs.org/plugin-development/#build-hooks) the same way Rollup does it. The following hooks are called once on server start: * [`options`](https://rollupjs.org/plugin-development/#options) * [`buildStart`](https://rollupjs.org/plugin-development/#buildstart) The following hooks are called on each incoming module request: * [`resolveId`](https://rollupjs.org/plugin-development/#resolveid) * [`load`](https://rollupjs.org/plugin-development/#load) * [`transform`](https://rollupjs.org/plugin-development/#transform) These hooks also have an extended `options` parameter with additional Vite-specific properties. You can read more in the [SSR documentation](/guide/ssr#ssr-specific-plugin-logic). Some `resolveId` calls' `importer` value may be an absolute path for a generic `index.html` at root as it's not always possible to derive the actual importer due to Vite's unbundled dev server pattern. For imports handled within Vite's resolve pipeline, the importer can be tracked during the import analysis phase, providing the correct `importer` value. The following hooks are called when the server is closed: * [`buildEnd`](https://rollupjs.org/plugin-development/#buildend) * [`closeBundle`](https://rollupjs.org/plugin-development/#closebundle) Note that the [`moduleParsed`](https://rollupjs.org/plugin-development/#moduleparsed) hook is **not** called during dev, because Vite avoids full AST parses for better performance. [Output Generation Hooks](https://rollupjs.org/plugin-development/#output-generation-hooks) (except `closeBundle`) are **not** called during dev. You can think of Vite's dev server as only calling `rollup.rollup()` without calling `bundle.generate()`. ## Vite Specific Hooks Vite plugins can also provide hooks that serve Vite-specific purposes. These hooks are ignored by Rollup. ### `config` * **Type:** `(config: UserConfig, env: { mode: string, command: string }) => UserConfig | null | void` * **Kind:** `async`, `sequential` Modify Vite config before it's resolved. The hook receives the raw user config (CLI options merged with config file) and the current config env which exposes the `mode` and `command` being used. It can return a partial config object that will be deeply merged into existing config, or directly mutate the config (if the default merging cannot achieve the desired result). **Example:** ```js // return partial config (recommended) const partialConfigPlugin = () => ({ name: 'return-partial', config: () => ({ resolve: { alias: { foo: 'bar', }, }, }), }) // mutate the config directly (use only when merging doesn't work) const mutateConfigPlugin = () => ({ name: 'mutate-config', config(config, { command }) { if (command === 'build') { config.root = 'foo' } }, }) ``` ::: warning Note User plugins are resolved before running this hook so injecting other plugins inside the `config` hook will have no effect. ::: ### `configResolved` * **Type:** `(config: ResolvedConfig) => void | Promise` * **Kind:** `async`, `parallel` Called after the Vite config is resolved. Use this hook to read and store the final resolved config. It is also useful when the plugin needs to do something different based on the command being run. **Example:** ```js const examplePlugin = () => { let config return { name: 'read-config', configResolved(resolvedConfig) { // store the resolved config config = resolvedConfig }, // use stored config in other hooks transform(code, id) { if (config.command === 'serve') { // dev: plugin invoked by dev server } else { // build: plugin invoked by Rollup } }, } } ``` Note that the `command` value is `serve` in dev (in the cli `vite`, `vite dev`, and `vite serve` are aliases). ### `configureServer` * **Type:** `(server: ViteDevServer) => (() => void) | void | Promise<(() => void) | void>` * **Kind:** `async`, `sequential` * **See also:** [ViteDevServer](./api-javascript#vitedevserver) Hook for configuring the dev server. The most common use case is adding custom middlewares to the internal [connect](https://github.com/senchalabs/connect) app: ```js const myPlugin = () => ({ name: 'configure-server', configureServer(server) { server.middlewares.use((req, res, next) => { // custom handle request... }) }, }) ``` **Injecting Post Middleware** The `configureServer` hook is called before internal middlewares are installed, so the custom middlewares will run before internal middlewares by default. If you want to inject a middleware **after** internal middlewares, you can return a function from `configureServer`, which will be called after internal middlewares are installed: ```js const myPlugin = () => ({ name: 'configure-server', configureServer(server) { // return a post hook that is called after internal middlewares are // installed return () => { server.middlewares.use((req, res, next) => { // custom handle request... }) } }, }) ``` **Storing Server Access** In some cases, other plugin hooks may need access to the dev server instance (e.g. accessing the WebSocket server, the file system watcher, or the module graph). This hook can also be used to store the server instance for access in other hooks: ```js const myPlugin = () => { let server return { name: 'configure-server', configureServer(_server) { server = _server }, transform(code, id) { if (server) { // use server... } }, } } ``` Note `configureServer` is not called when running the production build so your other hooks need to guard against its absence. ### `configurePreviewServer` * **Type:** `(server: PreviewServer) => (() => void) | void | Promise<(() => void) | void>` * **Kind:** `async`, `sequential` * **See also:** [PreviewServer](./api-javascript#previewserver) Same as [`configureServer`](/guide/api-plugin.html#configureserver) but for the preview server. Similarly to `configureServer`, the `configurePreviewServer` hook is called before other middlewares are installed. If you want to inject a middleware **after** other middlewares, you can return a function from `configurePreviewServer`, which will be called after internal middlewares are installed: ```js const myPlugin = () => ({ name: 'configure-preview-server', configurePreviewServer(server) { // return a post hook that is called after other middlewares are // installed return () => { server.middlewares.use((req, res, next) => { // custom handle request... }) } }, }) ``` ### `transformIndexHtml` * **Type:** `IndexHtmlTransformHook | { order?: 'pre' | 'post', handler: IndexHtmlTransformHook }` * **Kind:** `async`, `sequential` Dedicated hook for transforming HTML entry point files such as `index.html`. The hook receives the current HTML string and a transform context. The context exposes the [`ViteDevServer`](./api-javascript#vitedevserver) instance during dev, and exposes the Rollup output bundle during build. The hook can be async and can return one of the following: * Transformed HTML string * An array of tag descriptor objects (`{ tag, attrs, children }`) to inject to the existing HTML. Each tag can also specify where it should be injected to (default is prepending to ``) * An object containing both as `{ html, tags }` By default `order` is `undefined`, with this hook applied after the HTML has been transformed. In order to inject a script that should go through the Vite plugins pipeline, `order: 'pre'` will apply the hook before processing the HTML. `order: 'post'` applies the hook after all hooks with `order` undefined are applied. **Basic Example:** ```js const htmlPlugin = () => { return { name: 'html-transform', transformIndexHtml(html) { return html.replace( /(.*?)<\/title>/, `<title>Title replaced!`, ) }, } } ``` **Full Hook Signature:** ```ts type IndexHtmlTransformHook = ( html: string, ctx: { path: string filename: string server?: ViteDevServer bundle?: import('rollup').OutputBundle chunk?: import('rollup').OutputChunk }, ) => | IndexHtmlTransformResult | void | Promise type IndexHtmlTransformResult = | string | HtmlTagDescriptor[] | { html: string tags: HtmlTagDescriptor[] } interface HtmlTagDescriptor { tag: string /** * attribute values will be escaped automatically if needed */ attrs?: Record children?: string | HtmlTagDescriptor[] /** * default: 'head-prepend' */ injectTo?: 'head' | 'body' | 'head-prepend' | 'body-prepend' } ``` ::: warning Note This hook won't be called if you are using a framework that has custom handling of entry files (for example [SvelteKit](https://github.com/sveltejs/kit/discussions/8269#discussioncomment-4509145)). ::: ### `handleHotUpdate` * **Type:** `(ctx: HmrContext) => Array | void | Promise | void>` * **Kind:** `async`, `sequential` * **See also:** [HMR API](./api-hmr) Perform custom HMR update handling. The hook receives a context object with the following signature: ```ts interface HmrContext { file: string timestamp: number modules: Array read: () => string | Promise server: ViteDevServer } ``` * `modules` is an array of modules that are affected by the changed file. It's an array because a single file may map to multiple served modules (e.g. Vue SFCs). * `read` is an async read function that returns the content of the file. This is provided because on some systems, the file change callback may fire too fast before the editor finishes updating the file and direct `fs.readFile` will return empty content. The read function passed in normalizes this behavior. The hook can choose to: * Filter and narrow down the affected module list so that the HMR is more accurate. * Return an empty array and perform a full reload: ```js handleHotUpdate({ server, modules, timestamp }) { // Invalidate modules manually const invalidatedModules = new Set() for (const mod of modules) { server.moduleGraph.invalidateModule( mod, invalidatedModules, timestamp, true ) } server.ws.send({ type: 'full-reload' }) return [] } ``` * Return an empty array and perform complete custom HMR handling by sending custom events to the client: ```js handleHotUpdate({ server }) { server.ws.send({ type: 'custom', event: 'special-update', data: {} }) return [] } ``` Client code should register corresponding handler using the [HMR API](./api-hmr) (this could be injected by the same plugin's `transform` hook): ```js if (import.meta.hot) { import.meta.hot.on('special-update', (data) => { // perform custom update }) } ``` ## Plugin Ordering A Vite plugin can additionally specify an `enforce` property (similar to webpack loaders) to adjust its application order. The value of `enforce` can be either `"pre"` or `"post"`. The resolved plugins will be in the following order: * Alias * User plugins with `enforce: 'pre'` * Vite core plugins * User plugins without enforce value * Vite build plugins * User plugins with `enforce: 'post'` * Vite post build plugins (minify, manifest, reporting) Note that this is separate from hooks ordering, those are still separately subject to their `order` attribute [as usual for Rollup hooks](https://rollupjs.org/plugin-development/#build-hooks). ## Conditional Application By default plugins are invoked for both serve and build. In cases where a plugin needs to be conditionally applied only during serve or build, use the `apply` property to only invoke them during `'build'` or `'serve'`: ```js function myPlugin() { return { name: 'build-only', apply: 'build', // or 'serve' } } ``` A function can also be used for more precise control: ```js apply(config, { command }) { // apply only on build but not for SSR return command === 'build' && !config.build.ssr } ``` ## Rollup Plugin Compatibility A fair number of Rollup plugins will work directly as a Vite plugin (e.g. `@rollup/plugin-alias` or `@rollup/plugin-json`), but not all of them, since some plugin hooks do not make sense in an unbundled dev server context. In general, as long as a Rollup plugin fits the following criteria then it should just work as a Vite plugin: * It doesn't use the [`moduleParsed`](https://rollupjs.org/plugin-development/#moduleparsed) hook. * It doesn't have strong coupling between bundle-phase hooks and output-phase hooks. If a Rollup plugin only makes sense for the build phase, then it can be specified under `build.rollupOptions.plugins` instead. It will work the same as a Vite plugin with `enforce: 'post'` and `apply: 'build'`. You can also augment an existing Rollup plugin with Vite-only properties: ```js [vite.config.js] import example from 'rollup-plugin-example' import { defineConfig } from 'vite' export default defineConfig({ plugins: [ { ...example(), enforce: 'post', apply: 'build', }, ], }) ``` ## Path Normalization Vite normalizes paths while resolving ids to use POSIX separators ( / ) while preserving the volume in Windows. On the other hand, Rollup keeps resolved paths untouched by default, so resolved ids have win32 separators ( \ ) in Windows. However, Rollup plugins use a [`normalizePath` utility function](https://github.com/rollup/plugins/tree/master/packages/pluginutils#normalizepath) from `@rollup/pluginutils` internally, which converts separators to POSIX before performing comparisons. This means that when these plugins are used in Vite, the `include` and `exclude` config pattern and other similar paths against resolved ids comparisons work correctly. So, for Vite plugins, when comparing paths against resolved ids it is important to first normalize the paths to use POSIX separators. An equivalent `normalizePath` utility function is exported from the `vite` module. ```js import { normalizePath } from 'vite' normalizePath('foo\\bar') // 'foo/bar' normalizePath('foo/bar') // 'foo/bar' ``` ## Filtering, include/exclude pattern Vite exposes [`@rollup/pluginutils`'s `createFilter`](https://github.com/rollup/plugins/tree/master/packages/pluginutils#createfilter) function to encourage Vite specific plugins and integrations to use the standard include/exclude filtering pattern, which is also used in Vite core itself. ### Hook Filters Rolldown introduced a [hook filter feature](https://rolldown.rs/plugins/hook-filters) to reduce the communication overhead between the Rust and JavaScript runtimes. This feature allows plugins to specify patterns that determine when hooks should be called, improving performance by avoiding unnecessary hook invocations. This is also supported by Rollup 4.38.0+ and Vite 6.3.0+. To make your plugin backward compatible with older versions, make sure to also run the filter inside the hook handlers. ```js export default function myPlugin() { const jsFileRegex = /\.js$/ return { name: 'my-plugin', // Example: only call transform for .js files transform: { filter: { id: jsFileRegex, }, handler(code, id) { // Additional check for backward compatibility if (!jsFileRegex.test(id)) return null return { code: transformCode(code), map: null, } }, }, } } ``` ::: tip [`@rolldown/pluginutils`](https://www.npmjs.com/package/@rolldown/pluginutils) exports some utilities for hook filters like `exactRegex` and `prefixRegex`. ::: ## Client-server Communication Since Vite 2.9, we provide some utilities for plugins to help handle the communication with clients. ### Server to Client On the plugin side, we could use `server.ws.send` to broadcast events to the client: ```js [vite.config.js] export default defineConfig({ plugins: [ { // ... configureServer(server) { server.ws.on('connection', () => { server.ws.send('my:greetings', { msg: 'hello' }) }) }, }, ], }) ``` ::: tip NOTE We recommend **always prefixing** your event names to avoid collisions with other plugins. ::: On the client side, use [`hot.on`](/guide/api-hmr.html#hot-on-event-cb) to listen to the events: ```ts twoslash import 'vite/client' // ---cut--- // client side if (import.meta.hot) { import.meta.hot.on('my:greetings', (data) => { console.log(data.msg) // hello }) } ``` ### Client to Server To send events from the client to the server, we can use [`hot.send`](/guide/api-hmr.html#hot-send-event-payload): ```ts // client side if (import.meta.hot) { import.meta.hot.send('my:from-client', { msg: 'Hey!' }) } ``` Then use `server.ws.on` and listen to the events on the server side: ```js [vite.config.js] export default defineConfig({ plugins: [ { // ... configureServer(server) { server.ws.on('my:from-client', (data, client) => { console.log('Message from client:', data.msg) // Hey! // reply only to the client (if needed) client.send('my:ack', { msg: 'Hi! I got your message!' }) }) }, }, ], }) ``` ### TypeScript for Custom Events Internally, vite infers the type of a payload from the `CustomEventMap` interface, it is possible to type custom events by extending the interface: :::tip Note Make sure to include the `.d.ts` extension when specifying TypeScript declaration files. Otherwise, Typescript may not know which file the module is trying to extend. ::: ```ts [events.d.ts] import 'vite/types/customEvent.d.ts' declare module 'vite/types/customEvent.d.ts' { interface CustomEventMap { 'custom:foo': { msg: string } // 'event-key': payload } } ``` This interface extension is utilized by `InferCustomEventPayload` to infer the payload type for event `T`. For more information on how this interface is utilized, refer to the [HMR API Documentation](./api-hmr#hmr-api). ```ts twoslash import 'vite/client' import type { InferCustomEventPayload } from 'vite/types/customEvent.d.ts' declare module 'vite/types/customEvent.d.ts' { interface CustomEventMap { 'custom:foo': { msg: string } } } // ---cut--- type CustomFooPayload = InferCustomEventPayload<'custom:foo'> import.meta.hot?.on('custom:foo', (payload) => { // The type of payload will be { msg: string } }) import.meta.hot?.on('unknown:event', (payload) => { // The type of payload will be any }) ``` --- # Source: https://vite.dev/guide/build.md --- url: /guide/build.md --- # Building for Production When it is time to deploy your app for production, simply run the `vite build` command. By default, it uses `/index.html` as the build entry point, and produces an application bundle that is suitable to be served over a static hosting service. Check out the [Deploying a Static Site](./static-deploy) for guides about popular services. ## Browser Compatibility By default, the production bundle assumes a modern browser that is included in the [Baseline](https://web-platform-dx.github.io/web-features/) Widely Available targets. The default browser support range is: * Chrome >=107 * Edge >=107 * Firefox >=104 * Safari >=16 You can specify custom targets via the [`build.target` config option](/config/build-options.md#build-target), where the lowest target is `es2015`. If a lower target is set, Vite will still require these minimum browser support ranges as it relies on [native ESM dynamic import](https://caniuse.com/es6-module-dynamic-import), and [`import.meta`](https://caniuse.com/mdn-javascript_operators_import_meta): * Chrome >=64 * Firefox >=67 * Safari >=11.1 * Edge >=79 Note that by default, Vite only handles syntax transforms and **does not cover polyfills**. You can check out https://cdnjs.cloudflare.com/polyfill/ which automatically generates polyfill bundles based on the user's browser UserAgent string. Legacy browsers can be supported via [@vitejs/plugin-legacy](https://github.com/vitejs/vite/tree/main/packages/plugin-legacy), which will automatically generate legacy chunks and corresponding ES language feature polyfills. The legacy chunks are conditionally loaded only in browsers that do not have native ESM support. ## Public Base Path * Related: [Asset Handling](./assets) If you are deploying your project under a nested public path, simply specify the [`base` config option](/config/shared-options.md#base) and all asset paths will be rewritten accordingly. This option can also be specified as a command line flag, e.g. `vite build --base=/my/public/path/`. JS-imported asset URLs, CSS `url()` references, and asset references in your `.html` files are all automatically adjusted to respect this option during build. The exception is when you need to dynamically concatenate URLs on the fly. In this case, you can use the globally injected `import.meta.env.BASE_URL` variable which will be the public base path. Note this variable is statically replaced during build so it must appear exactly as-is (i.e. `import.meta.env['BASE_URL']` won't work). For advanced base path control, check out [Advanced Base Options](#advanced-base-options). ### Relative base If you don't know the base path in advance, you may set a relative base path with `"base": "./"` or `"base": ""`. This will make all generated URLs to be relative to each file. :::warning Support for older browsers when using relative bases `import.meta` support is required for relative bases. If you need to support [browsers that do not support `import.meta`](https://caniuse.com/mdn-javascript_operators_import_meta), you can use [the `legacy` plugin](https://github.com/vitejs/vite/tree/main/packages/plugin-legacy). ::: ## Customizing the Build The build can be customized via various [build config options](/config/build-options.md). Specifically, you can directly adjust the underlying [Rollup options](https://rollupjs.org/configuration-options/) via `build.rollupOptions`: ```js [vite.config.js] export default defineConfig({ build: { rollupOptions: { // https://rollupjs.org/configuration-options/ }, }, }) ``` For example, you can specify multiple Rollup outputs with plugins that are only applied during build. ## Chunking Strategy You can configure how chunks are split using `build.rollupOptions.output.manualChunks` (see [Rollup docs](https://rollupjs.org/configuration-options/#output-manualchunks)). If you use a framework, refer to their documentation for configuring how chunks are split. ## Load Error Handling Vite emits `vite:preloadError` event when it fails to load dynamic imports. `event.payload` contains the original import error. If you call `event.preventDefault()`, the error will not be thrown. ```js twoslash window.addEventListener('vite:preloadError', (event) => { window.location.reload() // for example, refresh the page }) ``` When a new deployment occurs, the hosting service may delete the assets from previous deployments. As a result, a user who visited your site before the new deployment might encounter an import error. This error happens because the assets running on that user's device are outdated and it tries to import the corresponding old chunk, which is deleted. This event is useful for addressing this situation. In this case, make sure to set `Cache-Control: no-cache` on the HTML file, otherwise the old assets will be still referenced. ## Rebuild on Files Changes You can enable rollup watcher with `vite build --watch`. Or, you can directly adjust the underlying [`WatcherOptions`](https://rollupjs.org/configuration-options/#watch) via `build.watch`: ```js [vite.config.js] export default defineConfig({ build: { watch: { // https://rollupjs.org/configuration-options/#watch }, }, }) ``` With the `--watch` flag enabled, changes to the `vite.config.js`, as well as any files to be bundled, will trigger a rebuild. ## Multi-Page App Suppose you have the following source code structure: ``` ├── package.json ├── vite.config.js ├── index.html ├── main.js └── nested ├── index.html └── nested.js ``` During dev, simply navigate or link to `/nested/` - it works as expected, just like for a normal static file server. During build, all you need to do is to specify multiple `.html` files as entry points: ```js twoslash [vite.config.js] import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' import { defineConfig } from 'vite' const __dirname = dirname(fileURLToPath(import.meta.url)) export default defineConfig({ build: { rollupOptions: { input: { main: resolve(__dirname, 'index.html'), nested: resolve(__dirname, 'nested/index.html'), }, }, }, }) ``` If you specify a different root, remember that `__dirname` will still be the folder of your vite.config.js file when resolving the input paths. Therefore, you will need to add your `root` entry to the arguments for `resolve`. Note that for HTML files, Vite ignores the name given to the entry in the `rollupOptions.input` object and instead respects the resolved id of the file when generating the HTML asset in the dist folder. This ensures a consistent structure with the way the dev server works. ## Library Mode When you are developing a browser-oriented library, you are likely spending most of the time on a test/demo page that imports your actual library. With Vite, you can use your `index.html` for that purpose to get the smooth development experience. When it is time to bundle your library for distribution, use the [`build.lib` config option](/config/build-options.md#build-lib). Make sure to also externalize any dependencies that you do not want to bundle into your library, e.g. `vue` or `react`: ::: code-group ```js twoslash [vite.config.js (single entry)] import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' import { defineConfig } from 'vite' const __dirname = dirname(fileURLToPath(import.meta.url)) export default defineConfig({ build: { lib: { entry: resolve(__dirname, 'lib/main.js'), name: 'MyLib', // the proper extensions will be added fileName: 'my-lib', }, rollupOptions: { // make sure to externalize deps that shouldn't be bundled // into your library external: ['vue'], output: { // Provide global variables to use in the UMD build // for externalized deps globals: { vue: 'Vue', }, }, }, }, }) ``` ```js twoslash [vite.config.js (multiple entries)] import { dirname, resolve } from 'node:path' import { fileURLToPath } from 'node:url' import { defineConfig } from 'vite' const __dirname = dirname(fileURLToPath(import.meta.url)) export default defineConfig({ build: { lib: { entry: { 'my-lib': resolve(__dirname, 'lib/main.js'), secondary: resolve(__dirname, 'lib/secondary.js'), }, name: 'MyLib', }, rollupOptions: { // make sure to externalize deps that shouldn't be bundled // into your library external: ['vue'], output: { // Provide global variables to use in the UMD build // for externalized deps globals: { vue: 'Vue', }, }, }, }, }) ``` ::: The entry file would contain exports that can be imported by users of your package: ```js [lib/main.js] import Foo from './Foo.vue' import Bar from './Bar.vue' export { Foo, Bar } ``` Running `vite build` with this config uses a Rollup preset that is oriented towards shipping libraries and produces two bundle formats: * `es` and `umd` (for single entry) * `es` and `cjs` (for multiple entries) The formats can be configured with the [`build.lib.formats`](/config/build-options.md#build-lib) option. ``` $ vite build building for production... dist/my-lib.js 0.08 kB / gzip: 0.07 kB dist/my-lib.umd.cjs 0.30 kB / gzip: 0.16 kB ``` Recommended `package.json` for your lib: ::: code-group ```json [package.json (single entry)] { "name": "my-lib", "type": "module", "files": ["dist"], "main": "./dist/my-lib.umd.cjs", "module": "./dist/my-lib.js", "exports": { ".": { "import": "./dist/my-lib.js", "require": "./dist/my-lib.umd.cjs" } } } ``` ```json [package.json (multiple entries)] { "name": "my-lib", "type": "module", "files": ["dist"], "main": "./dist/my-lib.cjs", "module": "./dist/my-lib.js", "exports": { ".": { "import": "./dist/my-lib.js", "require": "./dist/my-lib.cjs" }, "./secondary": { "import": "./dist/secondary.js", "require": "./dist/secondary.cjs" } } } ``` ::: ### CSS support If your library imports any CSS, it will be bundled as a single CSS file besides the built JS files, e.g. `dist/my-lib.css`. The name defaults to `build.lib.fileName`, but can also be changed with [`build.lib.cssFileName`](/config/build-options.md#build-lib). You can export the CSS file in your `package.json` to be imported by users: ```json {12} { "name": "my-lib", "type": "module", "files": ["dist"], "main": "./dist/my-lib.umd.cjs", "module": "./dist/my-lib.js", "exports": { ".": { "import": "./dist/my-lib.js", "require": "./dist/my-lib.umd.cjs" }, "./style.css": "./dist/my-lib.css" } } ``` ::: tip File Extensions If the `package.json` does not contain `"type": "module"`, Vite will generate different file extensions for Node.js compatibility. `.js` will become `.mjs` and `.cjs` will become `.js`. ::: ::: tip Environment Variables In library mode, all [`import.meta.env.*`](./env-and-mode.md) usage are statically replaced when building for production. However, `process.env.*` usage are not, so that consumers of your library can dynamically change it. If this is undesirable, you can use `define: { 'process.env.NODE_ENV': '"production"' }` for example to statically replace them, or use [`esm-env`](https://github.com/benmccann/esm-env) for better compatibility with bundlers and runtimes. ::: ::: warning Advanced Usage Library mode includes a simple and opinionated configuration for browser-oriented and JS framework libraries. If you are building non-browser libraries, or require advanced build flows, you can use [Rollup](https://rollupjs.org) or [esbuild](https://esbuild.github.io) directly. ::: ## Advanced Base Options ::: warning This feature is experimental. [Give Feedback](https://github.com/vitejs/vite/discussions/13834). ::: For advanced use cases, the deployed assets and public files may be in different paths, for example to use different cache strategies. A user may choose to deploy in three different paths: * The generated entry HTML files (which may be processed during SSR) * The generated hashed assets (JS, CSS, and other file types like images) * The copied [public files](assets.md#the-public-directory) A single static [base](#public-base-path) isn't enough in these scenarios. Vite provides experimental support for advanced base options during build, using `experimental.renderBuiltUrl`. ```ts twoslash import type { UserConfig } from 'vite' // prettier-ignore const config: UserConfig = { // ---cut-before--- experimental: { renderBuiltUrl(filename, { hostType }) { if (hostType === 'js') { return { runtime: `window.__toCdnUrl(${JSON.stringify(filename)})` } } else { return { relative: true } } }, }, // ---cut-after--- } ``` If the hashed assets and public files aren't deployed together, options for each group can be defined independently using asset `type` included in the second `context` param given to the function. ```ts twoslash import type { UserConfig } from 'vite' import path from 'node:path' // prettier-ignore const config: UserConfig = { // ---cut-before--- experimental: { renderBuiltUrl(filename, { hostId, hostType, type }) { if (type === 'public') { return 'https://www.domain.com/' + filename } else if (path.extname(hostId) === '.js') { return { runtime: `window.__assetsPath(${JSON.stringify(filename)})` } } else { return 'https://cdn.domain.com/assets/' + filename } }, }, // ---cut-after--- } ``` Note that the `filename` passed is a decoded URL, and if the function returns a URL string, it should also be decoded. Vite will handle the encoding automatically when rendering the URLs. If an object with `runtime` is returned, encoding should be handled yourself where needed as the runtime code will be rendered as is. --- # Source: https://vite.dev/guide/features.md --- url: /guide/features.md --- # Features At the very basic level, developing using Vite is not that different from using a static file server. However, Vite provides many enhancements over native ESM imports to support various features that are typically seen in bundler-based setups. ## npm Dependency Resolving and Pre-Bundling Native ES imports do not support bare module imports like the following: ```js import { someMethod } from 'my-dep' ``` The above will throw an error in the browser. Vite will detect such bare module imports in all served source files and perform the following: 1. [Pre-bundle](./dep-pre-bundling) them to improve page loading speed and convert CommonJS / UMD modules to ESM. The pre-bundling step is performed with [esbuild](http://esbuild.github.io/) and makes Vite's cold start time significantly faster than any JavaScript-based bundler. 2. Rewrite the imports to valid URLs like `/node_modules/.vite/deps/my-dep.js?v=f3sf2ebd` so that the browser can import them properly. **Dependencies are Strongly Cached** Vite caches dependency requests via HTTP headers, so if you wish to locally edit/debug a dependency, follow the steps [here](./dep-pre-bundling#browser-cache). ## Hot Module Replacement Vite provides an [HMR API](./api-hmr) over native ESM. Frameworks with HMR capabilities can leverage the API to provide instant, precise updates without reloading the page or blowing away application state. Vite provides first-party HMR integrations for [Vue Single File Components](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue) and [React Fast Refresh](https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react). There are also official integrations for Preact via [@prefresh/vite](https://github.com/JoviDeCroock/prefresh/tree/main/packages/vite). Note you don't need to manually set these up - when you [create an app via `create-vite`](./), the selected templates would have these pre-configured for you already. ## TypeScript Vite supports importing `.ts` files out of the box. ### Transpile Only Note that Vite only performs transpilation on `.ts` files and does **NOT** perform type checking. It assumes type checking is taken care of by your IDE and build process. The reason Vite does not perform type checking as part of the transform process is because the two jobs work fundamentally differently. Transpilation can work on a per-file basis and aligns perfectly with Vite's on-demand compile model. In comparison, type checking requires knowledge of the entire module graph. Shoe-horning type checking into Vite's transform pipeline will inevitably compromise Vite's speed benefits. Vite's job is to get your source modules into a form that can run in the browser as fast as possible. To that end, we recommend separating static analysis checks from Vite's transform pipeline. This principle applies to other static analysis checks such as ESLint. * For production builds, you can run `tsc --noEmit` in addition to Vite's build command. * During development, if you need more than IDE hints, we recommend running `tsc --noEmit --watch` in a separate process, or use [vite-plugin-checker](https://github.com/fi3ework/vite-plugin-checker) if you prefer having type errors directly reported in the browser. Vite uses [esbuild](https://github.com/evanw/esbuild) to transpile TypeScript into JavaScript which is about 20~30x faster than vanilla `tsc`, and HMR updates can reflect in the browser in under 50ms. Use the [Type-Only Imports and Export](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-8.html#type-only-imports-and-export) syntax to avoid potential problems like type-only imports being incorrectly bundled, for example: ```ts import type { T } from 'only/types' export type { T } ``` ### TypeScript Compiler Options Vite respects some of the options in `tsconfig.json` and sets the corresponding esbuild options. For each file, Vite uses the `tsconfig.json` in the closest parent directory. If that `tsconfig.json` contains a [`references`](https://www.typescriptlang.org/tsconfig/#references) field, Vite will use the referenced config file that satisfies the [`include`](https://www.typescriptlang.org/tsconfig/#include) and [`exclude`](https://www.typescriptlang.org/tsconfig/#exclude) fields. When the options are set in both the Vite config and the `tsconfig.json`, the value in the Vite config takes precedence. Some configuration fields under `compilerOptions` in `tsconfig.json` require special attention. #### `isolatedModules` * [TypeScript documentation](https://www.typescriptlang.org/tsconfig#isolatedModules) Should be set to `true`. It is because `esbuild` only performs transpilation without type information, it doesn't support certain features like const enum and implicit type-only imports. You must set `"isolatedModules": true` in your `tsconfig.json` under `compilerOptions`, so that TS will warn you against the features that do not work with isolated transpilation. If a dependency doesn't work well with `"isolatedModules": true`. You can use `"skipLibCheck": true` to temporarily suppress the errors until it is fixed upstream. #### `useDefineForClassFields` * [TypeScript documentation](https://www.typescriptlang.org/tsconfig#useDefineForClassFields) The default value will be `true` if the TypeScript target is `ES2022` or newer including `ESNext`. It is consistent with the [behavior of TypeScript 4.3.2+](https://github.com/microsoft/TypeScript/pull/42663). Other TypeScript targets will default to `false`. `true` is the standard ECMAScript runtime behavior. If you are using a library that heavily relies on class fields, please be careful about the library's intended usage of it. While most libraries expect `"useDefineForClassFields": true`, you can explicitly set `useDefineForClassFields` to `false` if your library doesn't support it. #### `target` * [TypeScript documentation](https://www.typescriptlang.org/tsconfig#target) Vite ignores the `target` value in the `tsconfig.json`, following the same behavior as `esbuild`. To specify the target in dev, the [`esbuild.target`](/config/shared-options.html#esbuild) option can be used, which defaults to `esnext` for minimal transpilation. In builds, the [`build.target`](/config/build-options.html#build-target) option takes higher priority over `esbuild.target` and can also be set if needed. ::: warning `useDefineForClassFields` If `target` in `tsconfig.json` is not `ESNext` or `ES2022` or newer, or if there's no `tsconfig.json` file, `useDefineForClassFields` will default to `false` which can be problematic with the default `esbuild.target` value of `esnext`. It may transpile to [static initialization blocks](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes/Static_initialization_blocks#browser_compatibility) which may not be supported in your browser. As such, it is recommended to set `target` to `ESNext` or `ES2022` or newer, or set `useDefineForClassFields` to `true` explicitly when configuring `tsconfig.json`. ::: #### Other Compiler Options Affecting the Build Result * [`extends`](https://www.typescriptlang.org/tsconfig#extends) * [`importsNotUsedAsValues`](https://www.typescriptlang.org/tsconfig#importsNotUsedAsValues) * [`preserveValueImports`](https://www.typescriptlang.org/tsconfig#preserveValueImports) * [`verbatimModuleSyntax`](https://www.typescriptlang.org/tsconfig#verbatimModuleSyntax) * [`jsx`](https://www.typescriptlang.org/tsconfig#jsx) * [`jsxFactory`](https://www.typescriptlang.org/tsconfig#jsxFactory) * [`jsxFragmentFactory`](https://www.typescriptlang.org/tsconfig#jsxFragmentFactory) * [`jsxImportSource`](https://www.typescriptlang.org/tsconfig#jsxImportSource) * [`experimentalDecorators`](https://www.typescriptlang.org/tsconfig#experimentalDecorators) * [`alwaysStrict`](https://www.typescriptlang.org/tsconfig#alwaysStrict) ::: tip `skipLibCheck` Vite starter templates have `"skipLibCheck": "true"` by default to avoid typechecking dependencies, as they may choose to only support specific versions and configurations of TypeScript. You can learn more at [vuejs/vue-cli#5688](https://github.com/vuejs/vue-cli/pull/5688). ::: ### Client Types Vite's default types are for its Node.js API. To shim the environment of client-side code in a Vite application, you can add `vite/client` to `compilerOptions.types` inside `tsconfig.json`: ```json [tsconfig.json] { "compilerOptions": { "types": ["vite/client", "some-other-global-lib"] } } ``` Note that if [`compilerOptions.types`](https://www.typescriptlang.org/tsconfig#types) is specified, only these packages will be included in the global scope (instead of all visible ”@types” packages). This is recommended since TS 5.9. ::: details Using triple-slash directive Alternatively, you can add a `d.ts` declaration file: ```typescript [vite-env.d.ts] /// ``` ::: `vite/client` provides the following type shims: * Asset imports (e.g. importing an `.svg` file) * Types for the Vite-injected [constants](./env-and-mode#env-variables) on `import.meta.env` * Types for the [HMR API](./api-hmr) on `import.meta.hot` ::: tip To override the default typing, add a type definition file that contains your typings. Then, add the type reference before `vite/client`. For example, to make the default import of `*.svg` a React component: * `vite-env-override.d.ts` (the file that contains your typings): ```ts declare module '*.svg' { const content: React.FC> export default content } ``` * If you are using `compilerOptions.types`, ensure the file is included in `tsconfig.json`: ```json [tsconfig.json] { "include": ["src", "./vite-env-override.d.ts"] } ``` * If you are using triple-slash directives, update the file containing the reference to `vite/client` (normally `vite-env.d.ts`): ```ts /// /// ``` ::: ## HTML HTML files stand [front-and-center](/guide/#index-html-and-project-root) of a Vite project, serving as the entry points for your application, making it simple to build single-page and [multi-page applications](/guide/build.html#multi-page-app). Any HTML files in your project root can be directly accessed by its respective directory path: * `/index.html` -> `http://localhost:5173/` * `/about.html` -> `http://localhost:5173/about.html` * `/blog/index.html` -> `http://localhost:5173/blog/index.html` Assets referenced by HTML elements such as ` ``` To opt-out of HTML processing on certain elements, you can add the `vite-ignore` attribute on the element, which can be useful when referencing external assets or CDN. ## Frameworks All modern frameworks maintain integrations with Vite. Most framework plugins are maintained by each framework team, with the exception of the official Vue and React Vite plugins that are maintained in the vite org: * Vue support via [@vitejs/plugin-vue](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue) * Vue JSX support via [@vitejs/plugin-vue-jsx](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue-jsx) * React support via [@vitejs/plugin-react](https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react) * React using SWC support via [@vitejs/plugin-react-swc](https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-react-swc) * [React Server Components (RSC)](https://react.dev/reference/rsc/server-components) support via [@vitejs/plugin-rsc](https://github.com/vitejs/vite-plugin-react/tree/main/packages/plugin-rsc) Check out the [Plugins Guide](/plugins/) for more information. ## JSX `.jsx` and `.tsx` files are also supported out of the box. JSX transpilation is also handled via [esbuild](https://esbuild.github.io). Your framework of choice will already configure JSX out of the box (for example, Vue users should use the official [@vitejs/plugin-vue-jsx](https://github.com/vitejs/vite-plugin-vue/tree/main/packages/plugin-vue-jsx) plugin, which provides Vue 3 specific features including HMR, global component resolving, directives and slots). If using JSX with your own framework, custom `jsxFactory` and `jsxFragment` can be configured using the [`esbuild` option](/config/shared-options.md#esbuild). For example, the Preact plugin would use: ```js twoslash [vite.config.js] import { defineConfig } from 'vite' export default defineConfig({ esbuild: { jsxFactory: 'h', jsxFragment: 'Fragment', }, }) ``` More details in [esbuild docs](https://esbuild.github.io/content-types/#jsx). You can inject the JSX helpers using `jsxInject` (which is a Vite-only option) to avoid manual imports: ```js twoslash [vite.config.js] import { defineConfig } from 'vite' export default defineConfig({ esbuild: { jsxInject: `import React from 'react'`, }, }) ``` ## CSS Importing `.css` files will inject its content to the page via a `