vite
这个构建工具被用在了vue3上门,而且它的构建思路我觉得优于webpack
,底层也是使用了esbuild
,性能上更优vite
的,我们先来看看什么是vite
vite
的天然优势:
如: <script type="module" src="/src/main.js"></script>
http://localhost:3000/src/main.js请求main.js文件:
// /src/main.js:
import { createApp } from 'vue'
import App from './App.vue'
createApp(App).mount('#app')
GET http://localhost:3000/@modules/vue.js
GET http://localhost:3000/src/App.vue
function createServer() {
let app = new Koa()
const context = { // 直接创建一个上下文 来给不同的插件共享功能
app,
root: process.cwd() //执行node命令的那个命令路径
}
// 运行koa中间件(就是我们的vite插件)
resolvePlugin.forEach(plugin => plugin(context))
return app
}
createServer().listen(4000, () => {
})
这里
readBody
其实就是一个读取文件流的方法,封装过而已,看成普通的读取流方法即可
app.use(async (ctx, next) => {
await next(); // 静态服务
// 默认会先执行 静态服务中间件 会将结果放到 ctx.body
// 需要将流转换成字符串 , 只需要处理js中的引用问题
if (ctx.body && ctx.response.is('js')) {
let r = await readBody(ctx.body); // vue => /@modules
const result = rewriteImports(r);
ctx.body = result;
}
})
},
.vue
文件和带@module
(重写路径之前就是node_modules
里面的文件) // 2. 拦截含有/@modules/vue的请求, 去node_modules引入对应的模块并返回
({ app, root }) => {
const reg = /^\/@modules\//
app.use(async (ctx, next) => {
// 如果没有匹配到 /@modules/vue 就往下执行即可
if (!reg.test(ctx.path)) {
return next();
}
const id = ctx.path.replace(reg, '');
let mapping = {
vue: path.resolve(root, 'node_modules', '@vue/runtime-dom/dist/runtime-dom.esm-browser.js'),
}
const content = await fs.readFile(mapping[id], 'utf8');
ctx.type = 'js'; // 返回的文件是js
ctx.body = content;
})
},
// 3. 解析.vue文件
({ app, root }) => {
app.use(async (ctx, next) => {
if (!ctx.path.endsWith('.vue')) {
return next();
}
const filePath = path.join(root, ctx.path);
const content = await fs.readFile(filePath, 'utf8');
// 引入.vue文件解析模板
const { compileTemplate, parse } = require(path.resolve(root, 'node_modules', '@vue/compiler-sfc/dist/compiler-sfc.cjs'))
let { descriptor } = parse(content);
if (!ctx.query.type) {
//App.vue
let code = ''
if (descriptor.script) {
let content = descriptor.script.content;
code += content.replace(/((?:^|\n|;)\s*)export default/, '$1const __script=');
}
if (descriptor.template) {
const requestPath = ctx.path + `?type=template`;
code += `\nimport { render as __render } from "${requestPath}"`;
code += `\n__script.render = __render`
}
code += `\nexport default __script`
ctx.type = 'js';
ctx.body = code
}
if (ctx.query.type == 'template') {
ctx.type = 'js';
let content = descriptor.template.content
const { code } = compileTemplate({ source: content }); // 将app.vue中的模板 转换成render函数
ctx.body = code;
}
})
},
// 4. 静态服务插件 实现可以返回文件的功能
({ app, root }) => {
app.use(static(root))
app.use(static(path.resolve(root, 'public')))
}
]
function createServer() {
let app = new Koa()
const context = { // 直接创建一个上下文 来给不同的插件共享功能
app,
root: process.cwd() // C:\Users\...\my-vite-vue3
}
// 运行中间件
resolvePlugin.forEach(plugin => plugin(context))
return app
}
//读取body方法
async function readBody(stream) {
if (stream instanceof Readable) {
return new Promise((resolve) => {
let res = ''
stream.on('data', function (chunk) {
res += chunk
});
stream.on('end', function () {
resolve(res)
})
})
} else {
return stream;
}
}
const resolvePlugin = [
// 1. 重写引入模块路径前面加上/@modules/vue, 重写后浏览器会再次发送请求
({ app, root }) => {
function rewriteImports(source) {
let imports = parse(source)[0];
let ms = new MagicString(source);
if (imports.length > 0) {
for (let i = 0; i < imports.length; i++) {
let { s, e } = imports[i];
let id = source.slice(s, e); // 应用的标识 vue ./App.vue
// 不是./ 或者 /
if (/^[^\/\.]/.test(id)) {
id = `/@modules/${id}`;
ms.overwrite(s, e, id)
}
}
}
return ms.toString();
}
npm init vite-app --template react
yarn
yarn dev
react
的项目就搭建好了,默认使用的是17.0.0
版本的react
,这样createElement
方法再也不用从react里面导出了,我想这样jsx
风格代码也会更容易被迁移到其他框架项目中 "dependencies": {
"react": "^17.0.0",
"react-dom": "^17.0.0"
},
"devDependencies": {
"vite": "^1.0.0-rc.13",
"vite-plugin-react": "^4.0.0"
}
// @ts-check
import reactPlugin from 'vite-plugin-react'
/**
* @type { import('vite').UserConfig }
*/
const config = {
jsx: 'react',
plugins: [reactPlugin]
}
export default config
vite
的实现原理,目前我还没有把它使用在生产环境中vite
如果生态能发展起来,可能我们就用不到wepback6
这个版本了(当然未来不可猜测)赞/在看
,关注一下【前端巅峰
】公众号吧