“This is the 7th day of my participation in the Gwen Challenge in November. Check out the details: The Last Gwen Challenge in 2021.”
Hello, ๐๐ปโ๏ธ๐๐ปโ ๐๐ปโ
I love knowledge transfer and am learning to write, ClyingDeng stool!
Working principle:
type="module"
ES Module native support in browser. If the browser supportstype="module"
We can use es6 modular writing. The browser sends another HTTP request to the server for the file we need to import. No packaging is required during development- Third parties rely on prepackaging
- Start a development server to process resource requests
Vite principle:
What does a browser do
Host file index.html
<script type="module" src="/src/main.js"></script>
Copy the code
After the browser gets the resources from the host file, it finds that it needs to request the main.js file again. The main.js resource request is sent to the server again.
main.js
In main, you can see that the browser is again launching the vue. Js? V = d253a66c, App. Vue? T =1637479953836 Resource request for two files.
The server compiles the content in app.vue and returns it to the browser. As you can see from the image below, both the logo and text are compiled into a _hoisted_ static node.
From the request header, you can also see that the SFC file has become a js file that the browser can recognize (the app.vue file must have script content to compile into JS). To the browser, it’s just a piece of JS code.
Other Bare Modules
If there are other dependencies in the Vue dependency, the browser will still make another resource request to get the resource.
Learn about pre-packing
For third-party dependencies (raw modules), vite packages them in advance and places them under node_modules/.vite. When starting the project, download the files directly from this path.
From the figure above, it can be seen that the path changes when the bare module is introduced.
What does the server do
Summary: the server processes files with special suffixes and returns them to the front end for display.
We can emulate Vite’s devServe and start a local service using KOA middleware.
// Introduce dependencies
const Koa = require('koa')
const app = new Koa()
const fs = require('fs')
const path = require('path')
const compilerSfc = require('@vue/compiler-sfc')
const compilerDom = require('@vue/compiler-dom')
app.use(async (ctx) => {
const { url, query } = ctx.request
// The resource code for processing requests is written here}) zaiz all h this z all he in app.listen(3001.() = > {
console.log('dyVite start!! ')})Copy the code
Request home index.html
if (url === '/') {
const p = path.join(__dirname, './index.html') // Absolute path
/ / home page
ctx.type = 'text/html'
ctx.body = fs.readFileSync(p, 'utf8')}Copy the code
By looking at the image above, we know that our host file has been requested successfully. This is just another request from the browser to the server for a main.js file. At this point, we also need to decide what to do with the main.js file.
Request files ending in.js
After we deal with the above, Emmmm… There are still many other resource requests in Main.
Basic JS file
The main files:
console.log(1)
Copy the code
To deal with the main:
else if (url.endsWith('.js')) {
ย ย // Respond to the js request
ย ย const p = path.join(__dirname, url)
ย ย ctx.type = 'text/javascript'
ย ย ctx.body = rewriteImport(fs.readFileSync(p, 'utf8')) // Handle dependent functions
}
Copy the code
Handle dependencies in Main
Do you think there is only one output in Main? That’s naive. Can you handle this?
The main files:
import { createApp, h } from 'vue'
createApp({ render: () = > h('div'.'helllo dyVite! ') }).mount('#app')
Copy the code
Emmm… It should!
We can change the address imported in main to a relative address. Add /@modules/ to the bare module path. Then you can identify /@modules/ files.
// Change the readable file address to a relative address
// Regular substitution overwrites imports into relative addresses
// import { createApp } from 'vue' => import { createApp } from '/@modules/vue'
function rewriteImport(content) {
return content.replace(/ from ['|"](.*)['|"]/g.function (s0, s1) {
// s0 matches the character string, s1 groups the content
// Is a relative path
if (s1.startsWith('/') || s1.startsWith('/') || s1.startsWith('.. / ')) {
// Return directly
return s0
} else {
return ` from '/@modules/${s1}'`}})}Copy the code
For third-party dependencies, vite internally requests internal resources from its own server /node_modules/.vite/ using prepackaging. We can simplify it a little bit by taking the dependency names to node_modules on the client.
else if (url.startsWith('/@modules/')) {
// Load the bare module
const moduleName = url.replace('/@modules/'.' ')
constpre! [1637477009328](imgs/1637477009328.png)! [1637477009368](imgs/1637477009368.The address of the PNG)const module = require(prefix + '/package.json').module
const filePath = path.join(prefix, module) // Get the file loading address
// Read dependencies
const ret = fs.readFileSync(filePath, 'utf8')
ctx.type = 'text/javascript'
ctx.body = rewriteImport(ret) // There may be dependencies inside a dependency that need to be recursed
}
Copy the code
When render is performed in main, the following error is reported:
The files we load are server-side libraries, which may generate code for the Node environment. We need to check the environment variables. If it is developing, it will output some warning messages, but not in the front end. So we need to mock out our current environment to the browser.
Add the process environment variable to the HTML.
ย <script>
ย ย window.process = { env: { NODE_ENV: 'dev' } }
ย </script>
Copy the code
The main file is now loaded.
But this is far from what we want!
We need a server that can compile vue files.
To deal with.vue
file
The main. Js file:
import { createApp, h } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
Copy the code
In the VUE file, it is modular loaded.
We need to process the parameters carried behind the.vue file when processing it.
Here, we simplify and consider only the Template and SFC cases.
else if (url.indexOf('.vue') > -1) {
// Handle vue file app.vue? vue&type=style&index=0&lang.css
// Read vue contents
const p = path.join(__dirname, url.split('? ') [0])
// compilerSfc parses the SFC to get the AST
const ret = compilerSfc.parse(fs.readFileSync(p, 'utf8'))
// App.vue? type=template
// If the request does not have query.type, it is SFC
if(! query.type) {// Process the internal script
const scriptContent = ret.descriptor.script.content
// Convert the default exported configuration object to a constant
const script = scriptContent.replace(
'export default '.'const __script = ',
)
ctx.type = 'text/javascript'
ctx.body = `
${rewriteImport(script)}Import {render as __render} from ';${url}? type=template' __script.render = __render export default __script `
} else if (query.type === 'template') {
const tpl = ret.descriptor.template.content
// Compile includes the render module
const render = compilerDom.compile(tpl, { mode: 'module' }).code
ctx.type = 'text/javascript'
ctx.body = rewriteImport(render)
}
}
Copy the code
Processing image path
Returns from reading directly from the client.
else if (url.endsWith('.png')) {
ย ย ctx.body = fs.readFileSync('src' + url)
}
Copy the code
Surprise at the end
Thank you all the time to support and encourage, today my article finally over 100!
You can click on ๐โ๏ธ to prevent getting lost!
If more than 20 people interact in the comments section, like and comment ๐!
I will draw one lucky reader and give away a gold digger mug (or gold digger enamel cup) ๐โ๏ธ!
Still the same (do not need to bear the freight oh) ๐!
The event ends on November 30th! ๐๐๐!
Lucky draw: random number is used to select the random commenter โจ.
Random number Random range: Maximum Indicates the minimum number of likes and comments.
The lucky winner does not have to worry about expiration this time, I will wait until you reply to my ha ๐ค๐ค๐ค!
One item for those interested can be plus-one item for vite or just one item from the author (โ’โก’โ)! . If not, please give me your advice.