前语
关于Vite和Vue3的评论越来越多,看了官网的特性后,真是按捺不住想测验一下。开发环境秒开?Composition API
? SFC Style CSS Variable Injection
? 看起来哪个都比webpack+Vue2香呀。(尤大都向React推荐Vite了,难道你还不试一下Vite么?)
其实在去年,咱们在LOFTER的哈利波特街区活动中就测验运用了Vite2 + Vue3建立活动主街区页面,当时对Vue3的语法还不是很适应,为啥ref要用value去取值?reactive解构后的呼应性怎么没了?Vite热更新咋不太灵光?为了确保活动页在Android6以下能满足基本交互需求,还引进了es6-proxy-polyfill
,友爱的提示用户体系不支撑。出于兼容性和稳定性的考虑,咱们没有在其他项目中运用。
时刻来到本年七月,跟着Vue2.7的正式发布,许多Vue3的编码特性被正式搬迁到了Vue2,更像是Vue3的根底试用版(Vue:再过18个月,我也懒得管Vue2了)。
The Composition API is backported using Vue 2’s getter/setter-based reactivity system to ensure browser compatibility.
便是官方的这句话,让我觉得把现在的Vue2项目彻底升到2.7是一件百利而无一害的工作。咱们的Vue2项目跟着事务迭代承载着愈加杂乱的事务场景,如何提高项目的开发体会也提上了日程。实际运用中,Vite仍是挺多坑要踩的,可是Vue2.7更新的内容,结合社区生态,对事务完成和开发体会的提高都提供了助力。
实战——查验Vite+Vue2.7
那就找个场景先预研一下吧,于是稻米节活动被拿来做了试验(希望不会被稻米看到)。
经过对官方文档的阅读,以及检查社区的评论,Vue2.7最次也是支撑option api的(假如遇到处理不了的bug降级一下写法就好了)。已然做试验,就要有试验目的。
- 查验SFC setup语法糖的各种写法兼容性
- 探究Vite现在开展的怎么样了
- 查验Vite出产环境的稳定性
先贴个定论,1和2的结果都挺好,3便是坑多多了。
试验流程:
项目建立
单纯的Vite Getting Started
流程实在是过于简单,啥装备都没有,难不成每个功能都要去搜索引擎查?还好有 awesome-vue 这个项目,集结了我们的才智(踩过的坑),参看了各种脚手架模板后,结合事务需求,项目架子初步搭好。
简单贴一下package.json
"dependencies": {
"@sentry/browser": "^5",
"@sentry/integrations": "^5", // sentry用来收集反常
"@vueuse/core": "^9.0.2", // 根据Composition API的东西函数,一起支撑Vue2, Vue3
"axios": "^0.27.2",
"nejsbridge": "^1.7.19",
……
"vue": "^2.7.8",
"vue-clipboard2": "^0.3.3",
"vue-router": "^3.5.4"
},
"devDependencies": {
"@antfu/eslint-config": "^0.25.2", // Anthony Fu是Vue和Vite团队的核心成员,有许多开源作品
"@vitejs/plugin-legacy": "^2.0.0", // 主动生成传统版别的chunk及与其相对应ES言语特性方面的polyfill
"@vitejs/plugin-vue2": "^1.1.2", // plugin only works with Vue@^2.7.0.
"autoprefixer": "^10.4.8",
"eslint": "^7.32.0",
"less": "^4.1.3",
"nei-ts-helper": "^0.1.3", // 组内接口生成TS声明的东西
"terser": "^5.4.0", // 出产环境打包代码需求
"typescript": "^4.6.4",
"unplugin-auto-import": "^0.10.1", // vue函数的主动导入
"unplugin-vue-components": "^0.21.2", // vue组件库的主动按需导入
"vite": "^3.0.4",
"vue-tsc": "^0.38.4"
}
重点推荐一下unplugin-auto-import
和unplugin-vue-components
。
unplugin-auto-import处理了vue3-hook、vue-router、useVue等多个插件的主动导入,也支撑自定义插件的主动导入,是一个功能强大的Typescript
支撑东西。根据unplugin,在构建和打包的时候主动解析模块并引进。
// vite.config.js
plugins: [
AutoImport({
imports: [
'vue',
'vue-router',
'@vueuse/core',
],
// 处理eslint报错问题
eslintrc: {
enabled: false,
globalsPropValue: true,
},
dts: 'src/auto-imports.d.ts',
}),
……
]
// ==> 主动生成大局声明 auto-imports.d.ts
declare global {
const asyncComputed: typeof import('@vueuse/core')['asyncComputed']
const autoResetRef: typeof import('@vueuse/core')['autoResetRef']
const computedAsync: typeof import('@vueuse/core')['computedAsync']
……
}
unplugin-vue-components支撑自定义组件主动引进,相同根据unplugin
// vite.config.js
plugins: [
Components({
transformer: 'vue2', // vue2.7必需
dirs: ['src/components'],
extensions: ['vue'],
dts: 'src/components.d.ts',
}),
……
]
// ==> 主动生成大局声明 auto-imports.d.ts
declare module '@vue/runtime-core' {
export interface GlobalComponents {
Container: typeof import('./components/Container.vue')['default']
Header: typeof import('./components/Header.vue')['default']
RouterLink: typeof import('vue-router')['RouterLink']
RouterView: typeof import('vue-router')['RouterView']
……
}
}
事务开发
- 运用插件后代码的书写简便了许多,格式愈加清爽,import理论上能够经过完善插件做到彻底消除。
<script setup>
import {
getNosThumbWebP,
} from '@/common/utils';
const props = defineProps(['blogNickName']);
const name = computed(() => (props.blogNickName ? `@${props.blogNickName}` : '你的'));
const bgUrl = `url(${getNosThumbWebP('', {
thumbnail: '1125x0',
})})`;
</script>
<template>
<div class="header">
<div class="user-name">{{name}}</div>
</div>
</template>
<style scoped lang="less">
.header {
width: 100%;
height: 1333px;
background-image: v-bind(bgUrl);
background-size: 100% 100%;
background-repeat: no-repeat;
position: relative;
.user-name {
……
}
}
</style>
- SFC Style CSS Variable Injection,力荐的style办理方案。能够完成JS和CSS的通信与样式的呼应式更新,在主题切换场景中运用非常便利。具体能够检查
Vue3 的 SFC Style CSS Variable Injection 提案完成的背后
留意:v-bind作用的元素假如有v-if
的场景,最好不是template
里的根元素,否则可能导致css变量无处挂载。
- setup语法糖,自己用了才知道,真的好用。还需求在更杂乱的事务场景中实践,结合相似
vueuse
的用法做逻辑封装。 - 热更新经常无效,
Vue.extend(ToastConfig)
创建的组件彻底不会更新,需求重启dev server才行。
打包测验
- 踩过坑才知道下面这部分内容有多重要
- 构建出产版别-浏览器兼容性
- 用于出产环境的构建包会假定方针浏览器支撑现代 JavaScript 语法。默许状况下,Vite 的方针是能够 支撑
原生 ESM script 标签
、支撑原生 ESM 动态导入
和import.meta
的浏览器:- 你也能够经过 build.target 装备项 指定构建方针,最低支撑 es2015。
- 请留意,默许状况下 Vite 只处理语法转译,且 默许不包括任何 polyfill。你能够前往 Polyfill.io 检查,这是一个根据用户浏览器 User-Agent 字符串主动生成 polyfill 包的服务。
- 传统浏览器能够经过插件
@vitejs/plugin-legacy
来支撑,它将主动生成传统版别的 chunk 及与其相对应 ES 言语特性方面的 polyfill。兼容版的 chunk 只会在不支撑原生 ESM 的浏览器中进行按需加载。
// 经过监测支撑import.meta.url和动态引进判断是否为现代浏览器
<script type="module">try{
import.meta.url;
import("_").catch(()=>1);
}catch(e){}
window.__vite_is_modern_browser=true;
</script>
<script type="module">!function(){
if(window.__vite_is_modern_browser)return;
console.warn("vite: loading legacy build because dynamic import or import.meta.url is unsupported, syntax error above should be ignored");
var e=document.getElementById("vite-legacy-polyfill"),n=document.createElement("script");n.src=e.src,n.onload=function(){System.import(document.getElementById('vite-legacy-entry').getAttribute('data-src'))},document.body.appendChild(n)
}();</script>
线上的一个白屏问题,发现报错源自try{}catch{}
这种ES10才支撑的语法。
vite3修正了默许的打包装备,仅支撑Chrome >=87。需求经过修正build: target提高构建产品的兼容性。
- _VITE_ASSET legacy.js打包的css相对途径不对,全换成cdn资源处理(最新版vite已修复该问题)。
暂没有遇到其他兼容性问题。
进阶——将一个重度Webpack+Vue2工程升级为Vite+Vue2.7
LOFTER阛阓工程用webpack的重度体现在
- 一套dev+build+init命令行交互
- 自定义页面参数装备,结合HtmlWebpackPlugin形成动态页面装备,HtmlWebpackPlugin确实是多页运用构建的神器
- 有些年头的css,babel装备
- 私有的webpack插件,离线包插件等
这些要么移除掉,要么在Vite中找到替代方案。
开始升级。。。
- 安装
vite
,vue2.7
,@vitejs/plugin-vue2
,@vitejs/plugin-legacy
去掉vue-template-compiler
- 增加
vite.config.js
,装备alias
,less
,vite会默许按root
装备的文件目录,主动查找文件目录下的index.html
,页面模板中增加代码
<script type="module" src="/cardHome/index.js"></script>
然后便是疯狂报错
- require url问题
vue.runtime.esm.js:4573 [Vue warn]: Error in created hook: "ReferenceError: require is not defined"
import.meta.url 是一个 ESM 的原生功能,会露出当前模块的 URL。将它与原生的 URL 构造器 组合运用,在一个 JavaScript 模块中,经过相对途径咱们就能得到一个被完好解析的静态资源 URL
// icon: require('@/common/images/card/upgrade/home.png') =>
icon: new URL('@/common/images/card/upgrade/home.png', import.meta.url).href
- svg 雪碧图插件替换,
svg-sprite-loader
->vite-plugin-svg-icons
symbolId的拼装方式不同,stroke color替换后者有问题,暂时能够经过样式掩盖处理
- css-loader中
@value
的用法在vite中不支撑,能够运用less变量的方式替换,不大局运用css变量一个是兼容性,还有是阛阓自身颜色不需求切换
/* @value --default_common_bg_tertiary: #3E3E3E; */
@default_common_bg_tertiary: #3E3E3E;
/* background: --default_common_bg_tertiary; */
background: @default_common_bg_tertiary;
- 运用HTTP2,能够装备
server.https
来启用,像卡牌主页的代码模块许多,经过H2能够改进恳求量大导致的页面刷新耗时较长的问题。可是
留意:当 server.proxy 选项 也被运用时,将会仅运用 TLS。
这会导致假如装备了接口代理的状况下项目又用不了H2了。
能够运用nginx
处理该问题,最新版nginx(1.22.0)
支撑装备listen 443 ssl http2;
结合server.https
和base
装备的途径,能够完成在开发环境下运用H2加快页面刷新。
Webpack与Vite开发环境比较
根据win10,i5-6500 CPU,16.0 GB内存
webpack devtool: ‘cheap-module-eval-source-map’, |
vite 便于比较,运用http/1.1 |
|
---|---|---|
无缓存run dev | 悉数40s 主页+背包24s |
暂无悉数数据 主页+背包3s+,需求更长烘托时刻 |
有缓存run dev | 悉数30s 主页+背包18s |
暂无悉数数据 主页+背包3s- |
热更新 | 主页7s左右 | 无提示,看起来很快,有时候改了组件代码刷新也没用,只能重新run dev |
背包页无缓存刷新 | 38 requests 3.1 MB transferred 12.7 MB resources Finish: 5.44 s DOMContentLoaded: 1.79 s Load: 2.52 s |
191 requests 3.7 MB transferred 3.7 MB resources Finish: 3.49 s DOMContentLoaded: 1.81 s Load: 3.46 s |
背包页有缓存刷新 | 34 requests 12.6 kB transferred 12.7 MB resources Finish: 1.99 s DOMContentLoaded: 1.20 s Load: 1.91 s |
191 requests 446 kB transferred 3.7 MB resources Finish: 3.02 s DOMContentLoaded: 1.48 s Load: 2.99 s |
主页无缓存刷新 | 82 requests 20.1 MB transferred 38.0 MB resources Finish: 5.55 s DOMContentLoaded: 2.57 s Load: 4.35 s |
278 requests 20.8 MB transferred 24.9 MB resources Finish: 4.84 s DOMContentLoaded: 2.46 s Load: 4.42 s |
主页有缓存刷新 | 81 requests 120 kB transferred 38.0 MB resources Finish: 3.39 s DOMContentLoaded: 1.82 s Load: 3.09 s |
278 requests 557 kB transferred 24.4 MB resources Finish: 3.88 s DOMContentLoaded: 1.92 s Load: 3.15 s |
- 比较1:在运用esm的状况下,页面的烘托速度并没有显著提高,运用H2或加强模块异步加载的处理睬稍微好点。
在实际项目中,Rollup 通常会生成 “共用” chunk
Vite 将运用一个预加载过程主动重写代码,来分割动态导入调用,以完成当 A 被恳求时,C 也将 一起 被恳求:
Entry —> (A + C)
C 也可能有更深的导入,在未优化的场景中,这会导致更多的网络往复。Vite 的优化会跟踪所有的直接导入,不管导入的深度如何,都能够彻底消除不必要的往复。
- 比较2:esm会发出更多的requests,浏览器等待耗时显着,偶然可能会堵塞导致更长的烘托时刻
- 比较3:Vite热更新不抱负,需求经常刷新或许重启,重启dev尽管很快,可是页面烘托等待耗时可能较长
关于vite的热更新:
Vite 经过特殊的 import.meta.hot 对象露出手动 HMR API。
Vite 热更新问题排查
能够监听自定义 HMR 事件,在插件中处理未更新的状况
还有一些运用场景进一步实践后再和我们分享。
一些感想:
- Vite更像是一个上层建筑,集合了esbuild,rollup,各种loader等,假如项目比较杂乱,依然需求深度定制,逃不开装备的递归运用。
- 新项目仍是很推荐用Vite构建,直接运用Vite和rollup的生态。
- 老项目从webpack搬迁仍是缺少一些完备的插件,也是为社区贡献的机会,开发环境Vite出产环境webpack理论上是可行的,需求处理两者之间的差异,比如环境变量,插件的差异等等。开发环境和出产环境的构建方式不同总感觉会有坑,仍是需求慎重。