​ 大家会发现浏览器回去请求.vue文件,那么浏览器为什么能够识别.vue文件,vite在中间或者是说在把文件给到浏览器之前对文件做了什么事情,能够让浏览器识别、解析.vue文件?大家可以带着问题看下去。

开发服务器

​ 我们在正常情况下,使用vite开发项目的时候,都会使用vite帮我们配置的服务器,通过pnpm run dev启动,浏览器发送的请求是给到vite启动的服务器,所以他可以在将文件发给浏览器之前做很多的事情。所以下面我们就搭建一个建议的vite服务器,看下vite都做了些什么?

安装依赖

​ vite搭建服务器主要使用的就是koa框架。所以我们的服务器也同样用koa来搭建。

引入koa

1
pnpm add koa

入口文件

​ 我们新建一个index.js文件作为项目的入口文件,实现以下代码

1
2
3
4
5
6
7
8
const koa = require("koa") //导入koa node端需要使用common js

const app = new koa() // 实例化一个koa

app.listen(5173, () => {
console.log('vite dev server start: http://localhost:5173');
})
// 监听5173 端口 启动后输出vite dev server start: http://localhost:5173

​ 随后我们可以使用node index.js启动项目,为了方便起见,我们可以使用nodemon启动项目,他可以在监听我们的文件,当其发生变化的时候自动重启我们的服务器,提高开发效率。

注册中间件

​ 随后我们可以注册一个中间件,一个中间件就是一个函数,一个完整的请求,服务端处理来自浏览器的请求,可能会经历数个中间件,中间价函数有两个参数,一个ctx、一个next,我们关注点主要是第一个,next主要是我们用来放行的,前面我们已经说过了,一个请求会经历数个中间价,如果我们不调用next函数放行,那么就不会到下一个中间件。

1
2
3
4
5
app.use((ctx, next) => {
console.log(111, ctx.request, ctx.response);
console.log(222, next); // Function
})
// 通过use函数注册中间件

读取文件返回给前端

  1. 新建index.html文件
1
2
3
4
5
6
7
8
9
10
11
12
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>my vite server</title>
</head>
<body>
my vite server
</body>
</html>
2. 修改index.js
1
2
3
4
5
6
7
8
9
10
11
12
const fs = require("fs")
const path = require("path")

const app = new koa()

app.use(async (ctx, next) => {
if (ctx.request.url === '/') {
const innerHTML = await fs.promises.readFile(path.resolve(__dirname, './index.html'))
ctx.response.body = innerHTML //把文件内容当成响应体返回给前端
ctx.response.set("Content-Type", "text/html") // 告诉浏览器你当成html来解析
}
})

​ 然后我们浏览器在重新发送请求的时候,就能拿到index.html的内容了。

返回.vue文件给浏览器

​ 到目前为止,一切都在按照我们的预想发展,那么我们尝试返回.vue文件给到浏览器看看效果。我们会发现,浏览器压根就不认识vue文件,我们在前面使用的Content-Type,压根就没有解析vue文件的选项,自始至终,浏览器就不支持解析vue文件。所以,我们需要另辟蹊径,也就是前面提到的,你找我要东西,我看到是vue文件,那么我处理成你能解析的格式(js),然后再给你,你去解析就可以了。vite编译vue文件我们会在后续的章节继续深究。在这里我们只需要明确一点,最终给到浏览器的vue文件是js代码。并且我们设置Content-Type为JavaScript即可。

1
2
3
4
5
6
7
8
9
app.use(async (ctx, next) => {
// 处理.vue文件
if (ctx.request.url === '/app.vue') {
const AppVue = await fs.promises.readFile(path.resolve(__dirname, './app.vue'))
// 对AppVue进行解析,因为服务器拿到的是字符串,所以我们可以很方便的对他进行处理,解析成js,这里这个步骤就先省略了,后续其他章节进行补充
ctx.response.body = AppVue
ctx.response.set("Content-Type", "text/javascript")
}
})

​ 在我们发现url是app.vue的时候(实际上是判断是否以.vue后缀结尾),就去拿到这个文件,然后对整个字符串的template、script、style标签里面的代码进行编译替换,template会生成AST语法树,然后最终是document.createElement形式的代码,交给浏览器去构建dom节点。

总结

​ vite在中间开启了一个服务器,对我们的代码进行解析编译,并且在中间帮我们做了很多优化,这个就先不谈。我们需要清楚vite处理vue文件的大致工作流程:

1. 首先遇到.vue结尾的文件,先去读取文件,然后对拿到的文件内容进行编译,处理成浏览器认识的代码,虽然设置Content-Type的值为text/javascript,告诉浏览器,虽然是vue文件,但是你别管了,我处理好了,你直接当成js来执行就好了。
1. 遇到js文件,直接设置Content-Type的值为text/javascript,告诉浏览器,你以js的形式执行代码就好了,别的不用管