react+webpack4.x搭建前端項目(六)webpack的多模塊打包配置

我們接著上一篇文章react+webpack4.x搭建前端項目(五)多頁面配置
來進行配置模塊的單獨打包方式(下邊簡稱多app打包)

這里小編推薦一個福利,更多精彩內容請點擊鏈接,點擊這里

多app打包的意思是:多個模塊單獨打包,模塊之間的資源互相不依賴,某一模塊的資源打包在該模塊下。這是和多頁面最不大的不同,打包資源再多頁面之間其實是公用的,bundle包資源也具有相互依賴的特征

先捋一下實現的思路,(基于上一篇react+webpack4.x多頁面配置release-tag-0.0.3代碼)

  • 多app打包基于node的child_process模塊創建子進程,在這個子進程執行打包任務,這樣我們可以創建多個子進程執行打包任務,也就可以打包出多app
  • 子進程執行打包命令的時候,注入參數區分是多app打包還是多頁面打包
  • 針對參數,動態生成webpack配置,進行不同方式打包

這里不具體講述修改的代碼細節了,值只貼一下關鍵代碼。
詳細代碼請查看 react+webpack4.x多模塊打包配置release-tag-0.0.4

新建build/build-apps.js多app打包腳本

使用child_process的child_process.execFileSync方法創建子進程執行打包任務

詳細使用教程請看官方文檔child_process使用文檔

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 `/`
        }
    }
}

其它詳細配置這里不多說了,詳細的請看源碼。

詳細代碼請查看 react+webpack4.x多模塊打包配置release-tag-0.0.4

打包結果

新增"build-apps": "cross-env NODE_ENV=production node build/build-apps.js"命令

執行npm run build-apps

打包結果請看下圖

QQ截圖20200318170028.png

這里解釋一下

a目錄輸出包對應src/modules/a目錄的代碼

b目錄輸出包對應src/modules/b目錄的代碼

默認的包是src/index.js對應打包輸出app

如果modules目錄下沒有任何模塊那打包結果自然就沒有a,b這些輸出包了

有什么疑問可以多多交流,謝謝!

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 227,401評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,011評論 3 413
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 175,263評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,543評論 1 307
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,323評論 6 404
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 54,874評論 1 321
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 42,968評論 3 439
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,095評論 0 286
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,605評論 1 331
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,551評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,720評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,242評論 5 355
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 43,961評論 3 345
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,358評論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,612評論 1 280
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,330評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,690評論 2 370

推薦閱讀更多精彩內容