小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。
vite发展到现在,整个生态规模已经有了一定的基础,本来想对工作中用到的项目从vue2多页应用直接升级为vue3+ts的技术架构,但调研后发现vue3不支持Android5,着实让人头秃。还好经过调研发现vite是可以支持vue2项目的开发的,而开发环境不用考虑浏览器兼容性,于是开搞。
需要用到的vite插件:
vite-plugin-imp !项目中用到组件库往往需要,用于配置自动引入组件库的样式文件
vite-plugin-eslint !非必需,是为了方便代码格式统一引入的插件
vite-plugin-virtual-html !多页仓库需要的包,可以在保持目录不变的情况下跟用webpack开发用同样的路径。
vite-plugin-vue2 !这个是必须用的插件,是vite打包Vue2组件的工具
vite基础
vite原理相关的文章很多,我也不再把别的解释搬运过来了,可以在掘金上输入相关的关键字搜索。这里我只想强调已有的Vue2项目改造vite开发所需要注意的关键几个点:
- vite项目开发,整个项目中引用的外部包格式必须是esm的,如果有些库没有导出esm格式,可能要先行解决下。
- 使用vite开发,注意老项目里面如果有 process.env 相关的写法,要注意改一下,会报错,原因是vite的开发环境并没有对这类变量做替换,这个运行时变量替换的事情是之前webpack做的。
- 如果是vite开发,webpack打包的话,需要注意开发完成后尽量早的打包尝试,避免工具不一致导致预料之外的问题。
改造步骤
比如现在已经有一个vue2的仓库,是多页应用的那种,入口文件在 src/pages/**/*.html, 需要改造成vite开发,要怎么做呢?莫慌,跟着下面的步骤来:
- 使用yarn安装 vite 和前面提到的4个vite插件
- 在package.json中声明vite启动命令, 如: vite: "cross-env vite"
- 在项目根目录添加 vite.config.js, 配置上四个插件的config,然后把webpack devserver 相关项迁移配置一下(如开发端口/proxy的接口等等)
- yarn vite 愉快开发
重点说一下vite-plugin-virtual-html这个插件,这个插件的功能是通过vite server中间件做了一些事情,用于复写资源请求路径并对html文件做了预处理,核心是判断html文件里面是否有js引入的标签,如果没有则在vite开发启动前自动注入与html文件同路径下的 js|ts 文件的module引入,这里存在个问题是,我的html文件模板里面很可能有引入一些外部sdk的script语句,这样会让注入失效。
为了解决这个问题,我对插件做了点修改,判断html文件是否有script标签这里加上了对 type="module" 的限制,因为平时我们写html模板里面的引用语句肯定不会用esm的格式引入。这样一个改动之后就可以保证模板在webpack打包和vite开发上都是完全兼容的,完美~
针对环境变量 process.env.MODE 之类的环境判断变量,我这里是这么改造的:
import online from './online'
import test from './test'
import dev from './dev'
let ENV = ''
try {
ENV = process.env.WINDOW_ENV
} catch (e) {
ENV = 'dev'
}
const config = (() => {
switch (ENV) {
case 'online':
case 'wechat_test':
return online
case 'test':
return test
case 'dev':
return dev
default:
return dev
}
})()
主要思路就是通过try...catch..来保证运行时不报错,由于vite只用于开发环境,所以在catch中就不再另行用import.meta 下的变量进行判断了。
听起来很简单是不是,不过第三步其实远没有描述的这么简单,我下面准备简单贴一下配置(业务相关的已隐藏),并对一些关键配置写注释解释一下,每一项配置都是踩坑踩过来。
vite配置详解
// vite.config.js
import path from 'path'
import glob from 'glob'
import { defineConfig } from 'vite'
import { createVuePlugin } from 'vite-plugin-vue2'
import vitePluginImp from 'vite-plugin-imp'
import eslintPlugin from 'vite-plugin-eslint';
import virtualHtml from './buildPlugin/vite-plugin-virtual-html'
// 常量配置
const VITE_APP_PORT = 3000
const VITE_APP_HOST = 'localhost'
const VITE_APP_PATH = './'
const TEMPLATE_PATH = './src/pages/**/*.html'
// 生成多页page入口配置
function getHtmls() {
const entries = {}
glob.sync(TEMPLATE_PATH).forEach(function(entry) {
const basename = path.basename(entry, path.extname(entry))
entries[basename] = entry.slice(1) // 相对路径改成绝对路径
})
return entries
}
const plugins = [
createVuePlugin(/* options */),
virtualHtml({
pages: getHtmls(),
indexPage: 'index'
}),
vitePluginImp(
[{
libName: 'vant',
style(name) {
if (/CompWithoutStyleFile/i.test(name)) {
// This will not import any style file
return false
}
return `vant/es/${name}/style/index.js`
}
}
]),
eslintPlugin({ include: '**/*.+(vue|js|jsx|ts|tsx)' }),
// 如果校验css的话,会有很多奇怪的报错
]
export default defineConfig({
base: VITE_APP_PATH
plugins,
server: {
port: VITE_APP_PORT,
host: VITE_APP_HOST,
open: '/index.html',
cors: true,
proxy: {
'^/.*api/.*': {
target: '', //根据自己业务填写
changeOrigin: true,
secure: false
}
}
},
resolve: {
// 类型: string[]
// 默认: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json']
// 导入时想要省略的扩展名列表。如果之前import语句对于vue类型文件没带上.vue 则需要加上'.vue'
extensions: ['.js', '.vue', '.json'],
alias: {
'@': resolve('src'),
vue$: 'vue/dist/vue.esm.js'
}
}
})
后续工作与展望
- 项目添加引入 @vue/composition-api 推行类Vue3的开发体验
- 借用vite,尝试使用rollup进行打包处理,从而完全避开Webpack的配置,也使得项目中针对环境的判断统一化