Vite
- Vite is a lighter, faster Web development application for modern browsers
- Implementation based on ECMAScript standard Native Module System (ESM)
Vite project dependencies
- Vite
- @vue/compiler-sfc
The characteristics of Vite
- Quick cold start
- Module hot update
- According to the need to compile
- Out of the box
vite serve
vue-cli-service serve
Vite only compiles the corresponding module when the file is requested
- Vite only compiles files when requested, and file changes only compile the current file
- Webpack HMR will be rebuilt using this file as an entry, and all involved dependencies will be reloaded
vite build
- A Rollup packaging
- Dynamic import
Reasons for using WebPack
- The browser environment does not support modularity
- Fragmented module files generate a large number of HTTP requests (http2 can be addressed by reusing links)
Out of the box
- Typescript built-in support
- Less/SASS/Stylus/PostCSS built-in support requires separate installation dependencies
- jsx
- Web Assembly
Vite’s core features
Vite starts with the current project as the root of the static server, intercepts some of the server’s file requests, compiles when it encounters modules that the browser doesn’t recognize, and implements HMR via WebSocked
Implementation principle of Vite
Static Web server
npm init -y
Copy the code
Set name to vite-cli in package.json file to vite-cli
Start with a Web server
#! /usr/bin/env node
const Koa = require('koa')
const send = require('koa-send')
const app = new Koa()
app.use(async (ctx,next) => {
await send(ctx, ctx.path, {
root: process.cwd(),
index: 'index.html'
})
await next()
})
app.listen(3000.() = > {
console.log('serve listen 3000')})Copy the code
Install the scaffolding tool locally using NPM link or YARN Link
npm link
# start
vite-cli
Copy the code
Handling javascript requests
// stream converts to a string
function streamToString(text) {
return new Promise((resolve, reject) = > {
let chunks = []
text.on('data'.chunk= > chunks.push(chunk))
text.on('error', reject)
text.on('end'.() = > resolve(Buffer.concat(chunks).toString('utf-8')))
})
}
app.use(async (ctx, next) => {
if (ctx.type === 'application/javascript') {
// ctx.body is a stream type that needs to be converted to a string
ctx.body = await streamToString(ctx.body)
}
await next()
})
Copy the code
Loading a third-party Module
You first need to change the third-party package path imported from the JavaScript code above to ‘/@modules/’, and then deal with the third-party module path
// Handling third-party package paths should come first
app.use(async (ctx, next) => {
if (ctx.path.startsWith('/@modules/')) {
let moduleName = ctx.path.substr(10)
let modulePath = path.resolve(process.cwd(), 'node_modules', moduleName)
let pkg = require(path.resolve(modulePath, 'package.json'))
ctx.path = path.join('/node_modules', moduleName, pkg.module)
}
await next()
})
...
app.use(async (ctx, next) => {
if (ctx.type === 'application/javascript') {
// ctx.body is a stream
let text = await streamToString(ctx.body)
// Change the path of the third-party module package
ctx.body = text.replace(/(from\s+['"])(? ! .\/)/g.'$1/@modules/')}await next()
})
Copy the code
Compile single-file components
First you need to modify the vUE file format to the following format
import {render as __render} from "/aa.vue? type=template"
__script.render = __render
export default __script
Copy the code
The second request for the Vue file outputs the compiled code
// Compile the file
const build = async (ctx, next) => {
// Compile the single-file component
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 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') {
let template = compilerSfc.compileTemplate({
source: descriptor.template.content,
filename: descriptor.filename,
id: ctx.path
})
code = template.code
}
ctx.body = stringToStream(code)
ctx.type = 'application/javascript'
}
await next()
}
Copy the code
To handle the imported CSS file, replace the imported CSS file path in the JS code with xxx@import
app.use(async (ctx, next) => {
if (ctx.type === 'application/javascript') {
// ctx.body is a stream
let text = await streamToString(ctx.body)
// Change the path of the third-party module package
ctx.body = text.replace(/(from\s+['"])(? ! [.\/])/g.'$1/@modules/')
.replace(/process\.env\.NODE_ENV/g.'"develop"')
// css
.replace(/(import\s+['"][\w\.\/]+\.css)(['"])/g.'$1? import$2')}await next()
})
Copy the code
Then add the CSS code to the HTML style
.if (ctx.path.endsWith('.css')) {
const css = await streamToString(ctx.body)
let code = `
import {updateStyle} from '/build/util/style.js'
const css = The ${JSON.stringify(css)}
updateStyle(css)
export default css
`
ctx.body = stringToStream(code)
ctx.type = 'application/javascript'}...export function updateStyle(content,id){
const style = document.createElement('style')
style.setAttribute('type'.'text/css')
style.innerHTML = content
document.head.appendChild(style)
}
Copy the code
The complete code
Entrance to the file
#! /usr/bin/env node
const Koa = require('koa')
const send = require('koa-send')
const path = require('path')
const {
static,
npmHandler,
build
} = require('./middlewares/index.js')
const {
streamToString
} = require('./util')
const app = new Koa()
// Handle third-party dependencies
app.use(npmHandler)
// Process static resources
app.use(static)
app.use(build)
// Modify third-party module dependencies
app.use(async (ctx, next) => {
if (ctx.type === 'application/javascript') {
// ctx.body is a stream
let text = await streamToString(ctx.body)
// Change the path of the third-party module package
ctx.body = text.replace(/(from\s+['"])(? ! [.\/])/g.'$1/@modules/')
.replace(/process\.env\.NODE_ENV/g.'"develop"')
.replace(/(import\s+['"][\w\.\/]+\.css)(['"])/g.'$1? import$2')}await next()
})
app.listen(3000)
console.log('server listen http://localhost:3000')
Copy the code
middlewares
const send = require('koa-send')
const path = require('path')
const compilerSfc = require('@vue/compiler-sfc')
const {
streamToString,
stringToStream
} = require('.. /util')
// Static resources
const static = async (ctx, next) => {
await send(ctx, ctx.path, {
root: process.cwd(),
index: 'index.html'
})
await next()
}
// Process third-party dependencies
const npmHandler = async (ctx, next) => {
if (ctx.path.startsWith('/@modules/')) {
let moduleName = ctx.path.substr(10)
let modulePath = path.resolve(process.cwd(), 'node_modules', moduleName)
let pkg = require(path.resolve(modulePath, 'package.json'))
ctx.path = path.join('/node_modules', moduleName, pkg.module)
}
await next()
}
// Compile the file
const build = async (ctx, next) => {
// Compile the single-file component
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 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') {
let template = compilerSfc.compileTemplate({
source: descriptor.template.content,
filename: descriptor.filename,
id: ctx.path
})
code = template.code
console.log(descriptor.filename)
}
ctx.body = stringToStream(code)
ctx.type = 'application/javascript'
} else if (ctx.path.endsWith('.css')) {
const css = await streamToString(ctx.body)
let code = `
import {updateStyle} from '/build/util/style.js'
const css = The ${JSON.stringify(css)}
updateStyle(css)
export default css
`
ctx.body = stringToStream(code)
ctx.type = 'application/javascript'
}
await next()
}
module.exports = {
static,
npmHandler,
build
}
Copy the code
utils
const {
Readable
} = require('stream')
// stream is converted to string
function streamToString(text) {
return new Promise((resolve, reject) = > {
let chunks = []
text.on('data'.chunk= > chunks.push(chunk))
text.on('error', reject)
text.on('end'.() = > resolve(Buffer.concat(chunks).toString('utf-8')))})}function stringToStream(text) {
const stream = new Readable()
stream.push(text)
stream.push(null)
return stream
}
module.exports = {
streamToString,
stringToStream
}
Copy the code
style
export function updateStyle(content,id){
const style = document.createElement('style')
style.setAttribute('type'.'text/css')
style.innerHTML = content
document.head.appendChild(style)
}
Copy the code