企业网站php模版,网上书店网网站建设,wordpress tag列表页,网站业务建设是什么意思戳蓝字前端优选关注我们哦#xff01;一.什么是Vite#xff1f;法语Vite(轻量#xff0c;轻快)vite 是一个基于 Vue3单文件组件的非打包开发服务器#xff0c;它做到了本地快速开发启动、实现按需编译、不再等待整个应用编译完成的功能作用。对于Vite的描述前端优选关注我们哦一.什么是Vite法语Vite(轻量轻快)vite 是一个基于 Vue3单文件组件的非打包开发服务器它做到了本地快速开发启动、实现按需编译、不再等待整个应用编译完成的功能作用。对于Vite的描述针对Vue单页面组件的无打包开发服务器可以直接在浏览器运行请求的vue文件。面向现代浏览器Vite基于原生模块系统 ESModule 实现了按需编译而在webpack的开发环境却很慢是因为其开发时需要将进行的编译放到内存中打包所有文件。Vite有如此多的优点那么它是如何实现的呢二.Vite的实现原理我们先来总结下Vite的实现原理Vite在浏览器端使用的是 export import 方式导入和导出的模块vite同时实现了按需加载Vite高度依赖module script特性。实现过程如下:在 koa 中间件中获取请求 body通过 es-module-lexer 解析资源 ast 并拿到 import 内容判断 import 的资源是否是 npm 模块返回处理后的资源路径vue /modules/vue将要处理的template,script,style等所需依赖以http请求的形式、通过query参数的形式区分并加载SFC(vue单文件)文件各个模块内容。接下来将自己手写一个Vite来实现相同的功能三.手把手实现Vite1.安装依赖实现Vite的环境需要es-module-lexer、koa、koa-static、magic-string模块搭建npm install es-module-lexer koa koa-static magic-string这些模块的功能是koa、koa-static 是vite内部使用的服务框架es-module-lexer 用于分析ES6import语法magic-string 用来实现重写字符串内容。2.基本结构搭建Vite需要搭建一个koa服务const Koa require(koa);function createServer() { const app new Koa(); const root process.cwd(); // 构建上下文对象 const context { app, root } app.use((ctx, next) { // 扩展ctx属性 Object.assign(ctx, context); return next(); }); const resolvedPlugins [ ]; // 依次注册所有插件 resolvedPlugins.forEach(plugin plugin(context)); return app;}createServer().listen(4000);3.Koa静态服务配置用于处理项目中的静态资源const {serveStaticPlugin} require(./serverPluginServeStatic);const resolvedPlugins [ serveStaticPlugin];const path require(path);function serveStaticPlugin({app,root}){ // 以当前根目录作为静态目录 app.use(require(koa-static)(root)); // 以public目录作为根目录 app.use(require(koa-static)(path.join(root,public)))}exports.serveStaticPlugin serveStaticPlugin;目的是让当前目录下的文件和public目录下的文件可以直接被访问4.重写模块路径const {moduleRewritePlugin} require(./serverPluginModuleRewrite);const resolvedPlugins [ moduleRewritePlugin, serveStaticPlugin];const { readBody } require(./utils);const { parse } require(es-module-lexer);const MagicString require(magic-string);function rewriteImports(source) { let imports parse(source)[0]; const magicString new MagicString(source); if (imports.length) { for (let i 0; i const { s, e } imports[i]; let id source.substring(s, e); if (/^[^\/\.]/.test(id)) { id /modules/${id}; // 修改路径增加 /modules 前缀 magicString.overwrite(s, e, id); } } } return magicString.toString();}function moduleRewritePlugin({ app, root }) { app.use(async (ctx, next) { await next(); // 对类型是js的文件进行拦截 if (ctx.body ctx.response.is(js)) { // 读取文件中的内容 const content await readBody(ctx.body); // 重写import中无法识别的路径 const r rewriteImports(content); ctx.body r; } });}exports.moduleRewritePlugin moduleRewritePlugin;对js文件中的 import 语法进行路径的重写改写后的路径会再次向服务器拦截请求读取文件内容const { Readable } require(stream)async function readBody(stream) { if (stream instanceof Readable) { // return new Promise((resolve, reject) { let res ; stream .on(data, (chunk) res chunk) .on(end, () resolve(res)); }) }else{ return stream.toString() }}exports.readBody readBody5.解析 /modules 文件const {moduleResolvePlugin} require(./serverPluginModuleResolve);const resolvedPlugins [ moduleRewritePlugin, moduleResolvePlugin, serveStaticPlugin];const fs require(fs).promises;const path require(path);const { resolve } require(path);const moduleRE /^\/modules\//; const {resolveVue} require(./utils)function moduleResolvePlugin({ app, root }) { const vueResolved resolveVue(root) app.use(async (ctx, next) { // 对 /modules 开头的路径进行映射 if(!moduleRE.test(ctx.path)){ return next(); } // 去掉 /modules/路径 const id ctx.path.replace(moduleRE,); ctx.type js; const content await fs.readFile(vueResolved[id],utf8); ctx.body content });}exports.moduleResolvePlugin moduleResolvePlugin;将/modules 开头的路径解析成对应的真实文件并返回给浏览器const path require(path);function resolveVue(root) { const compilerPkgPath path.resolve(root, node_modules, vue/compiler-sfc/package.json); const compilerPkg require(compilerPkgPath); // 编译模块的路径 node中编译 const compilerPath path.join(path.dirname(compilerPkgPath), compilerPkg.main); const resolvePath (name) path.resolve(root, node_modules, vue/${name}/dist/${name}.esm-bundler.js); // dom运行 const runtimeDomPath resolvePath(runtime-dom) // 核心运行 const runtimeCorePath resolvePath(runtime-core) // 响应式模块 const reactivityPath resolvePath(reactivity) // 共享模块 const sharedPath resolvePath(shared) return { vue: runtimeDomPath, vue/runtime-dom: runtimeDomPath, vue/runtime-core: runtimeCorePath, vue/reactivity: reactivityPath, vue/shared: sharedPath, compiler: compilerPath, }}编译的模块使用commonjs规范,其他文件均使用es6模块6.处理process的问题浏览器中并没有process变量所以我们需要在html中注入process变量const {htmlRewritePlugin} require(./serverPluginHtml);const resolvedPlugins [ htmlRewritePlugin, moduleRewritePlugin, moduleResolvePlugin, serveStaticPlugin];const { readBody } require(./utils);function htmlRewritePlugin({root,app}){ const devInjection app.use(async(ctx,next){ await next(); if(ctx.response.is(html)){ const html await readBody(ctx.body); ctx.body html.replace(//,$${devInjection}) } })}exports.htmlRewritePlugin htmlRewritePlugin在html的head标签中注入脚本7.处理.vue后缀文件const {vuePlugin} require(./serverPluginVue)const resolvedPlugins [ htmlRewritePlugin, moduleRewritePlugin, moduleResolvePlugin, vuePlugin, serveStaticPlugin];const path require(path);const fs require(fs).promises;const { resolveVue } require(./utils);const defaultExportRE /((?:^|\n|;)\s*)export default/function vuePlugin({ app, root }) { app.use(async (ctx, next) { if (!ctx.path.endsWith(.vue)) { return next(); } // vue文件处理 const filePath path.join(root, ctx.path); const content await fs.readFile(filePath, utf8); // 获取文件内容 let { parse, compileTemplate } require(resolveVue(root).compiler); let { descriptor } parse(content); // 解析文件内容 if (!ctx.query.type) { let code ; if (descriptor.script) { let content descriptor.script.content; let replaced content.replace(defaultExportRE, $1const __script ); code replaced; } if (descriptor.template) { const templateRequest ctx.path ?typetemplate code \nimport { render as __render } from ${JSON.stringify( templateRequest )}; code \n__script.render __render } ctx.type js code \nexport default __script; ctx.body code; } if (ctx.query.type template) { ctx.type js; let content descriptor.template.content; const { code } compileTemplate({ source: content }); ctx.body code; } })}exports.vuePlugin vuePlugin;在后端将.vue文件进行解析成如下结果import {reactive} from /modules/vue;const __script { setup() { let state reactive({count:0}); function click(){ state.count 1 } return { state, click } }}import { render as __render } from /src/App.vue?typetemplate__script.render __renderexport default __scriptimport { toDisplayString as _toDisplayString, createVNode as _createVNode, Fragment as _Fragment, openBlock as _openBlock, createBlock as _createBlock } from /modules/vueexport function render(_ctx, _cache) { return (_openBlock(), _createBlock(_Fragment, null, [ _createVNode(div, null, 计数器: _toDisplayString(_ctx.state.count), 1 /* TEXT */), _createVNode(button, { onClick: _cache[1] || (_cache[1] $event (_ctx.click($event))) }, ) ], 64 /* STABLE_FRAGMENT */))}解析后的结果可以直接在createApp方法中进行使用8.小结到这里基本的一个Vite就实现了。总结一下就是通过Koa服务实现了按需读取文件省掉了打包步骤以此来提升项目启动速度这中间包含了一系列的处理诸如解析代码内容、静态文件读取、浏览器新特性实践等等。其实Vite的内容远不止于此这里我们实现了非打包开发服务器那它是如何做到热更新的呢下次将手把手实现Vite热更新原理~历史好文推荐1、Vue3之——和Vite不得不说的事 2、大厂面试算法之斐波那契数列 3、2020字节跳动面试题一面解析 点个在看大家都看