大家好!
文本是为了提升开发效率及体验实践诞生的。
项目背景:
脚手架:vue-cli3,具体为 "@vue/cli-service": "^3.4.1"
库:vue2,具体为:"vue": "2.6.12"
备注:没有 typescript , 非 ssr
痛点:随着时间的推移、业务的不断迭代,依赖、功能、代码越来越多,项目本地启动比较慢、开发热更新比较慢。
改进目标:保留原来的 webpack, 支持 vite。并且尽可能的减少改动,减少维护成本。
考虑:
vite 生产环境用的是 rollup,rollup 更适合打包库。
vite 打包提效并没有提供太多。
保留原来的 webpack 方式,尽可能的保证生产的稳定与安全。
实践
主要是处理三方面:
配置文件需根据 vue.config.js
增加 vite.config.js
入口文件 index.html
支持 vite 的方式
配置 vite 启动命令
可能需要
解决 commonjs 与 esModule 的引入与混用
增加 vite.config.js
在项目根目录创建一个 vite.config.js
安装所需依赖
npm i vite vite-plugin-vue2 -D
根据 vue.config.js
在 vite.config.js
中增加对应配置
// 若改了该文件逻辑,请对照着改一下 vue.config.jsimport path from 'path'
import fs from 'fs'
import { defineConfig } from 'vite'
import config from './config'
import { createVuePlugin } from 'vite-plugin-vue2'
import { injectHtml } from 'vite-plugin-html'
const resolve = dir => path.join(__dirname, dir)
const alias = {
vue: 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
const publicPath = '/'
const mode = 'development'
// https://vitejs.dev/config/
export default defineConfig({
base: publicPath,
plugins: [
createVuePlugin(),
],
// 这些是注入项目中的变量,若有 process 开头的,都需要在这儿注入,vite 默认不会注入 process 相关的变量及值
define: {
'process.env.NODE_ENV': JSON.stringify(mode),
'process.env.publicPath': JSON.stringify(publicPath),
},
resolve: {
// 配置别名
alias,
// 导入时想要省略的扩展名列表,必须加入.vue,因为 vite 默认不支持省略 .vue 后缀
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
},
server: {
// 允许跨域
cors: true,
proxy: {
// 可直接拷贝 vue.config.js 中对应的 proxy
}
}
})
sass 相关
配置特殊说明:若项目中有用是 sass
预处理器, 且用到变量了。
需要安装 [email protected],不能安装比 1.32
更高的版本,跟高版本存在这个问题Sass报错: Using / for division is deprecated
npm i [email protected] -D
export default defineConfig({ ...
css: {
// 给 sass 传递选项
preprocessorOptions: {
scss: {
charset: false, // 最新版sass才支持
additionalData: `@import "src/sass/common/var.scss";`,
}
},
},
...
})
备注:如果生产环境用 vite 打包,采用 [email protected]
将会遇到这个问题vite2打包出现警告,"@charset" must be the first,该如何消除呢?,但是 [email protected]
不支持文档中的配置。所以这可以算是生产环境不用 vite 的一个原因。
还需全局替换 /deep/
为 ::v-deep
入口文件 index.html
支持 vite 的方式
由于 vite 的项目要求 index.html 文件在根目录,且有入口文件配置。
所以将 index.html 从 public 目录移到根目录。并加入
<% if (typeof isVite === 'boolean' && isVite) { %> <script type="module" src="/src/main.js"></script>
<% } %>
这样配置是为了能让 webpack、vite 方式都都支持,共用一个文件
而为了在 index.html 文件注入 isVite
变量,需要安装
npm i vite-plugin-html -D
需要在 vite.config.js
中配置
...import { injectHtml } from 'vite-plugin-html'
export default defineConfig({
...
plugins: [
...
injectHtml({
data: {
title: 'vite-plugin-html-example',
isVite: true
},
}),
],
define: {
'process.env.isVite': JSON.stringify(true)
},
...
})
配置 vite 启动命令
最后在 package.json
中增加脚本
"scripts": { "vite-start": "vite"
}
路由懒加载,vite 需要特殊处理
vue 实现路由懒加载的方式是这样的
const Home = import(/* webpackChunkName: "[home]" */ `@/page/home.vue`) const routes = [
{
path: `/home`,
name: 'home',
component: Home
},
]
但是 vite 不支持,解决
const modules = import.meta.glob('@/page/*.vue')const Home = modules['@/page/home.vue']
// 若改了该文件逻辑,请对照着改一下 vue.config.jsimport path from 'path'
import fs from 'fs'
import { defineConfig } from 'vite'
import config from './config'
import { createVuePlugin } from 'vite-plugin-vue2'
import { injectHtml } from 'vite-plugin-html'
const resolve = dir => path.join(__dirname, dir)
const alias = {
vue: 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
const publicPath = '/'
const mode = 'development'
// https://vitejs.dev/config/
export default defineConfig({
base: publicPath,
plugins: [
createVuePlugin(),
],
// 这些是注入项目中的变量,若有 process 开头的,都需要在这儿注入,vite 默认不会注入 process 相关的变量及值
define: {
'process.env.NODE_ENV': JSON.stringify(mode),
'process.env.publicPath': JSON.stringify(publicPath),
},
resolve: {
// 配置别名
alias,
// 导入时想要省略的扩展名列表,必须加入.vue,因为 vite 默认不支持省略 .vue 后缀
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
},
server: {
// 允许跨域
cors: true,
proxy: {
// 可直接拷贝 vue.config.js 中对应的 proxy
}
}
})
0
参考:vite-Glob 导入
所以可封装一下:
// 若改了该文件逻辑,请对照着改一下 vue.config.jsimport path from 'path'
import fs from 'fs'
import { defineConfig } from 'vite'
import config from './config'
import { createVuePlugin } from 'vite-plugin-vue2'
import { injectHtml } from 'vite-plugin-html'
const resolve = dir => path.join(__dirname, dir)
const alias = {
vue: 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
const publicPath = '/'
const mode = 'development'
// https://vitejs.dev/config/
export default defineConfig({
base: publicPath,
plugins: [
createVuePlugin(),
],
// 这些是注入项目中的变量,若有 process 开头的,都需要在这儿注入,vite 默认不会注入 process 相关的变量及值
define: {
'process.env.NODE_ENV': JSON.stringify(mode),
'process.env.publicPath': JSON.stringify(publicPath),
},
resolve: {
// 配置别名
alias,
// 导入时想要省略的扩展名列表,必须加入.vue,因为 vite 默认不支持省略 .vue 后缀
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
},
server: {
// 允许跨域
cors: true,
proxy: {
// 可直接拷贝 vue.config.js 中对应的 proxy
}
}
})
1
但是 webpack 不支持 import.meta,需要 loader 处理。解决:在本地建一个文件 webpack-import-meta-loader.js。
// 若改了该文件逻辑,请对照着改一下 vue.config.jsimport path from 'path'
import fs from 'fs'
import { defineConfig } from 'vite'
import config from './config'
import { createVuePlugin } from 'vite-plugin-vue2'
import { injectHtml } from 'vite-plugin-html'
const resolve = dir => path.join(__dirname, dir)
const alias = {
vue: 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
const publicPath = '/'
const mode = 'development'
// https://vitejs.dev/config/
export default defineConfig({
base: publicPath,
plugins: [
createVuePlugin(),
],
// 这些是注入项目中的变量,若有 process 开头的,都需要在这儿注入,vite 默认不会注入 process 相关的变量及值
define: {
'process.env.NODE_ENV': JSON.stringify(mode),
'process.env.publicPath': JSON.stringify(publicPath),
},
resolve: {
// 配置别名
alias,
// 导入时想要省略的扩展名列表,必须加入.vue,因为 vite 默认不支持省略 .vue 后缀
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
},
server: {
// 允许跨域
cors: true,
proxy: {
// 可直接拷贝 vue.config.js 中对应的 proxy
}
}
})
2
vue.config.js 修改配置:
// 若改了该文件逻辑,请对照着改一下 vue.config.jsimport path from 'path'
import fs from 'fs'
import { defineConfig } from 'vite'
import config from './config'
import { createVuePlugin } from 'vite-plugin-vue2'
import { injectHtml } from 'vite-plugin-html'
const resolve = dir => path.join(__dirname, dir)
const alias = {
vue: 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
const publicPath = '/'
const mode = 'development'
// https://vitejs.dev/config/
export default defineConfig({
base: publicPath,
plugins: [
createVuePlugin(),
],
// 这些是注入项目中的变量,若有 process 开头的,都需要在这儿注入,vite 默认不会注入 process 相关的变量及值
define: {
'process.env.NODE_ENV': JSON.stringify(mode),
'process.env.publicPath': JSON.stringify(publicPath),
},
resolve: {
// 配置别名
alias,
// 导入时想要省略的扩展名列表,必须加入.vue,因为 vite 默认不支持省略 .vue 后缀
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
},
server: {
// 允许跨域
cors: true,
proxy: {
// 可直接拷贝 vue.config.js 中对应的 proxy
}
}
})
3
解决 commonjs 与 esModule 的引入与混用
混用
webpack 方式下,若你的 src 项目源码中存在混用 commonjs 与 esModule。
方案一:不改源码,在 vite.config.js 中加配置,把 commonjs 转换为 esModule
安装 npm i cjs2esmodule -D
在 vite.config.js 中加配置
// 若改了该文件逻辑,请对照着改一下 vue.config.jsimport path from 'path'
import fs from 'fs'
import { defineConfig } from 'vite'
import config from './config'
import { createVuePlugin } from 'vite-plugin-vue2'
import { injectHtml } from 'vite-plugin-html'
const resolve = dir => path.join(__dirname, dir)
const alias = {
vue: 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
const publicPath = '/'
const mode = 'development'
// https://vitejs.dev/config/
export default defineConfig({
base: publicPath,
plugins: [
createVuePlugin(),
],
// 这些是注入项目中的变量,若有 process 开头的,都需要在这儿注入,vite 默认不会注入 process 相关的变量及值
define: {
'process.env.NODE_ENV': JSON.stringify(mode),
'process.env.publicPath': JSON.stringify(publicPath),
},
resolve: {
// 配置别名
alias,
// 导入时想要省略的扩展名列表,必须加入.vue,因为 vite 默认不支持省略 .vue 后缀
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
},
server: {
// 允许跨域
cors: true,
proxy: {
// 可直接拷贝 vue.config.js 中对应的 proxy
}
}
})
4
如果这个方案,能让你的项目运行正常。否则,可能需要采用方案二。
方案二:把 src 代码中的 commonjs 语法自己手动改为 esModule
引入
如果你的项目在有一个 config.js, 被 vue.config.js 中使用。那么你可能需要处理。
vue.config.js 必须是 commonjs 语法的文件,才能被使用,否则会报错。
vite.config.js 既可以 esModule 语法,也可以 commonjs 语法。默认是 esModule 语法。
若上面混用,你是采用方案二,而且 src 代码中也用了 config.js。那么你只能把 config.js 改成 esModule 的方式。此时 vue.config.js 不支持了,采用的方案是根据 config.js 自动生成一个 config-cjs.js。
目的是减少后期维护成本。
// 若改了该文件逻辑,请对照着改一下 vue.config.jsimport path from 'path'
import fs from 'fs'
import { defineConfig } from 'vite'
import config from './config'
import { createVuePlugin } from 'vite-plugin-vue2'
import { injectHtml } from 'vite-plugin-html'
const resolve = dir => path.join(__dirname, dir)
const alias = {
vue: 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
const publicPath = '/'
const mode = 'development'
// https://vitejs.dev/config/
export default defineConfig({
base: publicPath,
plugins: [
createVuePlugin(),
],
// 这些是注入项目中的变量,若有 process 开头的,都需要在这儿注入,vite 默认不会注入 process 相关的变量及值
define: {
'process.env.NODE_ENV': JSON.stringify(mode),
'process.env.publicPath': JSON.stringify(publicPath),
},
resolve: {
// 配置别名
alias,
// 导入时想要省略的扩展名列表,必须加入.vue,因为 vite 默认不支持省略 .vue 后缀
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
},
server: {
// 允许跨域
cors: true,
proxy: {
// 可直接拷贝 vue.config.js 中对应的 proxy
}
}
})
5
然后在 vue.config.js 原来引入的 config.js 的地方改为 config-cjs.
最后在 package.json
中改变下脚本,每次都重新生成一个最新的配置。
// 若改了该文件逻辑,请对照着改一下 vue.config.jsimport path from 'path'
import fs from 'fs'
import { defineConfig } from 'vite'
import config from './config'
import { createVuePlugin } from 'vite-plugin-vue2'
import { injectHtml } from 'vite-plugin-html'
const resolve = dir => path.join(__dirname, dir)
const alias = {
vue: 'vue/dist/vue.esm.js',
'@': resolve('src'),
}
const publicPath = '/'
const mode = 'development'
// https://vitejs.dev/config/
export default defineConfig({
base: publicPath,
plugins: [
createVuePlugin(),
],
// 这些是注入项目中的变量,若有 process 开头的,都需要在这儿注入,vite 默认不会注入 process 相关的变量及值
define: {
'process.env.NODE_ENV': JSON.stringify(mode),
'process.env.publicPath': JSON.stringify(publicPath),
},
resolve: {
// 配置别名
alias,
// 导入时想要省略的扩展名列表,必须加入.vue,因为 vite 默认不支持省略 .vue 后缀
extensions: ['.mjs', '.js', '.ts', '.jsx', '.tsx', '.json', '.vue']
},
server: {
// 允许跨域
cors: true,
proxy: {
// 可直接拷贝 vue.config.js 中对应的 proxy
}
}
})
6
总结
遇到很多坑,都是语法相关的,最终都 11 解决了!
也尝试过一些其他方案,但是不能用,我的项目没有生效:
wp2vite
支持了之后,开发是真的很高效!
希望这篇文章对有需要的有所帮助。
还没有评论,来说两句吧...