Vite – a new, faster Web development tool.

Two features:

  1. Quick cold start

  2. Instant module hot updates (retaining application state lost when the page is fully reloaded, only updating changes, styling faster)

  3. True on-demand compilation

3 Construction Project:

$ yarn create vite-app <project-name>
$ cd <project-name>
$ yarn
$ yarn dev
Copy the code

4 Implementation mechanism:

Vite uses KOA as a Web server, uses CLmLoader to create a watcher that listens for file changes, and implements a plug-in mechanism. Inject a context object into each plugin by combining koA-app with Watcher and other necessary tools.

Context component structure:

The plugin takes these components from the context in turn. Some plugins add middleware to koA instances, and some use Watcher to listen for changes to files. At the same time, each plug-in handles different things, so responsibilities are assigned more clearly.

5 the plugin:

  • User-injected plugins — custom plugins

  • HmrPlugin — Handles HMR

  • HtmlRewritePlugin — Rewrite script content within HTML

  • ModuleRewritePlugin – Overriding import imports in modules

  • ModuleResolvePlugin — Gets the content of the module

  • VuePlugin — Handles vUE single file components

  • EsbuildPlugin — Use esBuild to process resources

  • AssetPathPlugin – Handles static resources

  • ServeStaticPlugin – Manages static resources

  • CssPlugin — Handles references to CSS /less/sass etc

  • .

A simple plugin for intercepting JSON files:


interface ServerPluginContext { 
    root: string 
    app: Koa 
    server: Server 
    watcher: HMRWatcher 
    resolver: InternalResolver 
    config: ServerConfig 
} 

typeServerPlugin = (CTX :ServerPluginContext) =>void; 

const JsonInterceptPlugin:ServerPlugin = ({app}) = >{ 
    app.use(async (ctx, next) => { 
        await next() 
        if (ctx.path.endsWith('.json') && ctx.body) { 
            ctx.type = 'js' 
            ctx.body = `export default json`}})}Copy the code

6 Operating dependency Principle

Vite improves development server startup times by initially separating application modules into dependent and source modules.

  • The dependencies are mostly pure JavaScript and do not change at development time. Some large dependencies, such as component libraries with hundreds of modules, are also expensive to handle. Dependencies are also often split into a large number of smaller modules in some way (such as ESM or CommonJS). Vite will pre-build dependencies using esBuild. Esbuild is written using Go and is 10-100 times faster than a prepacker-built dependency written in JavaScript.

  • The source code usually contains files that are not directly JavaScript that need to be transformed (such as JSX, CSS, or Vue/Svelte components) and often edited. Also, not all source code needs to be loaded at the same time. (for example, code modules based on route splitting). Vite serves source code in a native ESM way. This essentially lets the browser take over part of the packaging: Vite simply transforms the source code when the browser requests it and makes it available on demand. Code that is dynamically imported according to the situation is only processed if it is actually used on the current screen.

6.1 Dependency on ES Module

To understand how vite works, you should first know what ES module is, see: JavaScript modules module – MDN.

Browser support is as follows: all major browsers (except Internet Explorer 11) already support it

Its biggest characteristic is used in the browser sideexport importImport and export modules in the script tagtype="module"And then use the module content.

6.2 the sample:

 // module SciPRt allows native support modules to be run directly in the browser
<script type="module">
    // index.js can be exported as a module, or it can continue to use import to load other dependencies
    // When an import dependency is encountered, HTTP requests are made directly to the corresponding module file.
    import { fn } from  ./index.js;
    fn();
</script>
Copy the code

HTTTP server to host index.js. In index.js, we use export to export fn function. The definition of fn is available in the script above.

export function fn() { 
    alert('hello world');
};
Copy the code

7 Functions in Vite

Open the running Vite project and visit the view-source to find this code in the HTML:

<script type="module">
    import { createApp } from '/@modules/vue'
    import App from '/App.vue'
    createApp(App).mount('#app')
</script>
Copy the code

From this code, we can get the following information:

  • Get the createApp method from http://localhost:3000/@modules/vue

  • Obtained from the http://localhost:3000/App.vue application portal

  • Create the application and mount the node using createApp

CreateApp is the API for vue3.X, which is used to create vue applications. Vite uses ES Module to create vue applications directly in the browser

  1. Remove packing step

  2. Implement load on demand

7.1 Remove the packing step

The concept of packaging is that developers use a packaging tool to bundle application modules together and read the module’s code with certain rules — for use in browsers that do not support modularity.

To load modules in the browser, the packaging tool uses glue code to assemble modules, such as Webpack using map to store module ids and paths, and the __webpack_require__ method to retrieve module exports.

By taking advantage of the browser’s native support for modular imports, Vite eliminates the need to assemble modules, so you don’t need to generate bundles, so you can skip the packaging step.

7.2 On-demand packaging

As mentioned earlier, packaging tools such as WebPack pack modules into bundles in advance, but the packaging process is static — regardless of whether a module’s code is executed, the module is packed into the bundle. The disadvantage of this is that as the project gets bigger, the bundle gets bigger.

In order to reduce the bundle size, developers load modules asynchronously by dynamically importing import(), or remove unreferenced modules as much as they can using tree shaking. However, these methods are not as elegant as Vite. Vite can introduce a module dynamically (with import()) only when it is needed, without pre-packaging.

8 How does vite process the ESM

Since Vite uses ESM to use modules in the browser, how exactly does this step work?

As mentioned above, to use ES Modules in a browser is to use HTTP requests to get modules, so Vite must provide a Web server to proxy these modules. Koa is responsible for this. Vite returns the contents of the resource to the browser by hijacking the requested path, but vite does something special for module imports.

8.1 What is @modules?

By comparing the index.html file in the project with the HTML source file in the development environment, it is found that the content in the script tag has changed

<script type="module">
    import { createApp } from 'vue'
    import App from '/App.vue'
    createApp(App).mount('#app')
</script>
Copy the code

Turned out to be

<script type="module">
    import { createApp } from '/@modules/vue'
    import App from '/App.vue'
    createApp(App).mount('#app')
</script>
Copy the code
  1. Get the request body in the KOA middleware

  2. Use es-module-lexer to parse the ast resource to get the contents of the import

  3. Check whether the imported resource is an absolute path and consider it as an NPM module

  4. Return the processed resource path: “vue” => “/@modules/vue”

This part of the code in the serverPluginModuleRewrite plugin,

8.2 Why @modules?

The esM in the browser cannot retrieve the contents of the imported module if we write the following code in the module:

import vue from 'vue'
Copy the code

Since the vue module is installed in node_modules, the previous use of Webpack, webpack encounters the above code, will help us do the following things:

  • Get the contents of this code

  • Parsed into AST

  • Walk through the AST to get the package name in the import statement

  • Use enhanced-resolve to fetch the actual address of the package for packaging,

But the ESM in the browser doesn’t have direct access to node_modules under the project, so Vite handles all imports, overwriting them with a prefix with @modules.

On the other hand, this is a very clever way to rewrite all the file paths in the same plugin, so that if you add more logic, it won’t affect other plugins. All other plugins get resource paths in @modules. For example, a later configuration might add aliases: just like webpack aliases: local files in a project can be configured as references to absolute paths.

8.3 How do I Return the Module Content

In the next piece of KOa Middleware, match a resource with @modules on its path with are, and take the package export back to the browser via require(‘ XXX ‘).

In the past, packaging tools like WebPack were used to assemble modules together into bundles and allow packages that use different module specifications to refer to each other, such as:

  • ES Module (ESM) imports CJS

  • CommonJS (CJS) imports esM

  • Dynamic Import Imports the ESM

  • Dynamic Import imports CJS

Pit on es module can be reading this (zhuanlan.zhihu.com/p/40733281).

When Vite was originally designed for Vue 3.x, the Vue ESM package was treated specially, such as: @vue/runtime-dom = @vue/runtime-dom = @vue/runtime-dom = @vue/runtime-dom = @vue/runtime-dom = @vue/runtime-dom Do require(‘@vue/runtime-dom/dist/ Runtime-dom.esm-bundler.js’) so that vite can get the Vue package that complies with the ESM module standard.

At present, most modules in the community are not set to export ESM by default, but export CJS package. Since Vue3.0 requires extra processing to get ESM package content, do other daily use NPM package also need to support? The answer is yes, currently using LoDash directly in vite projects still generates errors.

However, in the latest update, Vite has added itoptimizeThis command was specifically developed to address module reference pits, such as using Lodash in Vitevite.config.js(Vite configuration file), configureoptimizeDepsIn object,includeAdd LoDash to array.

// vite.config.js
module.exports = {
  optimizeDeps: {
    include: ["lodash"]}}Copy the code

When runOptimize is executed, vite will use rollup to recompile the lodash package, and put the new package to the.vite_opt_cache under node_modules. Depoptimizer.ts (); / / Depoptimizer.ts (); / / Depoptimizer.ts (); / / Depoptimizer.ts (); / / Depoptimizer.ts ();

In depoptimizer. ts, vite only handles packages declared in dependencies in package.json, so it cannot be used in a project

import pick from 'lodash/pick'
Copy the code

Use the pick method alone instead of using

import lodash from 'lodash'

lodash.pick()
Copy the code

This may have an impact on the volume of the bundle when some packages are used in production.

The content of the return module code in: serverPluginModuleResolve. Ts this plugin.

0 Vite hot update implementation

Vite/HMR is the key for vite to handle hot updates. ServerPluginHmr Plugin determines that path is equal to vite/ HMR:

app.use(async (ctx, next) => {
  if (ctx.path === '/vite/hmr') {
      ctx.type = 'js'
      ctx.status = 200
      ctx.body = hmrClient
  }
 }
Copy the code

HmrClient is a vite hot update client code, which needs to be executed in the browser. Here is the general hot update implementation, hot update generally needs four parts:

  • First you need the Web framework to support rerender/ Reload for the module

  • Listen for file changes through Watcher

  • Compile resources through the server side and push new module content to the client.

  • The client receives the new module contents, rerender/reload

Vite also has the same four parts, where the client code is in: client.ts, the server code is in serverPluginHmr, for vue component updates, through the HMRRuntime in vue3.

10 Yu Yuxi speaks

Vite, a development server based on browser native ES Imports. Parsing the imports in the browser, compiling and returning them on the server side on demand, bypassing the concept of packaging entirely, and making the server available on demand. Not only does it have Vue file support, it also handles hot updates, and the speed of hot updates does not slow down with the increase of modules. For production environments, the same code can be rollup. Although it is still rough, I think this direction has potential. If done well, it can completely solve the problem of changing a line of code and waiting for hot updates for half a day.

❤️ Thank you

That is all the content of this sharing. I hope it will help you

Don’t forget to share, like and bookmark your favorite things.

Welcome to pay attention to the public number ELab team receiving factory good article ~