咱們接着上一篇文章react+webpack4.x搭建前端項目(五)多頁面配置 來進行配置模塊的單獨打包方式(下邊簡稱多app打包)html
多app打包的意思是:多個模塊單獨打包,模塊之間的資源互相不依賴,某一模塊的資源打包在該模塊下。這是和多頁面最不大的不一樣,打包資源再多頁面之間實際上是公用的,bundle包資源也具備相互依賴的特徵前端
先捋一下實現的思路,(基於上一篇react+webpack4.x多頁面配置release-tag-0.0.3代碼)node
child_process
模塊建立子進程,在這個子進程執行打包任務,這樣咱們能夠建立多個子進程執行打包任務,也就能夠打包出多app這裏不具體講述修改的代碼細節了,值只貼一下關鍵代碼。 詳細代碼請查看 react+webpack4.x多模塊打包配置release-tag-0.0.4react
使用child_process的child_process.execFileSync
方法建立子進程執行打包任務webpack
詳細使用教程請看官方文檔child_process使用文檔git
const child_process = require("child_process");
const { getModuleList } = require("./module-entry");
const path = require("path")
const filePath = path.resolve(__dirname,"./build.js")
const fs = require("fs")
// 支持自定是模塊打包
const modules = process.argv[2];
if(modules){
const moduleList = modules.split(",")
// 動態遍歷每一個模塊,對每一個模塊開啓子進程單獨進行打包
for(let index=0;index<moduleList.length;index++){
const moduleName = moduleList[index];
try{
if(fs.statSync(path.resolve(__dirname, `./../src/modules/${moduleName}/index.js`))){
console.log(`開始打包<<<<<<${moduleName}<<<<<模塊`);
// 同步執行腳本文件
const result = child_process.execFileSync("node",[filePath,"single-bundle",moduleName]) // 第三個參數是是不是多頁面
process.stdout.write(result + '\n\n');
}
}catch(error){
console.log(`${moduleName}模塊不存在`)
}
}
}else{
// 打包默認的app
console.log(`開始打包默認模塊`);
const result = child_process.execFileSync("node",[filePath,"single-bundle"]) // 第三個參數不傳
process.stdout.write(result + '\n\n');
const moduleList = getModuleList();
console.log(moduleList)
// 動態遍歷每一個模塊,對每一個模塊開啓子進程單獨進行打包
for(let index=0;index<moduleList.length;index++){
const moduleName = moduleList[index];
console.log(`開始打包<<<<<<${moduleName}<<<<<模塊`);
// 同步執行腳本文件
const result = child_process.execFileSync("node",[filePath,"single-bundle",moduleName]) // 第三個參數是是不是多頁面
process.stdout.write(result + '\n\n');
}
}
複製代碼
getBuildEntry
獲取打包入口getHtmlWebpackPluginList
獲取打包模板文件的配置getPrdOutPutPath
獲取打包目錄getPublicPath
獲取打包資源的注入前綴路徑// 獲取webpack entry
function getBuildEntry(){
const MODULE_NAME = process.env.MODULE_NAME // 打包的模塊
const SINGLE_BUNDLE = process.env.SINGLE_BUNDLE;
// 開發環境和多頁面包括單頁面
if(utils.isDev() || SINGLE_BUNDLE == null){
const moduleList = getModuleList();
let entry = {};
for(let index in moduleList){
const moduleName = moduleList[index]
entry[moduleName] = `./src/modules/${moduleName}/index.js`
}
// 添加默認打包入口文件
entry["app"] = "./src/index.js"
return entry
}else if(isSingleBundle(SINGLE_BUNDLE)) {
let entry = {}; // 單獨打包
if(MODULE_NAME){
// modules下的入口
entry[MODULE_NAME] = "./src/modules/" + MODULE_NAME + "/index.js";
}else{
// 默認的打包入口文件
entry["app"] = "./src/index.js"
}
console.log(entry)
return entry;
}
}
// 獲取htmlwebpackplugin列表
function getHtmlWebpackPluginList(options={}){
const extractOptions = {
minify: {
removeComments: true, //去註釋
collapseWhitespace: true, //壓縮空格
removeAttributeQuotes: true //去除屬性引用
},
}
const MODULE_NAME = process.env.MODULE_NAME // 打包的模塊
const SINGLE_BUNDLE = process.env.SINGLE_BUNDLE;
// 開發環境和多頁面包括單頁面
if(utils.isDev() || SINGLE_BUNDLE == null){
// 多頁面打包
const moduleList = getModuleList();
const HtmlWebpackPluginList = [];
for(let index in moduleList){
const moduleName = moduleList[index];
const HtmlWebpackPluginOptions = {
filename: utils.resolve('./../dist/'+ moduleName+ '/index.html'), // html模板的生成路徑
template: utils.resolve("./../src/modules/" + moduleName + "/index.html"),//html模板
inject: true, // true:默認值,script標籤位於html文件的 body 底部
chunks: [moduleName], // 注入哪一個名稱bundel
};
if(options.extract){
HtmlWebpackPluginOptions = Object.assign(HtmlWebpackPluginOptions,extractOptions)
}
HtmlWebpackPluginList.push(new HtmlWebpackPlugin(HtmlWebpackPluginOptions))
}
// 添加默認的輸出模板文件
HtmlWebpackPluginList.push(new HtmlWebpackPlugin(Object.assign({
filename: utils.resolve('./../dist/index.html'), // html模板的生成路徑
template: 'index.html',//html模板
inject: true, // true:默認值,script標籤位於html文件的 body 底部
chunks: ['app'], // 注入哪一個名稱bundel
},extractOptions)))
return HtmlWebpackPluginList;
}else if(isSingleBundle(SINGLE_BUNDLE)){
// 多app打包
const HtmlWebpackPluginList = [];
if(MODULE_NAME){
// modules目錄下的打包模板文件配置
HtmlWebpackPluginList.push(new HtmlWebpackPlugin(Object.assign({
filename: utils.resolve('./../dist/'+ MODULE_NAME+ '/index.html'), // html模板的生成路徑
template: utils.resolve("./../src/modules/" + MODULE_NAME + "/index.html"),//html模板
inject: true, // true:默認值,script標籤位於html文件的 body 底部
chunks: ['vendors',MODULE_NAME], // 注入哪一個名稱bundel
},extractOptions)));
}else{
// 添加默認的輸出模板文件
HtmlWebpackPluginList.push(new HtmlWebpackPlugin(Object.assign({
filename: utils.resolve('./../dist/index.html'), // html模板的生成路徑
template: 'index.html',//html模板
inject: true, // true:默認值,script標籤位於html文件的 body 底部
chunks: ['app'], // 注入哪一個名稱bundel
},extractOptions)))
}
if(options.extract){
HtmlWebpackPluginOptions = Object.assign(HtmlWebpackPluginOptions,extractOptions)
}
return HtmlWebpackPluginList;
}
}
// 打包的輸出目錄
function getPrdOutPutPath(){
const MODULE_NAME = process.env.MODULE_NAME // 打包的模塊
const SINGLE_BUNDLE = process.env.SINGLE_BUNDLE;
// 開發環境和多頁面包括單頁面
if(utils.isDev() || SINGLE_BUNDLE == null){
return utils.resolve("../dist");
}else if(isSingleBundle(SINGLE_BUNDLE)){
// 多app打包
if(MODULE_NAME){
return utils.resolve(`../dist/${MODULE_NAME}`)
}else{
return utils.resolve("../dist");
}
}
}
// 打包資源的前綴路徑
function getPublicPath(){
const MODULE_NAME = process.env.MODULE_NAME // 打包的模塊
const SINGLE_BUNDLE = process.env.SINGLE_BUNDLE;
// 開發環境和多頁面包括單頁面
if(utils.isDev() || SINGLE_BUNDLE == null){
return "/"
}else if(isSingleBundle(SINGLE_BUNDLE)){
// 多app打包
if(MODULE_NAME){
return `/${MODULE_NAME}`
}else{
return `/`
}
}
}
複製代碼
其它詳細配置這裏很少說了,詳細的請看源碼。github
詳細代碼請查看 react+webpack4.x多模塊打包配置release-tag-0.0.4web
新增"build-apps": "cross-env NODE_ENV=production node build/build-apps.js"
命令npm
執行npm run build-apps
api
打包結果請看下圖
這裏解釋一下
a目錄輸出包對應src/modules/a目錄的代碼
b目錄輸出包對應src/modules/b目錄的代碼
默認的包是src/index.js對應打包輸出app
若是modules目錄下沒有任何模塊那打包結果天然就沒有a,b這些輸出包了
有什麼疑問能夠多多交流,謝謝!