
本地开发工程化改造优化
1. 背景及结果:
1.1 背景
- 当前系统功能复杂,模快依赖多,目前的依赖模块有 6000+ 个,加上自身的源码,总的模块依赖数量超过 7000+,导致每次启动的时候项目特别慢,需要 120S 左右,同时也影响了热更新速度。
- 所以想通过项目改造来提升启动速度和热更新速度,提升开发效率。
1.2 结果
对项目进行改造后, 项目启动时缩短为 10S
以内,启动效率提升 90%
。
1.3 统计依赖的模块数量:6000+
npm ls | wc -l
1.4 统计本地文件数量: 1000+
// 安装 tree 命令
brew install tree
// 统计模块数量
tree -fi src | grep -E '\.js$|\.css$|.vue$|.scss$|' | wc -l
2. 解决方案
将 webpack 构建转为 vite 构建。
3. 过程中需要解决的问题
3.1 依赖项变化
3.1.1 基础依赖
- 需要新增的依赖
"@vitejs/plugin-vue": "^1.6.1", // 支持 Vue 2.7 或以上版本
"@vitejs/plugin-vue2-jsx": "^1.1.0", // 支持 jsx
"vite": "^4.4.9",
// 或者
"vite-plugin-vue2" : "1.9.0" // 仅支持 Vue 2.6 或更早版本
"vite": "^2.9.18",
npm i vite-plugin-vue2@1.9.0 vite@2.9.18 -D
3.1.2 插件依赖
- 需要新增的依赖
"vite-plugin-dynamic-import": "^1.5.0", // 增强 Vite 内置的 dynamic import
"vite-plugin-env-compatible": "^1.1.1", // inject to process.env like vue-cli and also define client process.env.XXX for you.
"vite-plugin-node-polyfills": "^0.7.0", // 用于在浏览器环境中填充 Node 的核心模块
"@originjs/vite-plugin-commonjs": "^1.0.3", // Support commonJS to esm in vite
"@originjs/vite-plugin-require-context": "^1.0.9", // Support require.context in vite
"@rollup/plugin-alias": "^5.1.0",
"path-browserify": "^1.0.1",
npm i vite-plugin-dynamic-import@1.5.0 vite-plugin-env-compatible@1.1.1 vite-plugin-node-polyfills@0.7.0 @originjs/vite-plugin-commonjs@1.0.3 @originjs/vite-plugin-require-context@1.0.9 @rollup/plugin-alias@5.1.0 path-browserify@1.0.1 -D
- 自定义插件
// 替换不兼容的 npm 包
function transformNpmModules() {
return {
name: "vite-plugin-transform-npm-modules",
enforce: "pre",
transform(src, id) {
// 替换不兼容的包
if (/\.(js|vue)(\?)_/.test(id) && !id.includes("node_modules")) {
const keyword = [{ src: "path", target: "path-browserify" }];
keyword.forEach((item) => {
src = src
.replace(
new RegExp(`from\\s+(['"])${item.src}(['"])`, "gi"),
`from $1${item.target}$2`
)
.replace(
new RegExp(`require\\((['"])${item.src}(['"])\\)`, "gi"),
`require($1${item.target}$2)`
);
});
return {
code: src,
};
}
},
};
}
// 兼容 scss 旧语法
function transformScss() {
return {
name: "vite-plugin-transform-scss",
enforce: "pre",
transform(src, id) {
if (
/\.(js|vue)(\?)_/.test(id) &&
id.includes("lang.scss") &&
!id.includes("node_modules")
) {
return {
code: src.replace(/(\/deep\/|>>>)/gi, "::v-deep"),
};
}
// 单独的 css 文件内出现 vue 深度选择器将不起作用,webpack 直接忽略,而 vite 会报错,这里屏蔽这个错误
if (/\.(scss|css)$/.test(id) && !id.includes("node_modules")) {
return {
code: src.replace(
/(\/deep\/|::v-deep|>>>)/gi,
"**vite_remove_useless_vue_deep**"
),
};
}
},
};
}
3.2 文件变化
3.2.1 新增 index.html
对原 index.html 进行处理
- 手动添加入口文件:
<script type="module" src="/src/main.js"></script>
- 显示书写 title: 替换 <%= webpackConfig.name %>
3.2.2 新增 vite.config.js
需要手动配置的:
- 代理
- 别名
- 基础路径
import { defineConfig } from "vite";
import { createVuePlugin } from "vite-plugin-vue2";
import { resolve } from "path";
import alias from "@rollup/plugin-alias";
import envCompatible from "vite-plugin-env-compatible";
import { viteCommonjs } from "@originjs/vite-plugin-commonjs";
import viteRequireContext from "@originjs/vite-plugin-require-context";
import dynamicImport from "vite-plugin-dynamic-import";
import { nodePolyfills } from "vite-plugin-node-polyfills";
// 替换不兼容的 npm 包
function transformNpmModules() {
return {
name: "vite-plugin-transform-npm-modules",
enforce: "pre",
transform(src, id) {
// 替换不兼容的包
if (/\.(js|vue)(\?)_/.test(id) && !id.includes("node_modules")) {
const keyword = [{ src: "path", target: "path-browserify" }];
keyword.forEach((item) => {
src = src
.replace(
new RegExp(`from\\s+(['"])${item.src}(['"])`, "gi"),
`from $1${item.target}$2`
)
.replace(
new RegExp(`require\\((['"])${item.src}(['"])\\)`, "gi"),
`require($1${item.target}$2)`
);
});
return {
code: src,
};
}
},
};
}
// 兼容 scss 旧语法
function transformScss() {
return {
name: "vite-plugin-transform-scss",
enforce: "pre",
transform(src, id) {
if (
/\.(js|vue)(\?)_/.test(id) &&
id.includes("lang.scss") &&
!id.includes("node*modules")
) {
return {
code: src.replace(/(\/deep\/|>>>)/gi, "::v-deep"),
};
}
// 单独的 css 文件内出现 vue 深度选择器将不起作用,webpack 直接忽略,而 vite 会报错,这里屏蔽这个错误
if (/\.(scss|css)$/.test(id) && !id.includes("node_modules")) {
return {
code: src.replace(
/(\/deep\/|::v-deep|>>>)/gi,
"**vite_remove_useless_vue_deep**"
),
};
}
},
};
}
// https://vitejs.dev/config/
export default defineConfig({
// build: {
// rollupOptions: {
// input: 'public2/index.html',
// },
// },
plugins: [
// 兼容 scss 旧语法
transformScss(),
// transformNpmModules(),
// 支持.vue 文件, Vue2.6
createVuePlugin({
jsx: true, // 支持 vue jsx 语法(需要同时把.js 改为.jsx 或者 script 标签加属性 lang="jsx")
}),
dynamicImport(),
viteCommonjs(),
viteRequireContext(),
envCompatible(),
nodePolyfills(),
],
envPrefix: ["VUE_APP*"], // 兼容 VUE*APP*前缀
base: "/test/",
server: {
host: "me.xx.com",
},
resolve: {
extensions: [".js", ".vue", ".json"],
alias: {}, //
},
define: {
global: "globalThis",
},
});
4. 可能会遇到的问题:
4.1 JSX 相关
- 实例化 Vue2 插件的时候传入{jsx: true}开启 JSX 支持
- 在用到的组件上加上 jsx 标识:
<script lang="jsx"> </script>
4.2 全局 SCSS 变量
在 Vite 中我们可以通过 css.preprocessorOptions 进行配置。
css: {
preprocessorOptions: {
scss: {
additionalData: `@import './src/variables/index.scss';`,
},
},
}
4.3 CSS module 相关
任何以.module.css 为后缀名的 CSS 文件都被认为是一个 CSS modules 文件。导入这样的文件会返回一个相应的模块对象.Vite 中,如果你希望使用 CSS Modules 功能来局部化组件的样式,确实需要按照特定的命名约定来命名你的 SCSS 文件。通常,这个约定是将文件命名为 \*.module.scss
,这样 Vite 和其他构建工具就能够识别这些文件并作为 CSS Modules 来处理它们。
SCSS 导出的变量在 JS 文件找不到,如下:
:export {
menuText: $menuText;
}
或者, 配置所有的 .scss 文件都使用 CSS Modules, 使所有的样式默认使用 CSS Modules
defineConfig({
css: {
modules: {
// 配置所有的 .scss 文件都使用 CSS Modules
scopeBehaviour: "local", // 使所有的样式默认使用 CSS Modules
},
preprocessorOptions: {
scss: {
// additionalData: `@import "src/styles/variables.scss";`, // 如果有全局变量文件
},
},
},
});
4.4 /deep/ 相关
在 Vite 中,使用 /deep/
选择器是可以的,但需要注意它的非标准性和未来兼容性问题。Vite 本身没有对 /deep/
选择器做特殊处理,它依赖于 PostCSS 插件(如 postcss-preset-env
)来解析和处理这些非标准选择器。为了确保 /deep/
选择器在 Vite 项目中正常工作,按照以下步骤进行配置:
4.4.1. 安装必要的 PostCSS 插件:
npm install postcss postcss-preset-env --save-dev
4.4.2. 配置 PostCSS:
在项目根目录下创建一个 postcss.config.js
文件,并进行如下配置:
module.exports = {
plugins: [
require("postcss-preset-env")({
stage: 0,
features: {
"nesting-rules": true, // 支持嵌套规则
},
}),
],
};
5. 快捷的脚手架
方便大家进行项目改造,提供一个脚手架为大家完成基础的配置,大家根据项目再做个性化配置即可。
5.1 安装
npm i webpack2vite-cli -D
5.2 使用
w2v
5.3 启动
npm run vite
6. 参考资料
版权所有
版权归属:tuyongtao1