Ding Nan: Dao Xilin, the professional title party of medical Support group of wedoctor front-end Technology Department, who is addicted to food

preface

viteESM is a solution based on the browser-supported ESM module to solve the problem of large application local development environment packaging and hot update time. Currently, it is supportedvue,react,Svelte,SolidAnd so on mainstream framework, I believe that many students have begun to use Vite, and experience the “flying” experience, let’s have a lookviteHow to supportreact.

A, start,

Start by pulling down the source code for Vite from Github

git clone https://github.com/vitejs/vite.git
cd vite
yarn
cd packages/vite
yarn build
yarn link
Copy the code

Scaffolding the Viet-React project

yarn create @vitejs/app my-react-app --template react
yarn link vite
yarn dev
Copy the code

Add node browser debug script

"debug": "node --inspect-brk node_modules/vite/dist/node/cli.js"
Copy the code

Start the service and you can seeIndex. HTML has one more piece than the source codevite/clinet,@react/refreshThe type of the script ismoduleType, we come according to the source code analysis of vite is how to do this layer of transformation.

2. Middleware

After vite 2.x, the original koA model of 1.x was abandoned, and the middleware model of Node native HTTP module + Connect was adopted. The localhost request is first redirected to index.html by connect-history-api-fallback, and then to the next middleware, indexHtmlMiddleware. This is where the createDevHtmlTransformFn function is actually executed

// packages\vite\src\node\server\middlewares\indexHtml.ts
export function createDevHtmlTransformFn(
  server: ViteDevServer
) : (url: string, html: string, originalUrl: string) = >Promise<string> {
  const [preHooks, postHooks] = resolveHtmlTransforms(server.config.plugins)

  return (url: string, html: string, originalUrl: string): Promise<string> => {
    return applyHtmlTransforms(html, [...preHooks, devHtmlHook, ...postHooks], {
      path: url,
      filename: getHtmlFilename(url, server),
      server,
      originalUrl
    })
  }
}
Copy the code

Here two hooks will be exported, respectively

  • DevHtmlHook, insert @/vite/client.js into the header
  • React-refresh, which inserts a bunch of react-refresh code into the header

@/vite/client.js is a vite hot update plugin that supports vite-hMR hot updates. @react-refresh is a vite hot update plugin that supports react hot updates

3. Transform

Resource requests from the entry file (index.html) go into transformMiddleware

// Packages \vite\ SRC \node\server\index.ts file conversion core
  middlewares.use(transformMiddleware(server))
Copy the code
// packages\vite\src\node\server\transformRequest.ts 
export async function transformRequest(url { config, pluginContainer, moduleGraph, watcher } options) {...const loadResult = await pluginContainer.load(id, ssr)
  
  code = loadResult.code
  map = loadResult.map

  // Code conversion, call a series of plugin to do code conversion
  const transformStart = isDebug ? Date.now() : 0
  const transformResult = await pluginContainer.transform(code, id, map, ssr)
  
  code = transformResult.code!
  map = transformResult.map

  return (mod.transformResult = {
    code,
    map,
    etag: getEtag(code, { weak: true})}as TransformResult)
  
}
Copy the code

The transform function of pluginContainer calls a series of plugins built into vite during initialization to convert the source code. Take SRC /main. JSX as an example

import React from 'react'
import ReactDOM from 'react-dom'
import './index.css'
import App from './App'

ReactDOM.render(
  <React.StrictMode>
    <App />
  </React.StrictMode>.document.getElementById('root'))Copy the code

The plugin, identified as Vite :esbuild, takes advantage of esbuild’s built-in Apitransform to translate JSX syntax into React. CreateElement, in part replacing Babel

import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import App from "./App";
ReactDOM.render(/* @__PURE__ */ React.createElement(React.StrictMode, null./* @__PURE__ */ React.createElement(App, null)), document.getElementById("root"));
Copy the code

A plugin with an identifier named vite: import-Analysis is then entered

Native ES imports do not support raw module imports, and Vite will detect such raw module imports in all source files of the service, pre-build and rewrite imported legal urls

import { someMethod } from 'my-dep'
Copy the code

Because browsers do not support direct naked module imports, it is necessary to rewrite the module addresses into real resource file addresses. Import-analysis uses the es-module-lexer package to dynamically analyze the dependencies involved in the import syntax in the current code. /node_modules/.vite), and then calls the built-in transformCjsImport function to convert import statements of Commonjs type packages

import React from "react"
Copy the code

Will be translated into

import __vite__cjsImport0_react from "/node_modules/.vite/react.js? v=21227a2f"; const React = __vite__cjsImport0_react.__esModule ? __vite__cjsImport0_react.default : __vite__cjsImport0_react
Copy the code

Vue3 is also the same conversion logic, but for a single file requires @vitejs/plugin-vue support

The subsequent loading logic is similarly formatted without further elaboration.

Four, @ vitejs/plugin – react – refresh

Vite supports react with esbuild instead of @babel/preset — React, and presets the official react-refresh to support react hot updates. Let’s see what it does.

transcoding

All JSX files will be interpreted by @react-Refresh via @babel/core, but only react components that really need hot updates will be output

const result = transformSync(code, {
    babelrc: false.configFile: false.filename: id,
    parserOpts: {
      sourceType: 'module'.allowAwaitOutsideFunction: true.plugins: parserPlugins
    },
    generatorOpts: {
      decoratorsBeforeExport: true
    },
    plugins: [
      require('@babel/plugin-transform-react-jsx-self'),
      require('@babel/plugin-transform-react-jsx-source'),require('react-refresh/babel'), { skipEnvCheck: true}]],ast: !isReasonReact,
    sourceMaps: true.sourceFileName: id
  })

  if (!/\$RefreshReg\$\(/.test(result.code)) {
    // The regex is used to analyze whether the code block is a React Component that needs hot update support, otherwise the source code is returned
    return code
  }
Copy the code

Provide additional runtime code

// index.html is inserted into this string of initialization code
import RefreshRuntime from "/@react-refresh"
RefreshRuntime.injectIntoGlobalHook(window)
window.$RefreshReg$ = () = > {}
window.$RefreshSig$ = () = > (type) = > type
window.__vite_plugin_react_preamble_installed__ = true
Copy the code
import { createHotContext as __vite__createHotContext } from "/@vite/client";
import.meta.hot = __vite__createHotContext("/src/App.jsx");
import RefreshRuntime from "/@react-refresh";
if (import.meta.hot) {
  window.$RefreshReg$ = (type, id) = > {
    RefreshRuntime.register(type, "D:/xxx/vite-react/src/App.jsx " + id);
  };
  window.$RefreshSig$ = RefreshRuntime.createSignatureFunctionForTransform;
}

// Insert the converted component code here
if (import.meta.hot) {
  import.meta.hot.accept();
  if (!window.__vite_plugin_react_timeout) {
    window.__vite_plugin_react_timeout = setTimeout(() = > {
      window.__vite_plugin_react_timeout = 0;
      RefreshRuntime.performReactRefresh();
    }, 30); }}Copy the code

ImportAnalysis dynamically inserts the code for createHotContext, a mechanism provided by Vite for caching the context, into the JSX file.

Refreshruntime. register is an API provided by react-Refresh to register components. The second parameter is the component’s file path plus its ID, which identifies which component needs to be hot replaced.

RefreshRuntime. PerformReactRefresh trigger the react rendering.

Five, the summary

Let’s summarize what Vite does to support ReactIn fact, when starting the service, Vite will scan all the dependencies from the entry file and prebuild them, and generate the module dependency moduleGraph, which is similar to a tree, for easy cache management. Interested students welcome to continue tracking, passing brother, miss sisters to three even!

Small AD

  • Hospital support group of front End Technology Department of Wedoctor Group
  • Coordinates: Hangzhou, Zhejiang
  • 3 years + or 22 internship, favorable treatment
  • Resume email: [email protected]