記一次Webpack配置檔案的分離

c_Kim發表於2018-11-29

隨著前端技術的發展,業務邏輯的增多及功能化的繁瑣已經成為前端人員最燒腦的問題。前端自動化構建工具的出現,為前端人員帶來了專案構建上的福音,成為每個前端工程師必回的技術棧,目前比較流行的Webpack以萬物皆模組的思想構建我們的前端專案,同樣也是筆者正在使用的一個前端自動化構建工具。

Webpack對於每個前端人員來說都不會怎麼陌生,它將每一個靜態檔案當做一個模組,經過一系列的處理為我們整合出最後的需要的js、css、圖片、字型等檔案。

單個配置檔案所造成的問題

本文預設電腦前的你已經瞭解一些Webpack基礎的配置,並懂得了webpack.config.js配置檔案的基礎搭建。

隨著我們業務邏輯的增多,圖片、字型、css、ES6以及CSS前處理器和後處理器逐漸的加入到我們的專案中來,進而導致配置檔案的增多,使得配置檔案書寫起來比較繁瑣,更嚴重者(書寫特定檔案的位置會出現錯誤)。更由於專案中不同的生產環境和開發環境的配置,使得配置檔案變得更加糟糕。

使用單個的配置檔案會影響到任務的可重用性,隨著專案需求的增長,我們必須要找到更有效地管理配置檔案的方法。

管理配置檔案的幾種方法

配置檔案的管理有一下幾種方法。

  • 在每個環境的多個檔案中維護配置,並通過--config引數將webpack指向每個檔案,通過模組匯入共享配置。
  • 將配置檔案推送到庫,然後引用庫。
  • 將配置檔案推送到工具。
  • 維護單個配置檔案的所有配置並在那裡進行分支並依賴--env引數。

本文以第四種方式闡述webpack配置檔案的分離。

分離配置檔案

我們在根目錄下建立config資料夾,並建立四個配置檔案,分別是:

  • webpack.comm.js 公共環境的配置檔案
  • webpack.development.js 開發環境下的配置檔案
  • webpack.production.js 生產環境下的配置檔案
  • webpack.parts.js 各個配置零件的配置檔案

記一次Webpack配置檔案的分離

合併配置檔案的工具

如果配置檔案被分成了許多不同的部分,那麼必須以某種方式來組合他們,通常就是合併陣列和物件,webpack-merge很好的做到了這一點。

webpack-merge做了兩件事:它允許連線陣列併合並物件,而不是覆蓋組合。

const merge = require("webpack-merge");
merge(
    {a : [1],b:5,c:20},
    {a : [2],b:10, d: 421}
)
//合併後的結果
{a : [1,2] ,b :10 , c : 20, d : 421}
複製程式碼

使用webpack-merge合併配置檔案

首先將webpack-merge新增到專案中

npm install webpack-merge --save-dev
複製程式碼

首先設定各個配置檔案的連線

webpack.config.js

const commConfig = require("./config/webpack.comm");
const developmentConfig = requie("./config/webpack.development");
const productionConfig = require("./config/webpack.development")
const merge = require("webpack-merge");

module.exports = mode => {
    if(mode === "production"){
        return merge(commConfig,productionConfig,{mode});   
    }
    return merge(commConfig,developmentConfig,{mode});
}
複製程式碼

上面程式碼利用mode的值來判斷是開發環境還是生產環境

webpack.comm.js

const merge = require("webpack-merge");
const parts = require("./webpack.parts")    //引入配置零件檔案
const config = {
    //書寫公共配置    
}
module.exports = merge([
    config,
    parts......
])
複製程式碼

webpack.production.js

const merge = require("webpack-merge");
const parts = require("./webpack.parts");   //引入配置零件檔案
const config = {
    //書寫公共配置
}
modules.exports = merge([
    config,
    parts......
])
複製程式碼

webpack.development.js

const merge = require("webpack-merge");
const parts = require("./webpack.parts");   //引入配置零件檔案
const config = {
    //書寫公共配置
}
modules.exports = merge([
    config,
    parts......
])
複製程式碼

使用--env值傳參

使用--env允許將字串傳遞給配置。我們來修改下package.json

    "dev": "webpack --env development ",
    "prod": "webpack --env production",
    "dev:server": "webpack-dev-server --env development "
複製程式碼

這樣就使得env引數mode環境引數傳入到webpack.config.js中,就可以判斷是生產環境還是開發環境。

如何寫出可配置的webpack.parts.js

上面可以看出我們新建了一個webpack.parts.js檔案,這個檔案中主要是存放我們的一些配置零件。如何寫出可配置,可拔插的配置零件。就是我們這個檔案的最重要的部分。

以loadCSS為例:

exports.loadCSS = ({reg = /\.css$/,include,exclude,uses = []} = {}) => ({
    module : {
        rules:[{
            test : reg,
            include,
            exclude,
            use[{
                loader : "style-loader",
            },{
                loader : "css-loader",
            }].concat(uses),
        }]
    }
})
複製程式碼

上面程式碼中,利用exports匯出單個配置零件,通過解構賦值來傳入引數。使用陣列的concat來連線外部匯入的loader。引數解析:

  • reg:表示loader匹配的test正則,預設為css,這裡可以是(less、sass、stylus)。
  • include:表示所要打包的資料夾。
  • exclude:表示要跳過打包的資料夾。
  • uses:外部匯入的loader。

在webpack.development.js中引入

module.exports = merge([
    config,
    parts.loadCSS({
        reg : /\.less/,
        use : ["less-loader"]
    }),
    parts.loadCSS(),
])

複製程式碼

分離配置檔案的好處

配置檔案拆分可以是我們繼續擴充套件配置。最重要的收益是我們可以提取不同目標之間的共性。並且還可以識別要組合的較小配置部件,這些配置不見可以推送到自己的軟體包以跨專案使用。還可以將配置作為依賴項進行管理,而不是在多個專案中複製類似的配置。

我自己的parts配置

展示一部分我自己的部件配置,由於在學習階段,不足的地方還望大佬們提出,學習進步。

/**
 * @name 本地伺服器配置
 * @param host  開啟的url
 * @param port  開啟url的埠號
 * 
 */
exports.devServer = ({ host, port} = {}) => ({
    devServer : {
        stats : "errors-only",
        host,
        port,
        open : true,
        overlay : true,
    }
})
/**
 * @name 未從js中分離的cssLoader配置
 * @param reg 匹配檔案的字尾名test
 * @param include 所要打包的資料夾
 * @param exclude 跳過打包的資料夾
 * @param uses 所要向loadCSS中新增的loader
 */
exports.loadCSS = ({reg = /\.css$/,include,exclude,uses = []} = {}) => {
    return {
        module: {
            rules: [{
                test: reg,
                use: [{
                    loader: "style-loader"
                }, {
                    loader: "css-loader"
                }].concat(uses),
                include,
                exclude,
            }]
        },
    }
}
/**
 * @name 從js中分離的cssLoader配置
 * @param reg 匹配檔案的字尾名test
 * @param include 所要打包的資料夾
 * @param exclude 跳過打包的資料夾
 * @param uses 所要向loadCSS中新增的loader
 *  */
const MiniCssExtrectPlugin = require("mini-css-extract-plugin");
exports.extractCSS = ({reg = /\.css$/,include,exclude,uses = []} = {}) => {
    const plugin = new MiniCssExtrectPlugin({
        filename : "styles/[name]-[hash:5].css",
    })
    return {
        module: {
            rules: [{
                test: reg,
                use: [{
                    loader: MiniCssExtrectPlugin.loader,
                    options : {
                        publicPath : "../"
                    }
                }, {
                    loader: "css-loader"
                }].concat(uses),
                include,
                exclude,
            }]
        },
        plugins : [
            plugin,
        ]
    }
}
/**
 * @name css tree-shaking:將沒有用到的css扔掉
 * @param paths 監聽css tree-shaking 的檔名
 */
const PurifyCssPlugin = require("purifycss-webpack");
exports.purifyCSS = ({paths}) => ({
    plugins : [
        new PurifyCssPlugin({paths})
    ]
})

/**
 * @name autoprefixer 為css樣式新增瀏覽器字首
 * @author wangchong
 */
exports.autoprefix =() =>({
    loader : "postcss-loader",
    options : {
        plugins : () => [require("autoprefixer")]
    }
})

/**
 * @name loadImage :打包圖片資源
 * @param include 所要打包的資料夾
 * @param exclude 跳過打包的資料夾
 * @param options loader的options配置
 */
exports.loadImage = ({include,exclude,options} = {}) => ({
    module : {
        rules : [
            {
                test : /\.(png|jpg)$/,
                include,
                exclude,
                use : {
                    loader : "url-loader",
                    options,
                }
            }
        ]
    }
})

複製程式碼

文章總結自:Surviejs-webpack

相關文章