前言
本文总结了一些关于 Vite 的工作原理,以及一些实现细节。
本节对应的 demo 可以在这里找到。
什么是 Vite
Vite 是一个基于浏览器原生 ES imports 的开发服务器。利用浏览器去解析 imports,在服务器端按需编译返回,完全跳过了打包这个概念,服务器随起随用。
实现步骤
- 项目搭建
- 实现 cli
- 起静态服务器, nodemon 监听文件修改,执行 vite 命令
- 处理 index.html
- 处理 js,处理 node_modules 的引入
- 中间件拆分
- 处理 react 文件
项目结构
├── _example
├── cli
│ └── index.js
├── src
│ └── index.js
_example 通过 npx create-vite-app 创建的 vite 项目, 用于和 mini-vite 对比
npx create-vite _example --template react
实现 cli
新建 cli/index.js
#! /usr/bin/env node
console.log("mini-vite!");
mini-vite/package.json
{
"bin": "cli/index.js"
}
通过 yarn link 将 cli 链接到全局
# _demo/mini-vite目录
yarn link
在 _example 中 link
# _demo/mini-vite/_example目录
yarn link mini-vite
在 package.json 中添加命令
{
"scripts": {
"dev:mini-vite": "mini-vite"
}
}
跑下 dev:mini-vite 命令,可以看到控制台已经打印出 mini-vite!
起静态服务器
依赖安装
yarn add koa koa-static
在 src 目录下新建 index.js
// src/index.js
const Koa = require("koa");
const KoaStatic = require("koa-static");
const app = new Koa();
// 执行命令时的路径
const rootPath = process.cwd();
app.use(KoaStatic(rootPath));
app.listen(8000, () => {
console.log("mini-vite server启动成功!");
});
同时,在_example 中的 package.json 中添加命令
{
"scripts": {
"dev:mini-vite": "nodemon -w ../ --exec mini-vite",
"mini-vite": "mini-vite"
}
}
并安装 nodemon
# mini-vite/_example
yarn add nodemon -D
执行,可以看到控制台打印出 mini-vite server 启动成功!同时在浏览器中打开 http://localhost:8000/ 可以看到项目已经跑起来了。(这里的端口号是 8000,是因为 create-vite-app 默认的端口号是 3000,所以这里我们用 8000)
同时修改 index.js 也可以看到 terminal 中打印出修改成功。
处理 jsx
现在我们已经可以返回静态文件了,但是在返回 index.html 中后,浏览器随即发起了 src/main.jsx 的请求
<script type="module" src="/https/blog.csdn.net/src/main.jsx"></script>
然后就报错了,因为浏览器无法解析 jsx 文件,所以我们需要对.jsx 进行处理,将 src/main.jsx 改为 src/main.js
main.jsx:1 Failed to load module script: Expected a JavaScript module script but the server responded with a MIME type of “text/jsx”. Strict MIME type checking is enforced for module scripts per HTML spec.
首先是 jsx 的转换
在 mini-vite 目录安装依赖:
# mini-vite
yarn add @babel/core @babel/plugin-transform-react-jsx
添加 transformJsx 函数
function transformJsx(jsxCode) {
const babel = require("@babel/core");
const options = {
// presets: ['@babel/preset-env'], // 注意这里不要使用 @babel/preset-env,因为它会将所有的代码都转换成 ES5,包括import
plugins: [
[
"@babel/plugin-transform-react-jsx",
{
pragma: "React.createElement",
pragmaFrag: "React.Fragment",
},
],
],
};
const {
code } = babel.transform(jsxCode, options);
return code;
}
修改 src/index.js 的代码, 进行了一点重构, 添加中间件的机制
// index.js
const Koa = require("koa");
const KoaStatic = require("koa-static");
function createServer() {
const app = new<