Why use Vite
- Es Module is supported in browser. Key changes are as follows:
Therefore, in a development environment, it is no longer necessary to package all the resources used before running the project. Instead, it loads resources as it runs. As a result, it is faster than a build (Bundler) development server (Webpack).
Initialize the project
# npm 6.x
npm init @vitejs/app my-vue-app --template vue
# npm 7+, requires extra double dashes: NPM init @vitejs/app my-vue-app -- --template vue # yarn yarn create @vitejs/app my-vue-app --template vueCopy the code
Supported template presets include:
- vanilla
- vue
- vue-ts
- react
- react-ts
- preact
- preact-ts
- lit-element
- lit-element-ts
- svelte
- svelte-ts
Three, vite framework process
Vite has a total of four command-line commands
1. Default command — Develop (serve)
CreateServer (main running process for creating a server)
There are four main processes for vite to start the server:
- Started file listener and websocket server to start hot update
- The ViteDevServer object is created
- Internal middleware mount
- Overridden httpServer’s Listen function to perform buildStart plugin hooks and pre-build optimizations before calling LISTEN
async function createServer(
inlineConfig: InlineConfig = {}
) :Promise<ViteDevServer> {
// 1
// 2. Define ViteDevServer
const server: ViteDevServer = {}
// 3. An example of the use of internal middleware is as follows
// main transform middleware
middlewares.use(transformMiddleware(server))
Container. BuildStart ({}) and runOptimize ({})
if(! middlewareMode && httpServer) {// overwrite listen to run optimizer before server start
const listen = httpServer.listen.bind(httpServer)
httpServer.listen = (async(port: number, ... args: any[]) => {try {
await container.buildStart({})
await runOptimize()
} catch (e) {
httpServer.emit('error', e)
return
}
returnlisten(port, ... args) })as any
httpServer.once('listening'.() = > {
// update actual port since this may be different from initial value
serverConfig.port = (httpServer.address() as AddressInfo).port
})
} else {
await runOptimize()
}
return server
}
Copy the code
InlineConfig (User configuration parameter parsing)
The config configuration entered by the user on the command line and the configuration in vite.config.js
interface InlineConfig extendsUserConfig { configFile? : string |false} interface UserConfig { root? : string base? : string publicDir? : string mode? : string define? : Record<string, any> plugins? : (PluginOption | PluginOption[])[] resolve? : ResolveOptions & { alias? : AliasOptions } css? : CSSOptions json? : JsonOptions esbuild? : ESBuildOptions |falseassetsInclude? : string |RegExp | (string | RegExp)[] server? : ServerOptions build? : BuildOptions optimizeDeps? : DepOptimizationOptions ssr? : SSROptions logLevel? : LogLevel clearScreen? : boolean alias? : AliasOptions dedupe? : string[] }Copy the code
ViteDevServer (server parameters parsing)
export interface ViteDevServer {
/** * Parsed vite configuration */
config: ResolvedConfig
/** * a connect application instance. * - Can be used to add custom middleware to development servers. * - can also be used as a custom HTTP server handler function * or as middleware for any Connect style Node.js framework ** https://github.com/senchalabs/connect#use-middleware */
middlewares: Connect.Server
/ * * *@deprecated use `server.middlewares` instead
*/
app: Connect.Server
/** * Native Node HTTP server instance * in middleware mode is null */
httpServer: http.Server | null
/**
* chokidar watcher 实例
* https://github.com/paulmillr/chokidar#api
*/
watcher: FSWatcher
/** * Web socket server with 'send(payload)' method */
ws: WebSocketServer
/** * Rollup plugin container, which can run plugin hook */ for a given file
pluginContainer: PluginContainer
/** * module diagram: Track import relationships, URL-to-file mapping, and hot update status ** /
moduleGraph: ModuleGraph
/** * Programmatically resolve, load and transform a URL and get the result * without going through the http request pipeline. */transformRequest( url: string, options? : TransformOptions ):Promise<TransformResult | null>
/** * Apply vite built-in HTML transforms and any plugin HTML transforms. */
transformIndexHtml(url: string, html: string): Promise<string>
/** * Util for transforming a file with esbuild. * Can be useful for certain plugins. */
transformWithEsbuild(
code: string,
filename: string, options? : EsbuildTransformOptions, inMap? : object ):Promise<ESBuildTransformResult>
/** * Load a given URL as an instantiated module for SSR. */
ssrLoadModule(url: string): Promise<Record<string, any>>
/** * Fix ssr error stacktrace */
ssrFixStacktrace(e: Error) :void
/** * Start the server. */listen(port? : number, isRestart? : boolean):Promise<ViteDevServer>
/** * Stop the server. */
close(): Promise<void>
/ * * *@internal* /
_optimizeDepsMetadata: DepOptimizationMetadata | null
/**
* Deps that are externalized
* @internal* /
_ssrExternals: string[] | null
/ * * *@internal* /
_globImporters: Record<
string,
{
base: string
pattern: string
module: ModuleNode
}
>
/ * * *@internal* /
_isRunningOptimizer: boolean
/ * * *@internal* /
_registerMissingImport: ((id: string, resolved: string) = > void) | null
/ * * *@internal* /
_pendingReload: Promise<void> | null
}
Copy the code
2. Build command — Build
Production builds are used with the rollup method:
3. Optimize commands — Optimize
Prebuild is not done every time, and only when node_modules dependencies or associated user configurations change is scanImports built when the server is started. Otherwise, you have to execute the prebuild command line yourself to enforce the prebuild. The pre-build process is as follows:
The middleware
Vite middleware mainly relies on Connect (Connect is an Extensible HTTP Server framework for node using “plugins” known as Middleware.) extends middleware for httpServer. Among them, the middleware used are: IndexHtmlMiddleware, transformMiddleware, baseMiddleware, serveRawFsMiddleware, servePublicMiddleware, ServeStaticMiddleware, proxyMiddleware, decodeURIMiddleware, errorMiddleware, timeMiddleware.
Among them, the core middleware includes:
- IndexHtmlMiddleware: Processes index.html
- TransformMiddleware: Matched to
.map
./\.((j|t)sx? |mjs|vue)($|\?) /
./ (\? |&)import(? : & | $) /
.\\.(css|less|sass|scss|styl|stylus|postcss)($|\\?)
./ \? html-proxy&index=(\d+)\.js$/
File, which is processed by the vite built-in plug-in or external reference plug-in
Build optimization
Prebuilt dependencies
why
Raw ES imports do not support the following raw module imports
import { someMethod } from 'my-dep'
Copy the code
Vite will detect such raw module imports in all source files of the service and do the following:
- Third party dependencies are pre-built and stored in /node_modules/.vite/
2. NPM dependency analysis
Vite plug-in
The plugin hooks
The Vite plugin inherits the rollup plugin and extends its own unique functionality.
- General hook
- Server startup: options, buildStart
- On each incoming module request: resolveId, Load, Transform
- Server shutdown: buildEnd, closeBundle
- Vite unique hooks
- Before the configuration is resolved, modify the configuration: config
- After resolving the configuration: configResolved
- Before the internal middleware is installed: configureServer is injected into the back-end middleware
- Convert index.html: transformIndexHtml
- Perform custom hot update processing: handleHotUpdate
- Build-time hooks
- Get the build parameter: outputOptions
- renderChunk
- GenerateBunddle file: generateBunddle
Plug-in type
Vite plug-ins can be divided into user-defined plug-ins and built-in plug-ins.
Plug-ins configured by users can be divided into three categories according to the order of plug-in execution:
- prePlugins
- normalPlugins
- postPlugins
Plugin specific execution order, see vite source code as follows:
export async function resolvePlugins(config: ResolvedConfig, prePlugins: Plugin[], normalPlugins: Plugin[], postPlugins: Plugin[]) :Promise<Plugin[] >{
const isBuild = config.command === 'build'
const buildPlugins = isBuild
? (await import('.. /build')).resolveBuildPlugins(config)
: { pre: [].post: []}return [
isBuild ? null : preAliasPlugin(),
aliasPlugin({ entries: config.resolve.alias }), ... prePlugins, config.build.polyfillDynamicImport ? dynamicImportPolyfillPlugin(config) :null, resolvePlugin({ ... config.resolve,root: config.root,
isProduction: config.isProduction,
isBuild,
asSrc: true}), htmlInlineScriptProxyPlugin(), cssPlugin(config), config.esbuild ! = =false ? esbuildPlugin(config.esbuild) : null,
jsonPlugin(
{
namedExports: true. config.json }, isBuild ), wasmPlugin(config), webWorkerPlugin(config), assetPlugin(config), ... normalPlugins, definePlugin(config), cssPostPlugin(config), ... buildPlugins.pre, ... postPlugins, ... buildPlugins.post,// internal server-only plugins are always applied after everything else. (isBuild ? [] : [clientInjectionsPlugin(config), importAnalysisPlugin(config)]) ].filter(Boolean) as Plugin[]
}
Copy the code
All vite plug-ins are executed in the following order:
- alias
- PrePlugins (with
enforce: 'pre'
的User plug-in) - Build. PolyfillDynamicImport dynamicImportPolyfillPlugin 】 (whether the introduction of dynamic polyfill plug-in)
- ResolvePlugin (File path conversion)
- htmlInlineScriptProxyPlugin
- cssPlugin
- [config.esbuild!== false] esbuildPlugin
- jsonPlugin
- wasmPlugin
- webWorkerPlugin
- assetPlugin
- NormalPlugins (no
enforce
The value of theUser plug-in) - definePlugin
- cssPostPlugin
- Buildplugins. pre(plugin for Vite builds)
- PostPlugins (with
enforce: 'post'
的User plug-in) - Buildplugins.post (plugin for Vite builds)
- Clientinjsplugin (built-in Server-only plugins)
- ImportAnalysisPlugin (built-in server-only plugins for parsing import content in code)
Four, Esbuild
An extremely fast javascript bundler
Vite transforms JSX and TS based on ESBuild, and runOptimize (pre-built dependencies)
ESbuild is written in go and builds 10-100 times faster than js written packaging tools
ESbuild is astonishingly fast and is already a great tool for building libraries, but some important features for building applications are still under development, especially code splitting and CSS handling. Therefore, vite builds projects using rollup, but we can’t rule out using esBuild in the future.
V. WebAPCK project vite transformation
- Does not support the require
The following is the message from Yyx teacher in vite’s issue
2. Corresponding replacement plug-ins or methods should be found for webpack plug-ins, htML-webpack-plugin and expose-loader used in previous projects. Also, webpack’s require.ensure method will be written as a dynamic import.
- Vite subcontracting problem
Mainly divided into the following kinds of packages:
(1) Vendor package (2) CSS file (3) index entry file (4) index.html (5) manifest.json (6) DynamicImport module
- Vendor packet segmentation: outputOptions. ManualChunks:
(id, { getModuleInfo }) => {
if (
id.includes('node_modules') &&! isCSSRequest(id) && ! hasDynamicImporter(id, getModuleInfo, cache) ) {return 'vendor'}}Copy the code
- CSS, manifest.json, index.html file, rollup
generateBundle
Hook, callthis.emitFile
Code splitting with rollup is a relatively new feature (it was fully implemented after the release of 2.0.0 in March 2020)
- ongenerate: use
generateBundle
instead - onwrite: use
writeBundle
instead - transformBundle: use
renderChunk
instead - transformChunk: use
renderChunk
instead
Segmentation, code examples:
generateBundle() {
this.emitFile({
type: 'asset'.fileName: 'index.html'.source: fs.readFileSync(
path.resolve(__dirname, 'index.dist.html'),
'utf-8')})}Copy the code
- File name extension problem introduced
For suffixes like. Vue, it is recommended to write the full name rather than omit the suffix.
- Environment variable problem
In vite change to:
- Import.meta.env. PROD: Boolean Specifies whether the application is running in production
- Import.meta.env. DEV: Boolean Whether the application is running in a development environment (always the opposite of import.meta.env.prod)