Hello, I am very glad that you can click on this blog. This blog is a series of articles on the interpretation of the source code of Vite
. After reading it carefully, I believe you can have a simple understanding of the workflow and principles of Vite
.
Vite
is a new front-end construction tool that can significantly improve the front-end development experience.
I will use the combination of pictures and texts to try to make this article less boring (obviously for source code interpretation articles, this is not a simple thing).
If you haven't used Vite
, then you can read my first two articles, I just experienced it for two days. (as follows)
This article mainly interprets vite
source code ontology, vite
provides development server through connect
library, and realizes multiple development server configurations through middleware mechanism. However, rollup
did not use packaging tools such as webpack
or vite
during local development, but realized the translation of files by scheduling internal plugin
, so as to achieve a small and fast effect.
Well, without further ado, let's get started!
vite dev
project directory
The Vite
source code version read in this article is 2.8.0-beta.3
. If you want to read it with me, you can download the Vite source code at this address.
Let's first take a look at the project directory of the package Vite
. (As shown below)
This is an integrated management project, the core of which is several packages in packages
. Let's take a look at what these packages do. (as follows)
Package names | effect |
---|---|
vite | Vite main library, responsible for the local development (plug-in scheduling) and production product construction (Rollup scheduling) of the Vite project |
create-vite | Used to create a new Vite project, which stores the initialization templates of multiple frameworks (such as react、vue ) |
plugin-vue | Vite Official plugin to provide Vue 3 single-file component support |
plugin-vue-jsx | Vite Official plugin to provide Vue 3 JSX support (via a dedicated Babel transform plugin). |
plugin-react | Vite official plugin for full React support |
plugin-legacy | Vite official plugin, used to provide traditional browser compatibility support for packaged files |
playground | Some built-in test cases and Demo of Vite |
These source code repositories are actually worth reading, but this time we will focus on our main line of this issue - Vite
, and let's start with Vite
.
Next, we focus on interpreting vite
local development service command - vite / vite dev / vite serve
.
vite dev
Let's take a look at vite dev
command, the internal workflow of the local development service.
vite dev
calls the internal createServer
method to create a service, which uses middleware (third party) to support multiple capabilities (such as cross-domain,
static file server, etc.), and internally created
watcher
to continuously monitor file changes , with just-in-time compilation and hot reloading.
And createServer
does is the core logic we need to pay attention to.
In the createServer
method, the collection of the configuration is first performed - resolveConfig
.
Configurations supported by vite
We can just look at the configuration supported by the vite
project through the source code. You can also directly refer Vite official document . (as follows)
Configuration name | Configuration instructions |
---|---|
configFile | Configuration file, read the vite.config.js configuration file in the root directory by default |
envFile | Environment variable configuration file, read the .env environment variable configuration file in the root directory by default |
root | The root directory of the project, the default value is the directory where the command is executed - process.cwd() |
base | Similar to webpack in publicPath , which is the public base path of the resource |
server | Local runtime service settings, such as setting host (host address), port (running port)... For detailed configuration, please refer to vite document |
build | For options when building production products, you can refer to vite document |
preview | Preview option, after using the build command, you can run vite preview to preview the product. For the specific configuration, please refer to vite document |
publicDir | Static resource directory, used to place static resources that do not need to be compiled, the default value is the public directory |
cacheDir | Cache folder, used to place some cache dependencies precompiled by vite , to speed up the compilation speed of vite |
mode | Compile mode, the default value is development when running locally, and production when building production products |
define | Define global variables, where each item of the development environment will be defined globally, and the production environment will be statically replaced |
plugins | Configure the plugin for the vite project |
resolve | resolve supports many configurations, you can refer to vite document |
css | For the compilation options of the css file, you can refer to vite document |
json | For the compilation options of the json file, you can refer to vite document |
esbuild | Looking at the official document is used to convert files, but I don't know what the specific work does. If you have any trouble, please leave a message in the comment area to clarify your doubts. |
assetsInclude | Set the file type that needs to be processed independently by the picomatch mode (a file matching mode) |
optimizeDeps | Depends on optimization options, for details, please refer to vite document |
ssr | For related options of ssr , please refer to vite document |
logLevel | Adjust the level of console output, default is info |
customLogger | Custom logger , this option is not exposed, it is an internal option |
clearScreen | The default is true . After the configuration is false , each recompile will not clear the previous content. |
envDir | The directory used to load the environment variable configuration file .env , the default is the current root directory |
envPrefix | The prefix of the environment variable, the environment variable with the prefix will be injected into the project |
worker | Configure bundle output type, plugins and Rollup configuration items |
Some of the above configurations can be added through command line parameters at startup, for example, set in the form of vite --base / --mode development
.
If you want the configuration to be readable through configuration, you can also configure it all through vite.config.js
.
Configure breakpoint debugging
After a cursory look at the configurations supported by vite
, we return to createServer
function, ready to start reading.
Before that, if we can directly run vite dev
command and hit a breakpoint, it can better help us read the source code better, so let's configure it first.
We need to enter vite/packages/vite
first, install the dependencies, then run scripts
in npm run build
, and build vite
into the dist
directory.
Then, we use the debugging capabilities of vscode
, create a launch.json
(below), and run one of our vite
projects.
// launch.json
{
"version": "0.2.0",
"configurations": [
{
"type": "pwa-node",
"request": "launch",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
],
"program": "packages/vite/bin/vite.js",
"args": ["/Users/Macxdouble/Desktop/ttt/vite-try"]
}
]
}
After the debugging configuration is completed, we can hit a breakpoint in the resolveConfig
function to check the effect (the file location is in the dist
directory, you need to find the corresponding file according to your own reference).
load configuration file
The first step of resolveConfig
is to load the configuration file of the project directory. If the location of the configuration file is not specified, it will automatically search for vite.config.js
, vite.config.mjs
, vite.config.ts
, vite.config.cjs
in the root directory.
If no configuration file is found, the program will be aborted directly.
When thevite
project is initialized, thevite.config.js
configuration file will be automatically generated in the project root directory.
After reading the configuration file, the configuration file and the initial configuration (higher priority, some configurations come from command line parameters) will be merged, and then a configuration will be obtained. (As shown below)
Configuration Collection - resolveConfig
At the beginning of createServer
, the resolveConfig
function is called for configuration collection.
Let's take a look at what resolveConfig
has done.
Handling plugin execution order
First, resolveConfig
handles the plugin collation internally, corresponding to the following collation.
In the process of subsequent processing, the plug-ins will be executed sequentially according to the corresponding sorting rules, so that the plug-ins can work better in each life cycle node.
Merge plugin configuration
After the plug-in sorting is completed, the vite
plug-in of exposes a configuration field of
config
. By setting this property, the plug-in can add or rewrite some configurations of vite
. (As shown below)
Handling aliases
Then, resolveConfig
internally processes the logic of alias
, and replaces the specified alias
with the corresponding path.
Read environment variable configuration
Next, resolveConfig
finds the configuration directory of env
(the default is the root directory), and then reads the corresponding env
environment variable configuration file in the directory. We can look at the internal read rule priority (as shown below)
It can be seen that the read priorities are .env.[mode].local
and .env.[mode]
respectively. If there is no configuration file corresponding to mode
, it will try to find .env.local
and .env
configuration files. After reading the configuration files, use doteenv
to write the environment variables into the project; if these environment variable configuration files do not exist, then will return an empty object.
The environment variable configuration file does not affect the operation of the project, so it has no effect if it is not configured.
export configuration
Next, vite
initializes the build configuration, which is the build
property in the document. For details, please refer to the build options document
Finally, resolveConfig
processed some publicDir
and cacheDir
directories, the following configuration was exported.
const resolved: ResolvedConfig = {
...config,
configFile: configFile ? normalizePath(configFile) : undefined,
configFileDependencies,
inlineConfig,
root: resolvedRoot,
base: BASE_URL,
resolve: resolveOptions,
publicDir: resolvedPublicDir,
cacheDir,
command,
mode,
isProduction,
plugins: userPlugins,
server,
build: resolvedBuildOptions,
preview: resolvePreviewOptions(config.preview, server),
env: {
...userEnv,
BASE_URL,
MODE: mode,
DEV: !isProduction,
PROD: isProduction
},
assetsInclude(file: string) {
return DEFAULT_ASSETS_RE.test(file) || assetsFilter(file)
},
logger,
packageCache: new Map(),
createResolver,
optimizeDeps: {
...config.optimizeDeps,
esbuildOptions: {
keepNames: config.optimizeDeps?.keepNames,
preserveSymlinks: config.resolve?.preserveSymlinks,
...config.optimizeDeps?.esbuildOptions
}
},
worker: resolvedWorkerOptions
}
resolveConfig
has some additional work processing inside, mainly collecting the internal plug-in collection (as shown in the figure below), and configuring some deprecated option warning messages.
Local Development Services - createServer
Going back to the createServer
method, this method processes the logic of ssr
(server-side rendering) for the first time after getting the configuration through resolveConfig
.
If server-side rendering is used, local development and debugging will be performed in other ways.
If it is not server-side rendering, a http server
will be created for local development and debugging, and a websocket
service will be created for hot reloading. (As shown below)
File monitoring + hot reload
Then, vite
creates a FSWatcher
object to monitor changes in local project files. (The chokidar
library is used here)
const watcher = chokidar.watch(path.resolve(root), {
ignored: [
// 忽略 node_modules 目录的文件变更
'**/node_modules/**',
// 忽略 .git 目录的文件变更
'**/.git/**',
// 忽略用户传入的 `ignore` 目录文件的变更
...(Array.isArray(ignored) ? ignored : [ignored])
],
ignoreInitial: true,
ignorePermissionErrors: true,
disableGlobbing: true,
...watchOptions
}) as FSWatcher
Then, vite
organizes multiple properties and methods into a server
object, which is responsible for starting the local development service and also responsible for the subsequent development hot reloading of the service.
Next, let's take a look at how watcher
does page hot reloading. The principle is to re-trigger the plugin compilation after monitoring the file change, and then send the update message to the client. (As shown below)
plugin container
Next, vite
creates the plugin container ( pluginContainer
) for calling the plugin's hooks at various stages of the build. (As shown below)
In fact, the plugin container is created before hot reloading. For the convenience of reading, the article puts the hot reloading content together.
middleware mechanism
Next is some internal middleware processing. When configuring development server options, vite
internally provides support through the middleware capabilities of the connect
framework. (As shown below)
Among them, many configurations such as public
directory and public path are realized through connect
+ middleware, making full use of the capabilities of third-party libraries without reinventing the wheel.
prebuilt dependencies
Next, vite
pre-builds the dependencies used in the project, one is to be compatible with different ES module specifications, and the other is to improve the loading performance. (As shown below)
When the preparations are ready, vite
internally calls startServer
start the local development server. (as follows)
// ...
httpServer.listen(port, host, () => {
httpServer.removeListener('error', onError)
resolve(port)
})
summary
So far, the source code part of vite
itself has been parsed.
It can be seen that during local development, vite
mainly relies on plug-in + middleware system to provide capability support. Because only a small amount of compilation work is involved in local development, it is very fast.
vite
rollup
building the production product.
Let's use a flowchart to finally sort out the internal workflow of the vite local development service.
Then this article ends here. In the next article, I will select 1-2 typical plug-ins or build
(production product construction) for source code analysis.
one last thing
If you have seen this, I hope you will give a like and go~
Your likes are the greatest encouragement to the author, and can also allow more people to see this article!
If you think this article is helpful to you, please help to light up star
on github to encourage it!
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。