Vite 是什么
2020/5/1 5:02:43
本文主要是介绍Vite 是什么,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
本文基于 vite@0.7.0 编写,可能与目前代码不符,如有疑问欢迎邮件或评论沟通
什么是 vite
vite 是一个基于 Vue3 单文件组件的非打包开发服务器
这和传统基于打包(例如 Webpack)的开发服务器有什么区别
vite 在开发的时候没有打包的过程,ES 模块源码直接传输给浏览器,浏览器使用自带的 <script module>
进行解析支持,通过 HTTP 请求进行每次 import,开发服务器拦截请求和对需要转换的代码进行转换。
例如:*.vue
文件会在发回浏览器之前进行编译
这样操作有许多优势:
- 开发服务器启动后不需要进行打包操作,启动会变得非常迅速
- 代码在需要的时候进行编译,所以只有代码真正在屏幕上展现的时候才进行编译。开始开发的时候再也不需要等待整个应用编译完成,这对大型应用是一个巨大的改变
- 热模块替换的性能和模块的数量之间的关系解耦,热模块替换变得非常快
导入本地 ES 模块可能会引发深层的导入链路,整个页面重新加载会比依赖打包的开发服务器略慢。然而这是一个本地开发服务器,这部分增加的时间和实际编译的时间相比应该非常小(编译的文件会被缓存在内存中)
vite 的编译本质上还是的 Node.js 中进行,从技术上讲它可以支持打包工具能支持的各种代码转换,没有什么可以阻止你将代码包用于生产,实际上,vite 提供了vite build
的脚本用于这个操作,因此不会在生产环境中遭遇到网络流爆炸的问题
当前 vite 尚处于实验性阶段,不适合用于生产环境,但希望有一天能做到这个目标
特性
模块解析
本地 ES 模块导入不支持如下的导入方式
import { createApp } from 'vue'
默认情况下将会导致一个错误,vite 在 js 文件中检测到这种情况将会将其改写为@modules/{package-name}
,在这些特殊的路径下,vite 执行以下的方式找到正确的文件
-
vue
有特殊的处理,你不需要安装这个模块,如果需要使用特殊的版本,vite 将会使用node_modules
内部的模块包 - 如果
web_modules
目录存在,将会使用它 - 如果其它方式都没有定位到模块,将会在
node_modules
中查找
热模块替换
- 对于
*.vue
文件将会得到开箱即用的替换功能 - 对于
*.js
需要提供类似于 webpack HMR 的 API
import { foo } from "./foo.js"; import { hot } from "@hmr"; foo(); hot.accept("./foo.js", ({ foo }) => { // the callback receives the updated './foo.js' module foo(); });
CSS 预处理器
安装模块即可在 *.vue
中使用
<style lang="scss"> /* use scss */ </style>
生产构建
执行 vite build
,当前支持 --root
和 --cdn
两个参数
API
可以使用 API 定制开发服务器,vite 支持插件形式扩展,可以定制化访问 vite 内部的 koa 实例和增加相关的中间件
下一步开发计划
- Source Map 支持
- 自动加载 postcss 配置
解析
启动一个 vite 开发服务器
-
http://localhost:3000/
首屏页面
<div id="app"></div> <script type="module"> import { createApp } from "/@modules/vue"; // 此模块中包含相关热加载逻辑 import App from "./App.vue"; // 此文件为SFC主模板 createApp(App).mount("#app"); // 渲染模版 </script>
-
http://localhost:3000/App.vue
主模板
import { updateStyle } from "/@hmr"; // 加载更新style方法 const __script = { data: () => ({ count: 0 }) }; updateStyle("c44b8200-0", "/App.vue?type=style&index=0"); __script.__scopeId = "data-v-c44b8200"; import { render as __render } from "/App.vue?type=template"; // 加载template模板 __script.render = __render; __script.__hmrId = "/App.vue"; __script.__file = "/Users/shoyuf/work/vite-app/App.vue"; export default __script;
-
/@hmr
更新逻辑
console.log("[vite] connecting..."); const socket = new WebSocket(`ws://${location.host}`); // Listen for messages socket.addEventListener("message", ({ data }) => { const { type, path, id, index, timestamp } = JSON.parse(data); switch (type) { case "connected": // 连接成功 console.log(`[vite] connected.`); break; case "vue-reload": // 当script改变的情况下,需要重新加载 import(`${path}?t=${timestamp}`).then(m => { __VUE_HMR_RUNTIME__.reload(path, m.default); console.log(`[vite] ${path} reloaded.`); }); break; case "vue-rerender": // 当template改变的情况下,需要重新渲染 import(`${path}?type=template&t=${timestamp}`).then(m => { __VUE_HMR_RUNTIME__.rerender(path, m.render); console.log(`[vite] ${path} template updated.`); }); break; case "vue-style-update": // 当css改变情况下更新style updateStyle(id, `${path}?type=style&index=${index}&t=${timestamp}`); console.log( `[vite] ${path} style${index > 0 ? `#${index}` : ``} updated.` ); break; case "vue-style-remove": // css改变后移除旧的css引用 const link = document.getElementById(`vite-css-${id}`); if (link) { document.head.removeChild(link); } break; case "js-update": // js 模块更新重新加载 const update = jsUpdateMap.get(path); if (update) { update(timestamp); console.log(`[vite]: js module reloaded: `, path); } else { console.error( `[vite] got js update notification but no client callback was registered. Something is wrong.` ); } break; case "full-reload": // 导入链进入死胡同,需要进行页面重新加载 location.reload(); } }); // ping server socket.addEventListener("close", () => { console.log(`[vite] server connection lost. polling for restart...`); setInterval(() => { new WebSocket(`ws://${location.host}`).addEventListener("open", () => { location.reload(); }); }, 1000); }); export function updateStyle(id, url) { const linkId = `vite-css-${id}`; let link = document.getElementById(linkId); if (!link) { link = document.createElement("link"); link.id = linkId; link.setAttribute("rel", "stylesheet"); link.setAttribute("type", "text/css"); document.head.appendChild(link); } link.setAttribute("href", url); } const jsUpdateMap = new Map(); export const hot = { accept(importer, deps, callback) { jsUpdateMap.set(importer, timestamp => { if (Array.isArray(deps)) { Promise.all(deps.map(dep => import(dep + `?t=${timestamp}`))).then( callback ); } else { import(deps + `?t=${timestamp}`).then(callback); } }); } };
-
/App.vue?type=template
主模板 HTML 部分
import { createVNode as _createVNode, toDisplayString as _toDisplayString, Fragment as _Fragment, openBlock as _openBlock, createBlock as _createBlock, withScopeId as _withScopeId, pushScopeId as _pushScopeId, popScopeId as _popScopeId } from "/@modules/vue"; const _withId = _withScopeId("data-v-c44b8200"); _pushScopeId("data-v-c44b8200"); const _hoisted_1 = _createVNode( // 创建Virtual DOM "h1", null, "Hello Vite + Vue 3!", -1 /* HOISTED */ ); const _hoisted_2 = _createVNode( "p", null, "Edit ./App.vue to test hot module replacement (HMR).", -1 /* HOISTED */ ); _popScopeId(); export const render = _withId(function render(_ctx, _cache) { // 渲染函数 return ( _openBlock(), _createBlock( _Fragment, null, [ _hoisted_1, _hoisted_2, _createVNode("p", null, [ _createVNode( "span", null, "Count is: " + _toDisplayString(_ctx.count), 1 /* TEXT */ ), _createVNode( "button", { onClick: _cache[1] || (_cache[1] = $event => _ctx.count++) }, "increment" ) ]) ], 64 /* STABLE_FRAGMENT */ ) ); });
-
/App.vue?type=style&index=0
主模板 css 部分,包括 scopedId
h1[data-v-c44b8200] { color: #4fc08d; } h1[data-v-c44b8200], p[data-v-c44b8200] { font-family: Arial, Helvetica, sans-serif; }
-
ws://localost:3000/
执行热替换的数据交互,与/@hmr
相联
Example:
{ path: "/App.vue", timestamp: 1588242356511, type: "vue-reload" }
type 与@hmr
的相关方法一致
- vue-reload
- vue-rerender
- vue-style-update
- vue-style-remove
- js-update
- full-reload
webpack 很慢
参考
- vuejs/vite: Experimental no-bundle dev server for Vue SFCs
这篇关于Vite 是什么的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-10-05HTML 颜色
- 2024-10-05HTML 颜色名
- 2024-10-01AntDesign-Form-rules学习:轻松入门教程
- 2024-10-01classnames学习:轻松掌握前端中的类名管理
- 2024-09-30前端案例资料:新手入门必读教程
- 2024-09-30前端编程资料:新手入门必备教程
- 2024-09-30前端培训资料:新手入门必读教程
- 2024-09-30滚动吸顶项目实战:从入门到上手
- 2024-09-29HTML学习:span标签教程详解
- 2024-09-29HTML基础:button标签教程