vue-cli3 vue2 保留 webpack 支持 vite 成功实践
大家好!
文本是为了提升开发效率及体验实践诞生的。
项目背景:
- 脚手架: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 启动命令
- 可能需要
- 路由懒加载,vite 需要特殊处理
- 解决 commonjs 与 esModule 的引入与混用
增加 vite.config.js
在项目根目录创建一个 vite.config.js
安装所需依赖
npm i vite vite-plugin-vue2 -D
根据 vue.config.js
在 vite.config.js
中增加对应配置
// 若改了该文件逻辑,请对照着改一下 vue.config.js
import 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
预处理器, 且用到变量了。
需要安装 sass@1.32.13,不能安装比 1.32
更高的版本,跟高版本存在这个问题Sass报错: Using / for division is deprecated
npm i sass@1.32.13 -D
export default defineConfig({
...
css: {
// 给 sass 传递选项
preprocessorOptions: {
scss: {
charset: false, // 最新版sass才支持
additionalData: `@import "src/sass/common/var.scss";`,
}
},
},
...
})
备注:如果生产环境用 vite 打包,采用 sass@1.32.13
将会遇到这个问题vite2打包出现警告,"@charset" must be the first,该如何消除呢?,但是 sass@1.32.13
不支持文档中的配置。所以这可以算是生产环境不用 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']
const modules = import.meta.glob('@/page/*.vue')
// vite 会生成代码
const modules = {
'@/page/home.vue': () => import('@/page/home.vue'),
'@/page/page1.vue': () => import('@/page/page1.vue'),
'@/page/page2.vue': () => import('@/page/page2.vue'),
...
}
参考:vite-Glob 导入
所以可封装一下:
function loadPage (view) {
if (process.env.isVite) {
const modules = import.meta.glob('../pages/*.vue')
return modules[`../pages/${view}.vue`]
}
return () => import(/* webpackChunkName: "[request]" */ `@/pages/${view}`)
}
// 使用:
const routes = [
{
path: `/home`,
name: 'home',
component: loadPage('home'),
},
{
path: `/404`,
name: '404',
component: loadPage('404'),
},
]
但是 webpack 不支持 import.meta,需要 loader 处理。解决:在本地建一个文件 webpack-import-meta-loader.js。
// 来源:https://github.com/KmjKoishi/webpack-import-meta-loader-fixed
// 是对 @open-wc/webpack-import-meta-loader 这个的修复
// 主要是修复 当 this.rootContext 不存在的判断处理。构建生产环境时不存在
/* eslint-disable */
// @ts-nocheck
const path = require('path');
function toBrowserPath(filePath, _path = path) {
return filePath.replace(new RegExp(_path.sep === '\\' ? '\\\\' : _path.sep, 'g'), '/');
};
const regex = /import\.meta/g;
/**
* Webpack loader to rewrite `import.meta` in modules with url data to the source code file location.
*
* @example
* return import.meta;
* // becomes: return ({ url: `${window.location.protocol}//${window.location.host}/relative/path/to/file.js` });
*
* return import.meta.url;
* // becomes: return ({ url: `${window.location.protocol}//${window.location.host}/relative/path/to/file.js` }).url;
*/
module.exports = function (source) {
const path = require('path');
const relativePath = this.context.substring(
this.context.indexOf(this.rootContext) + (this.rootContext && this.rootContext.length >= 0 ? (this.rootContext.length + 1) : 0),
this.resource.lastIndexOf(path.sep) + 1,
);
const browserPath = toBrowserPath(relativePath);
const fileName = this.resource.substring(this.resource.lastIndexOf(path.sep) + 1);
let found = false;
let rewrittenSource = source.replace(regex, () => {
found = true;
return `({ url: getAbsoluteUrl('${browserPath}/${fileName}') })`;
});
if (found) {
return `
function getAbsoluteUrl(relativeUrl) {
const publicPath = __webpack_public_path__;
let url = '';
if (!publicPath || publicPath.indexOf('://') < 0) {
url += window.location.protocol + '//' + window.location.host;
}
if (publicPath) {
url += publicPath;
} else {
url += '/';
}
return url + relativeUrl;
}
${rewrittenSource}`;
} else {
return source;
}
};
vue.config.js 修改配置:
const resolve = dir => require('path').join(__dirname, dir)
module.exports = {
...
configureWebpack: {
...
module: {
rules: {
...
{
test: /index.js$/,
use: [
resolve('webpack-import-meta-loader'),
'babel-loader'
],
include: [resolve('src/router')]
}
}
}
}
...
}
解决 commonjs 与 esModule 的引入与混用
混用
webpack 方式下,若你的 src 项目源码中存在混用 commonjs 与 esModule。
方案一:不改源码,在 vite.config.js 中加配置,把 commonjs 转换为 esModule
安装 npm i cjs2esmodule -D
在 vite.config.js 中加配置
export default defineConfig({
plugins: [cjs2esmVitePlugin()]
})
如果这个方案,能让你的项目运行正常。否则,可能需要采用方案二。
方案二:把 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。
目的是减少后期维护成本。
// transformConfig2cjs.js
// 运行项目的时候,会根据config.js自动生成文件:config-cjs.js, 以便让 vue-config.js 能直接使用
const {transformAsync} = require('@babel/core');
const plugin = require('@babel/plugin-transform-modules-commonjs')
const fs = require('fs')
const resolve = dir => require('path').join(__dirname, dir)
async function transfrom () {
const inputPath = resolve('config.js')
const input = fs.readFileSync(inputPath, 'utf-8')
const {code} = await transformAsync(input, {
sourceType: 'module',
plugins: [ plugin ]
});
fs.writeFileSync(resolve('./config-cjs.js'), code);
}
transfrom()
然后在 vue.config.js 原来引入的 config.js 的地方改为 config-cjs.
最后在 package.json
中改变下脚本,每次都重新生成一个最新的配置。
"scripts": {
"transformConfig2cjs": "node transformConfig2cjs.js",
"serve": "npm run transformConfig2cjs && vue-cli-service serve",
"build": "npm run transformConfig2cjs && vue-cli-service build",
}
总结
遇到很多坑,都是语法相关的,最终都 11 解决了!
也尝试过一些其他方案,但是不能用,我的项目没有生效:
支持了之后,开发是真的很高效!
希望这篇文章对有需要的有所帮助。
vue-cli3 vue2 保留 webpack 支持 vite 成功实践的更多相关文章
- 使用VUE CLI3.0搭建项目vue2+scss+element简易版
1.安装Vue CLI 3 //三选一即可cnpm install -g @vue/cli npm install -g @vue/cli yarn global add @vue/cli 注意: 1 ...
- 一步步构造自己的vue2.0+webpack环境
前面vue2.0和webpack都已经有接触了些(vue.js入门,webpack入门之简单例子跑起来),现在开始学习如何构造自己的vue2.0+webpack环境. 1.首先新建一个目录vue-wk ...
- cordova打包vue2(webpack)android、ios app
使用cordova打包vue2(webpack)app for android ios1.vue项目通过vue-cli脚手架建立项目,使用webpack进行打包,下边是一整套命令. #npm 版本最好 ...
- Vue2.0+Webpack项目环境构建到发布
前言:为什么要用webpack搭建项目呢,因为这个工具可以把目前浏览器不全部支持的ES6语法,通过打包工具生成所有浏览器都支持的单个JS文件. 参考: https://blog.csdn.net/u0 ...
- vue cli3 项目配置
[转]https://juejin.im/post/5c63afd56fb9a049b41cf5f4 基于vue-cli3.0快速构建vue项目 本章详细介绍使用vue-cli3.0来搭建项目. 本章 ...
- 一篇文章说清 webpack、vite、vue-cli、create-vue 的区别
webpack.vite.vue-cli.create-vue 这些都是什么?看着有点晕,不要怕,我们一起来分辨一下. 先看这个表格: 脚手架 vue-cli create-vue 构建项目 vite ...
- 在 vue cli3 的项目中配置双服务,模拟 ajax 分页请求
最近安装了下vue cli3版本,与 cli 2 相比,文件少了,以前配置方法也不管用了.demo 中的大量的数据,需要做成 ajax 请求的方式来展示数据,因此,需要启动两个服务,一个用作前端请求, ...
- Vue2+VueRouter2+webpack 构建项目实战(二):目录以及文件结构
通过上一篇博文<Vue2+VueRouter2+webpack 构建项目实战(一):准备工作>,我们已经新建好了一个基于vue+webpack的项目.本篇文章详细介绍下项目的结构. 项目目 ...
- Vue CLI3 开启gzip压缩
gizp压缩是一种http请求优化方式,通过减少文件体积来提高加载速度.html.js.css文件甚至json数据都可以用它压缩,可以减小60%以上的体积. webpack在打包时可以借助 compr ...
随机推荐
- [nowcoder5668J]Operating on the Tree
考虑令$a_{i}$为i的位置,$p_{i}=0/1$表示第i个点的贡献,那么$p_{x}=0$当且仅当存在与其相邻的点$y$满足$a_{y}<a_{x}$且$p_{y}=1$ 树形dp,定义状 ...
- 面试官问我JVM调优,我忍不住了!
面试官:今天要不来聊聊JVM调优相关的吧? 面试官:你曾经在生产环境下有过调优JVM的经历吗? 候选者:没有 面试官:... 候选者:嗯...是这样的,我们一般优化系统的思路是这样的 候选者:1. 一 ...
- 洛谷 P5400 - [CTS2019]随机立方体(组合数学+二项式反演)
洛谷题面传送门 二项式反演好题. 首先看到"恰好 \(k\) 个极大值点",我们可以套路地想到二项式反演,具体来说我们记 \(f_i\) 为钦定 \(i\) 个点为极大值点的方案数 ...
- Codeforces 917C - Pollywog(状压 dp+矩阵优化)
UPD 2021.4.9:修了个 typo,为啥写题解老出现 typo 啊( Codeforces 题目传送门 & 洛谷题目传送门 这是一道 *2900 的 D1C,不过还是被我想出来了 u1 ...
- Unique Path AGC 038 D
Unique Path AGC 038 D 考虑如果两个点之间只能有一个边它们就把它们缩起来,那么最后缩起来的每一块都只能是一棵树. 如果两个点之间必须不止一个边,并且在一个连通块,显然无解. 首先把 ...
- Atcoder Grand Contest 021 F - Trinity(dp+NTT)
Atcoder 题面传送门 & 洛谷题面传送门 首先我们考虑设 \(dp_{i,j}\) 表示对于一个 \(i\times j\) 的网格,其每行都至少有一个黑格的合法的三元组 \((A,B, ...
- DTOJ 3987: 数学课
题目描述 wzy又来上数学课了-- 虽然他很菜,但是数学还是懂一丢丢的.老师出了一道题,给定一个包含$n$个元素的集合$P=1,2,3--n$求有多少集合$A \subseteq P$,满足$x \i ...
- wget 命令用法
wget 命令用法 1. 用法/命令格式 wget [OPTION]... [URL]... wget [参数列表] [目标软件.网页的网址] 长选项所必须的参数在使用短选项时也是必须的 2. 常用参 ...
- 【豆科基因组】绿豆Mungbean, Vigna radiata苏绿基因组预印
目录 一.来源 二.结果 测序组装 组装评价 编码基因预测 基因功能注释 非编码RNA注释 假基因预测 重复序列注释 进化分析和分歧时间估计 全基因组复制 LTR插入时间估计 正选择基因 一.来源 H ...
- Linux命令行好玩的命令
0.cal 2019 #输出日历并显示今天是哪一天 1.命令"date",显示系统的当前日期和时间: 2.命令"date 040100002016",屏幕显示 ...