移动端项目往往内嵌着各种各样的H5页面,为了缩小H5打包体积和便于管理前端代码,需要对项目进行分包。 在此,记录一下我的学习思路。
实现一个简单的多模块打包
vue create hello-world
第一步:新建一个vue项目,新建modules目录,在里面新建一个app1文件夹,作为代号为app1的项目。 将默认生成的App.vue、views等文件转移到app1目录中:
第二步:vue.config.js添加配置
pages对象中存放项目(模块)的信息,Vue-cli官网文件这里有介绍:cli.vuejs.org/zh/config/#…
outputDir这里build时需要用到,需要改成对应的项目(模块)名称
const { defineConfig } = require("@vue/cli-service");
module.exports = defineConfig({
publicPath: "./",
outputDir: `dist/app1`, // 输出目录
pages: {
app1: {
// page 的入口
entry: "src/modules/app1/main.js",
// 模板来源
template: "public/index.html",
// 修改:将 "index.html" 改为 "page1.html",使URL路径与文件名一致
filename: process.env.NODE_ENV === "production" ? "index.html" : "app1/index.html",
// 当使用 title 选项时,
// template 中的 title 标签需要是 <title><%= htmlWebpackPlugin.options.title %></title>
title: "app1",
// 在这个页面中包含的块,默认情况下会包含
// 提取出来的通用 chunk 和 vendor chunk。
chunks: ["chunk-vendors", "chunk-common", "app1"],
}
},
transpileDependencies: true,
});
第三步:运行
执行npm run serve,打开浏览器:http://localhost:8080/app1#/
可看到正常运行的网页:
第四步:接着试试打包
npm run build
可以看到dist目录成功出现了一个app1的目录,也能成功运行
第五步:新增加一个模块app2
运行,打开浏览器:http://localhost:8080/app2#/
app2也能正常的预览:
接着build,但是这里不方便的地方是,要手动的更改vue.config.js中的outputDir配置。
如果需要打包app2,就要更改为dist/app2,同时要注释掉pages中关于app1的部分。
app2打包出来:
实现命令行动态打包
我们打包的时候,可以在命令行携带参数,例如:npm run build --page=app1
然后,vue-cli配置文件获取到该参数,动态改变outputDir。
在此之前,需要声明一个配置变量/配置文件,用于记录多模块页面的信息。
代码如下:
const { defineConfig } = require("@vue/cli-service");
// 在这里配置模块信息,最好单独一个文件,方便管理
const businessArray = [{
chunk: 'app1',
chunkName: 'app1'
}, {
chunk: 'app2',
chunkName: 'app2'
}];
const modules = {}
// 打包指定模块,获取命令行 --page参数,例如 npm run build --page=app1
const npm_config_page = process.env.npm_config_page || ''
if (process.env.NODE_ENV === "production") {
// 获取配置的环境变量
console.log('打包模块:' + npm_config_page)
// 生产环境只构建指定模块
const targetModule = businessArray.find(i => i.chunk === npm_config_page)
if (targetModule) {
// 下部分代码不变,后面可以封装成函数
modules[targetModule.chunk] = {
entry: `src/modules/${targetModule.chunk}/main.js`,
template: "public/index.html",
filename: "index.html",
title: targetModule.chunkName,
chunks: ["chunk-vendors", "chunk-common", targetModule.chunk],
}
} else {
throw new Error(`未找到模块: ${npm_config_page},请检查配置`)
}
} else {
businessArray.forEach(i => {
// 下部分代码不变,后面可以封装成函数
modules[i.chunk] = {
entry: `src/modules/${i.chunk}/main.js`,
template: "public/index.html",
filename: `${i.chunk}/index.html`,
title: i.chunkName,
chunks: ["chunk-vendors", "chunk-common", i.chunk],
}
})
}
console.log('modules:', modules)
module.exports = defineConfig({
publicPath: "./",
outputDir: `dist/` + npm_config_page, // 输出目录
pages: modules,
transpileDependencies: true,
});
补充,除了process.env.npm_config_page这个方法外,还可以使用第三方工具commander来解析命令行参数和选项。
打包并压缩成.zip
压缩方案:
- 使用webpack插件zip-webpack-plugin
// npm install zip-webpack-plugin --save-dev
module.exports = defineConfig({
publicPath: "./",
outputDir: `dist/` + npm_config_page, // 输出目录
pages: modules,
transpileDependencies: true,
configureWebpack: config => {
if (process.env.NODE_ENV === "production") {
// 添加zip插件
config.plugins.push(new (require('zip-webpack-plugin'))({
path: path.join(__dirname, 'dist'),
filename: `${npm_config_page}.zip`,
extension: 'zip'
}));
}
}
});
- 使用 npm scripts 后续处理
{
"scripts": {
"build": "vue-cli-service build",
"build:zip": "vue-cli-service build && node scripts/zip-dist.js"
}
}
scripts/zip-dist.js 是压缩的脚本
使用spawn进行更细致化处理
const { spawn } = require('child_process');
function buildWithSpawn(moduleName) {
return new Promise((resolve, reject) => {
// 可以在执行前做更多准备工作
console.log(`开始构建模块: ${moduleName}`);
const buildProcess = spawn('npm', ['run', 'build', '--', `--page=${moduleName}`], {
stdio: 'inherit',
shell: true
});
buildProcess.on('close', (code) => {
if (code === 0) {
console.log(`模块 ${moduleName} 构建成功`);
// 可以在这里执行后续操作,如压缩、上传等
resolve();
} else {
reject(new Error(`构建失败,退出码: ${code}`));
}
});
});
}
批量构建多个模块
async function buildAllModules() {
const modules = ['app1', 'app2', 'app3'];
// 串行构建
for (const module of modules) {
try {
await buildWithSpawn(module);
// 构建完成后可以执行额外操作
await zipModule(module);
} catch (error) {
console.error(`构建模块 ${module} 失败:`, error);
break;
}
}
// 或者并行构建(需要注意资源占用)
// await Promise.all(modules.map(buildWithSpawn));
}