vite introduction:
vite is a lighter and faster Web tool for modern browsers based on es modules
Solve the problems of too long cold start time of devServer and slow response speed of HMR hot update in webpack development stage;
1. Quick cold start (comparison vue-cli):
1. A project created with vite is a common v3 application, which has fewer configuration files and dependencies than a project created with Vue cli;
Vite project dependencies: vite, @ Vue / compiler SFC
vite serve; vite build
2. vite is to directly start the server, and then start compiling the file and pass it to the server after the request (instant compilation will be faster on demand, and there is no need to store it in the development stage);
3. Vue cli packages the bundle storage first, and then sends the bundle to the server for resolution. Therefore, the process of packaging the bundle is affected by the project size and dependency;
2. Module hot update HMR:
vite HMR: compile the currently modified file immediately
webpack HMR: it will automatically rewrite the build with this file as the entry, and all the dependencies involved will be loaded again
3. Compile build on demand
vite build:
In the production environment, rollup is used for packaging, or it will be packaged and compiled in advance;
Dynamic import, which only supports modern browsers, can be assisted by Polyfill;
Packaging reason using webpack (packaging reason):
The browser environment does not support modularization; -- Modern browser support for es module
Scattered module files generate a large number of http requests; - http2 multiplexing
4. Out of the box:
TS (built-in), less / sass / style / postcss - built-in needs to be installed separately, JSX, Web Assembly
vite feature summary:
Quick cold start, module hot update, on-demand compilation, out of the box (avoid loader and plugin configuration)
vite principle
Core function analysis: static Web server, compiling single file components (intercepting and processing modules not recognized by the browser), HMR
1. Static server
Based on koa and koa send
2. The processing path of the processing module, such as from 'vue' - > from '/ @ modules/vue.js'
ctx.type === 'application/javascript'
contents.replace(/(from\s+['"])(?![\.\/])/g, '$1/@modules/') <!-- /?!/ Indicates a mismatch $1 Group matched content -->
3. Load third-party modules, such as / @ modules/vue.js
Verify the route and adjust ctx.path to the actual address:
const pkg = require(pkgPath) ctx.path = path.join('/node_modules', moduleName, pkg.module) // pkg.module is the value of the pkg package.json entry file
4. Processing sheet file module
The single file component is compiled into an option object and returned to the browser;
Compile the template into render function (ctx.requery.type = = 'template')
compilerSFC = require('@vue/compiler-sfc') const templateRender = compilerSFC.compileTemplate({ source: descriptor.template.content }) code = templateRender.code
process - /shared cannot be found in the browser; Process.env.xx - > corresponding value in the development environment; Such as node_ ENV -> development
vite preliminary implementation:
#!/usr/bin/env node const path = require('path') const { Readable } = require('stream') const Koa = require('koa') const send = require('koa-send') const compilerSFC = require('@vue/compiler-sfc') const app = new Koa() const streamToString = stream => new Promise((resolve, reject) => { const chunks = [] stream.on('data', chunk => chunks.push(chunk)) stream.on('end', () => resolve(Buffer.concat(chunks).toString('utf-8'))) stream.on('error', reject) }) const stringToStream = text => { const stream = new Readable() stream.push(text) stream.push(null) // The null identity stream has been written return stream } // 3. Load the third-party module app.use(async (ctx, next) => { // ctx.path --> /@modules/vue if (ctx.path.startsWith('/@modules/')) { const moduleName = ctx.path.substr(10) const pkgPath = path.join(process.cwd(), 'node_modules', moduleName, 'package.json') const pkg = require(pkgPath) ctx.path = path.join('/node_modules', moduleName, pkg.module) // pkg.module is the value of the pkg package.json entry file, and it is also a path; For example, vue corresponds to "module": "dist/vue.runtime.esm-bundler.js" } await next() }) // 1. Static file server app.use(async (ctx, next) => { await send(ctx, ctx.path, { root: process.cwd(), index: 'index.html' }) await next() }) // 4. Processing sheet file component app.use(async (ctx, next) => { if (ctx.path.endsWith('.vue')) { const contents = await streamToString(ctx.body) const { descriptor } = compilerSFC.parse(contents) let code if (!ctx.query.type) { code = descriptor.script.content // console.log(code) code = code.replace(/export\s+default\s+/g, 'const __script = ') code += ` import { render as __render } from "${ctx.path}?type=template" __script.render = __render export default __script ` } else if (ctx.query.type === 'template') { const templateRender = compilerSFC.compileTemplate({ source: descriptor.template.content }) // Templates in components code = templateRender.code // code is the render function } ctx.type = 'application/javascript' ctx.body = stringToStream(code) } await next() }) // 2. Modify the path of the third-party module app.use(async (ctx, next) => { if (ctx.type === 'application/javascript') { const contents = await streamToString(ctx.body) // import vue from 'vue' // import App from './App.vue' ctx.body = contents .replace(/(from\s+['"])(?![\.\/])/g, '$1/@modules/') .replace(/process\.env\.NODE_ENV/g, '"development"') } }) app.listen(3000) console.log('Server running @ http://localhost:3000')