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