preamble
Picking up from the previous post, we learn thatvite
The principle of local construction is mainly:Start a connect server to intercept the ESM request from the browser. Finds the corresponding file in the requested path and compiles it to return it to the browser in the ESM format.
Based on this core idea, we can try to get our hands dirty to realize it.
Build a static server
on the basis ofkoa
Build a project:
The project is structured as above, with services usingkoa
Build.bin
Specify the location of the cli executable
#!/usr/bin/env node
// means that the script uses thenodefulfillment
const koa = require('koa');
const send = require('koa-send');
const App = new koa()
(3000, () => {
('Server is running at http://localhost:3000');
});
This way a service is built, and for debugging purposes, we execute in that working directorynpm link
This will link the project to the global npm, which is equivalent to installing the npm package globally.
Then we run themy-vite
You will be able to start the service!
Processing root directory html files
Since we didn't process any routes for the above service, when accessing thehttp://localhost:3000
You will find nothing, we first need to put the project's template fileReturn to Browser
const root = (); // Get the current working directory
('Current working directory: ', ()); // Get the current working directory.
// Static file serving area
(async (ctx, next) => {
// Process the root path and return
await send(ctx, , { root: () ,index: ''}); }
await next(); { // Process the root path and return.
}).
The template file is below:
<!doctype html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<link rel="icon" type="image/svg+xml" href="/" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Vite + Vue + TS</title>
</head>
<body>
<div id="app"></div>
<script>
= { env: { NODE_ENV: 'development' } };
</script>
<script type="module" src="/src/"></script>
</body>
</html>
that isESM
is loaded by means of thevue
entry file for the
After adding this code, we add thevue3
Let's do it under the projectmy-vite
Come to the browser to see what's going on at this point:
At this point the browser loads theThe file is as follows: it passes the
import
Two modules were introduced
import { createApp } from 'vue'
import App from './'
createApp(App).mount('#app')
Logically, the browser should have proceeded to initiate a request to fetch both modules at this point, but it doesn't now 🤔
At this point there is an error on the console:
It means that to load a module, it must be loaded with a relative path (/, . /, . /)
So we now need to deal with the loading paths of these modules
Processing module load path
Since the tripartite modules are loaded directly by module name, here we need to convert the reference paths of these modules to relative paths.
// Handle the module import
const importAction = (content) => {
return (/(from\s+['"])(?! \. \/)/g, '$1/@modules/')
}
// Modify the path to the third-party module
(async (ctx, next) => {
// ('', , ); }
// Handle ts or js files
if (('.ts') || ('.js')){
const content = await fileToString(); // Get the content of the file
= 'application/javascript'; // set the response type to js
= importAction(content); // Handle import loading paths
}
await next(); }
}).
In this middleware, we use regular expressions to replace the module's reference path with the path of the/@modules
beginning, so that it conforms to the browser's quoting rules.
Then go back to the browser to see what happens at this point:
At this point the browser can already make two other requests to load thevue
modules as well asComponent up.
can be seenvue
The load path of the module has changed to/@modules
It's open, although the path is still404
, but at the very least it's a step forward from where we were before.
indeed404
It's also well understood that since our service doesn't handle these kinds of paths at all yet, it should handle them next/@modules
this kind (of)path
and load the contents of the module
Loading third-party modules
Here we just need to go to the intercept just/@modules
and find the real location of the module under that path, and finally return it to the browser.
// Loading third-party modules
(async (ctx, next) => {
if (('/@modules/')) {
const moduleName = (10); // Get module name
const modulePath = (root, 'node_modules', moduleName); // Get module path
const package = require(modulePath + '/'); // Get the module's
// ('modulePath', modulePath);
= ('/node_modules', moduleName, ); // Rewrite Path
}
await next();
});
We can do this by reading thein the file
module
field to find the entry file for the third-party module.
This middleware needs to be executed before the middleware that handles module loading paths
At this point come back to the browser to view it:
It can be seen that at this point in time thevue
The module has been able to be reloaded, but there are four more modules loaded below, where did they come from?
can be seenvue
The module introduces anotherruntime-dom
modules, and their load paths have been converted to the/@modules
To begin with, this is the above mentionedThe middleware that loads the module needs to be executed before the middleware that handles the module load pathsAfter the module is loaded back, it passes through the middleware that handles the loading path, so it is equivalent to recursively converting all the paths of the module into relative paths.
runtime-dom
The module in turn introduces theruntime-core
together withshared
module, whereasruntime-core
The module in turn introduces thereactivity
module, so you'll see a loading order like the one in the image above.
The modules are loaded and introduced correctly, but the page still doesn't show any rendered content.
This is because at this point in timeIt hasn't been compiled in any way, and browsers don't recognize and execute the file directly.
So the next point is that you need to putfile into a browser-executable
javascript
Content (render function)
Handling Vue single-file components
Here we need to use theVue
compilation module@vue/compiler-sfc
together with@vue/compiler-dom
(coll.) speak tovue
The file is compiled and processed.
Handling scripts
const content = await fileToString(); // get the file content
const { descriptor } = (content); // Parsing a single file component
const compileScript = importAction(
(
descriptor, { { descriptor } = (content); // Parsing a single-file component.
{
id.
}
).content); // compile script
Handling templates
const compileRender =importAction((,
// compilingtemplate, renderThe variables in the function are removed from thesetupGetting
{ mode: 'module',
sourceMap: true,
filename: (),
__isScriptSetup: true, // Whether or not the marker issetup
compatConfig: { MODE: 3 }, // compatibilityvue3
}).code); // compilingtemplate
Handling style
let styles = '';
if(){
('', );
// Handle styles
styles = ((style,index) => {
return `
import '${}?type=style&index=${index}';
`
}).join('\n');
} // Handling styles
Here's a way to make an additional request to thestyle
This is handled so that the segregation logic can be clearer
Handling requests for styles
In the middleware by intercepting thetype
because ofstyle
request to be processed by the
if ( === 'style') {
// Handling styles
const styleBlock = [];
('styleBlock', styleBlock);
= 'application/javascript';
= `
const _style = (css) => {
const __style = ('style');
__style.type = 'text/css';
__style.innerHTML = css;
(__style);
}
_style(${()});
export default _style;
`;
}
final verification
summarize
After an in-depth exploration of thevite
After the workflow, you may realize that while it may seem simple conceptually, thevite
The implementation behind it is yet quite complex and subtle. We've just gone through a walk-through of its core process for thevite
There is an initial understanding of how to load modules, parse and compile files. However, this is just the tip of the iceberg.
Overall.vite
While the workings of the program can be understood with a simplified example, its true power and complexity extends far beyond that. It would be nice to have a better understanding of thevite
If you are interested in the in-depth workings of this program, you can read its source code in depth, where we can learn a lot more.