npm Dependency Resolving and Pre-Bundling
Native ES imports do not support bare module imports like the following:- Pre-bundle them to improve page loading speed and convert CommonJS / UMD modules to ESM. The pre-bundling step is performed with esbuild and makes Vite’s cold start time significantly faster than any JavaScript-based bundler.
-
Rewrite the imports to valid URLs like
/node_modules/.vite/deps/my-dep.js?v=f3sf2ebdso that the browser can import them properly.
Hot Module Replacement
Vite provides an HMR API 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
- React Fast Refresh
- Official integrations for Preact via @prefresh/vite
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.
- Production Builds
- Development
For production builds, you can run
tsc --noEmit in addition to Vite’s build command.tsc, and HMR updates can reflect in the browser in under 50ms.
Use the Type-Only Imports and Export syntax to avoid potential problems like type-only imports being incorrectly bundled:
TypeScript Compiler Options
Vite respects some of the options intsconfig.json and sets the corresponding esbuild options. For each file, Vite uses the tsconfig.json in the closest parent directory.
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
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.
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+. 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.
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 addvite/client to compilerOptions.types inside tsconfig.json:
tsconfig.json
Note that if
compilerOptions.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.vite/client provides the following type shims:
- Asset imports (e.g. importing an
.svgfile) - Types for the Vite-injected constants on
import.meta.env - Types for the HMR API on
import.meta.hot
HTML
HTML files stand front-and-center of a Vite project, serving as the entry points for your application, making it simple to build single-page and multi-page applications. Any HTML files in your project root can be directly accessed by its respective directory path:<root>/index.html→http://localhost:5173/<root>/about.html→http://localhost:5173/about.html<root>/blog/index.html→http://localhost:5173/blog/index.html
<script type="module" src> and <link href> are processed and bundled as part of the app. The full list of supported elements are:
<audio src><embed src><img src>and<img srcset><image href>and<image xlink:href><input src><link href>and<link imagesrcset><object data><script type="module" src><source src>and<source srcset><track src><use href>and<use xlink:href><video src>and<video poster><meta content>(with specific attributes)
CSS
Importing.css files will inject its content to the page via a <style> tag with HMR support.
@import Inlining and Rebasing
Vite is pre-configured to support CSS @import inlining via postcss-import. Vite aliases are also respected for CSS @import. In addition, all CSS url() references, even if the imported files are in different directories, are always automatically rebased to ensure correctness.
@import aliases and URL rebasing are also supported for Sass and Less files.
PostCSS
If the project contains valid PostCSS config (any format supported by postcss-load-config, e.g.postcss.config.js), it will be automatically applied to all imported CSS.
CSS minification will run after PostCSS and will use the
build.cssTarget option.CSS Modules
Any CSS file ending with.module.css is considered a CSS modules file. Importing such a file will return the corresponding module object:
css.modules option.
If css.modules.localsConvention is set to enable camelCase locals (e.g. localsConvention: 'camelCaseOnly'), you can also use named imports:
CSS Pre-processors
Because Vite targets modern browsers only, it is recommended to use native CSS variables with PostCSS plugins that implement CSSWG drafts (e.g. postcss-nesting) and author plain, future-standards-compliant CSS. That said, Vite does provide built-in support for.scss, .sass, .less, .styl and .stylus files. There is no need to install Vite-specific plugins for them, but the corresponding pre-processor itself must be installed:
If using Vue single file components, this also automatically enables
<style lang="sass"> et al.JSON
JSON files can be directly imported - named imports are also supported:Glob Import
Vite supports importing multiple modules from the file system via the specialimport.meta.glob function:
modules object to access the corresponding modules:
{ eager: true } as the second argument:
Glob Import Features
- Multiple Patterns
- Negative Patterns
- Named Imports
The first argument can be an array of globs:
WebAssembly
Pre-compiled.wasm files can be imported with ?init. The default export will be an initialization function that returns a Promise of the WebAssembly.Instance:
WebAssembly.instantiate as its second argument:
In the production build,
.wasm files smaller than assetInlineLimit will be inlined as base64 strings. Otherwise, they will be treated as a static asset and fetched on-demand.Web Workers
Import with Constructors
A web worker script can be imported usingnew Worker() and new SharedWorker(). Compared to the worker suffixes, this syntax leans closer to the standards and is the recommended way to create workers.
The worker detection will only work if the
new URL() constructor is used directly inside the new Worker() declaration. Additionally, all options parameters must be static values (i.e. string literals).Import with Query Suffixes
A web worker script can be directly imported by appending?worker or ?sharedworker to the import request. The default export will be a custom worker constructor:
The worker script can also use ESM
import statements instead of importScripts(). Note: During development this relies on browser native support, but for the production build it is compiled away.inline query:
url query:
Content Security Policy (CSP)
To deploy CSP, certain directives or configs must be set due to Vite’s internals.'nonce-{RANDOM}'
When html.cspNonce is set, Vite adds a nonce attribute with the specified value to any <script> and <style> tags, as well as <link> tags for stylesheets and module preloading. Additionally, when this option is set, Vite will inject a meta tag (<meta property="csp-nonce" nonce="PLACEHOLDER" />).
The nonce value of a meta tag with property="csp-nonce" will be used by Vite whenever necessary during both dev and after build.
data: URIs
By default, during build, Vite inlines small assets as data URIs. Allowing data: for related directives (e.g. img-src, font-src), or, disabling it by setting build.assetsInlineLimit: 0 is necessary.
Build Optimizations
Features listed below are automatically applied as part of the build process and there is no need for explicit configuration unless you want to disable them.
CSS Code Splitting
Vite automatically extracts the CSS used by modules in an async chunk and generates a separate file for it. The CSS file is automatically loaded via a<link> tag when the associated async chunk is loaded, and the async chunk is guaranteed to only be evaluated after the CSS is loaded to avoid FOUC.
If you’d rather have all the CSS extracted into a single file, you can disable CSS code splitting by setting build.cssCodeSplit to false.
Preload Directives Generation
Vite automatically generates<link rel="modulepreload"> directives for entry chunks and their direct imports in the built HTML.
Async Chunk Loading Optimization
In real world applications, Rollup often generates “common” chunks - code that is shared between two or more other chunks. Combined with dynamic imports, it is quite common to have the following scenario:A is imported, the browser will have to request and parse A before it can figure out that it also needs the common chunk C. This results in an extra network roundtrip.
Vite automatically rewrites code-split dynamic import calls with a preload step so that when A is requested, C is fetched in parallel: