4W字長文帶你深度解鎖Webpack系列(上)


三篇長文,4W余字,帶你解鎖 Webpack ,希望讀完這三篇文章,你能夠對 webpack 的各項配置有一個更為清晰的認識。

1.webpack 是什么?

webpack 是一個現代 JavaScript 應用程序的靜態模塊打包器,當 webpack 處理應用程序時,會遞歸構建一個依賴關系圖,其中包含應用程序需要的每個模塊,然后將這些模塊打包成一個或多個 bundle

2.webpack 的核心概念

  • entry: 入口

  • output: 輸出

  • loader: 模塊轉換器,用於把模塊原內容按照需求轉換成新內容

  • 插件(plugins): 擴展插件,在webpack構建流程中的特定時機注入擴展邏輯來改變構建結果或做你想要做的事情

3.初始化項目

新建一個文件夾,如: webpack-first (當然,你可以使用任意一個你喜歡的項目名)。推薦大家參考本文一步一步進行配置,不要總是在網上找什么最佳配置,你掌握了webpack之后,根據自己的需求配置出來的,就是最佳配置。

本篇文章對應的項目地址(編寫本文時使用): https://github.com/YvetteLau/webpack/tree/master/webpack-first

使用 npm init -y 進行初始化(也可以使用 yarn)。

要使用 webpack,那么必然需要安裝 webpackwebpack-cli:

npm install webpack webpack-cli -D

鑒於前端技術變更迅速,祭出本篇文章基於 webpack 的版本號:

├── webpack@4.41.5 
└── webpack-cli@3.3.10 

從 wepack V4.0.0 開始, webpack 是開箱即用的,在不引入任何配置文件的情況下就可以使用。

新建 src/index.js 文件,我們在文件中隨便寫點什么:

//index.js
class Animal {
    constructor(name) {
        this.name = name;
    }
    getName() {
        return this.name;
    }
}

const dog = new Animal('dog');

使用 npx webpack --mode=development 進行構建,默認是 production 模式,我們為了更清楚得查看打包后的代碼,使用 development 模式。

可以看到項目下多了個 dist 目錄,里面有一個打包出來的文件 main.js

webpack 有默認的配置,如默認的入口文件是 ./src,默認打包到dist/main.js。更多的默認配置可以查看: node_modules/webpack/lib/WebpackOptionsDefaulter.js

查看 dist/main.js 文件,可以看到,src/index.js 並沒有被轉義為低版本的代碼,這顯然不是我們想要的。

{
    "./src/index.js":
        (function (module, exports) {

            eval("class Animal {\n    constructor(name) {\n        this.name = name;\n    }\n    getName() {\n        return this.name;\n    }\n}\n\nconst dog = new Animal('dog');\n\n//# sourceURL=webpack:///./src/index.js?");

        })
}

4.將JS轉義為低版本

前面我們說了 webpack 的四個核心概念,其中之一就是 loaderloader 用於對源代碼進行轉換,這正是我們現在所需要的。

將JS代碼向低版本轉換,我們需要使用 babel-loader

babel-loader

首先安裝一下 babel-loader

npm install babel-loader -D

此外,我們還需要配置 babel,為此我們安裝一下以下依賴:

npm install @babel/core @babel/preset-env @babel/plugin-transform-runtime -D

npm install @babel/runtime @babel/runtime-corejs3

對babel7配置不熟悉的小伙伴,可以閱讀一下這篇文章: 不可錯過的 Babel7 知識

新建 webpack.config.js,如下:

//webpack.config.js
module.exports = {
    module: {
        rules: [
            {
                test: /\.jsx?$/,
                use: ['babel-loader'],
                exclude: /node_modules/ //排除 node_modules 目錄
            }
        ]
    }
}

建議給 loader 指定 include 或是 exclude,指定其中一個即可,因為 node_modules 目錄通常不需要我們去編譯,排除后,有效提升編譯效率。

這里,我們可以在 .babelrc 中編寫 babel 的配置,也可以在 webpack.config.js 中進行配置。

創建一個 .babelrc

配置如下:

{
    "presets": ["@babel/preset-env"],
    "plugins": [
        [
            "@babel/plugin-transform-runtime",
            {
                "corejs": 3
            }
        ]
    ]
}

現在,我們重新執行  npx webpack --mode=development,查看 dist/main.js,會發現已經被編譯成了低版本的JS代碼。

在webpack中配置 babel

//webpack.config.js
module.exports = {
    // mode: 'development',
    module: {
        rules: [
            {
                test: /\.jsx?$/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ["@babel/preset-env"],
                        plugins: [
                            [
                                "@babel/plugin-transform-runtime",
                                {
                                    "corejs": 3
                                }
                            ]
                        ]
                    }
                },
                exclude: /node_modules/
            }
        ]
    }
}

這里有幾點需要說明:

  • loader 需要配置在 module.rules 中,rules 是一個數組。

  • loader 的格式為:

{
    test: /\.jsx?$/,//匹配規則
    use: 'babel-loader'
}

或者也可以像下面這樣:

//適用於只有一個 loader 的情況
{
    test: /\.jsx?$/,
    loader: 'babel-loader',
    options: {
        //...
    }
}

test 字段是匹配規則,針對符合規則的文件進行處理。

use 字段有幾種寫法

  • 可以是一個字符串,例如上面的 use: 'babel-loader'

  • use 字段可以是一個數組,例如處理CSS文件時,use: ['style-loader', 'css-loader']

  • use 數組的每一項既可以是字符串也可以是一個對象,當我們需要在webpack 的配置文件中對 loader 進行配置,就需要將其編寫為一個對象,並且在此對象的 options 字段中進行配置,如:

rules: [
    {
        test: /\.jsx?$/,
        use: {
            loader: 'babel-loader',
            options: {
                presets: ["@babel/preset-env"]
            }
        },
        exclude: /node_modules/
    }
]

上面我們說了如何將JS的代碼編譯成向下兼容的代碼,當然你可以還需要一些其它的 babel 的插件和預設,例如 @babel/preset-react@babel/plugin-proposal-optional-chaining 等,不過,babel 的配置並非本文的重點,我們繼續往下。

不要說細心的小伙伴了,即使是粗心的小伙伴肯定也發現了,我們在使用 webpack 進行打包的時候,一直運行的都是 npx webpack --mode=development 是否可以將 mode 配置在 webpack.config.js 中呢?顯然是可以的。

5.mode

將 mode 增加到 webpack.config.js 中:

module.exports = {
    //....
    mode: "development",
    module: {
        //...
    }
}

mode 配置項,告知 webpack 使用相應模式的內置優化。

mode 配置項,支持以下兩個配置:

  • development:將 process.env.NODE_ENV 的值設置為 development,啟用 NamedChunksPlugin 和 NamedModulesPlugin

  • production:將 process.env.NODE_ENV 的值設置為 production,啟用 FlagDependencyUsagePluginFlagIncludedChunksPluginModuleConcatenationPluginNoEmitOnErrorsPluginOccurrenceOrderPluginSideEffectsFlagPlugin 和 UglifyJsPlugin

現在,我們之間使用 npx webpack 進行編譯即可。

6.在瀏覽器中查看頁面

搞了這么久,還不能在瀏覽器中查看頁面,這顯然不能忍!

查看頁面,難免就需要 html 文件,有小伙伴可能知道,有時我們會指定打包文件中帶有 hash,那么每次生成的 js 文件名會有所不同,總不能讓我們每次都人工去修改 html,這樣不是顯得我們很蠢嘛~

我們可以使用 html-webpack-plugin 插件來幫助我們完成這些事情。

首先,安裝一下插件:

npm install html-webpack-plugin -D 

新建 public 目錄,並在其中新建一個 index.html 文件( 文件內容使用 html:5 快捷生成即可)

修改 webpack.config.js 文件。

//首先引入插件
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
    //...
    plugins: [
        //數組 放着所有的webpack插件
        new HtmlWebpackPlugin({
            template: './public/index.html',
            filename: 'index.html', //打包后的文件名
            minify: {
                removeAttributeQuotes: false, //是否刪除屬性的雙引號
                collapseWhitespace: false, //是否折疊空白
            },
            // hash: true //是否加上hash,默認是 false
        })
    ]
}

此時執行 npx webpack,可以看到 dist 目錄下新增了 index.html 文件,並且其中自動插入了 <script> 腳本,引入的是我們打包之后的 js 文件。

這里要多說一點點東西,HtmlWebpackPlugin 還為我們提供了一個 config 的配置,這個配置可以說是非常有用了。

html-webpack-plugin 的 config 的妙用

有時候,我們的腳手架不僅僅給自己使用,也許還提供給其它業務使用,html 文件的可配置性可能很重要,比如:你公司有專門的部門提供M頁的公共頭部/公共尾部,埋點jssdk以及分享的jssdk等等,但是不是每個業務都需要這些內容。

一個功能可能對應多個 js 或者是 css 文件,如果每次都是業務自行修改 public/index.html 文件,也挺麻煩的。首先他們得搞清楚每個功能需要引入的文件,然后才能對 index.html 進行修改。

此時我們可以增加一個配置文件,業務通過設置 true 或 false 來選出自己需要的功能,我們再根據配置文件的內容,為每個業務生成相應的 html 文件,豈不是美美的。

Let's Go!

首先,我們在 public 目錄下新增一個 config.js ( 文件名你喜歡叫什么就叫什么 ),將其內容設置為:

//public/config.js 除了以下的配置之外,這里面還可以有許多其他配置,例如,pulicPath 的路徑等等
module.exports = {
    dev: {
        template: {
            title: '你好',
            header: false,
            footer: false
        }
    },
    build: {
        template: {
            title: '你好才怪',
            header: true,
            footer: false
        }
    }
}

現在,我們修改下我們的 webpack.config.js:

//webpack.config.js
const HtmlWebpackPlugin = require('html-webpack-plugin');
const isDev = process.env.NODE_ENV === 'development';
const config = require('./public/config')[isDev ? 'dev' : 'build'];

modue.exports = {
    //...
    mode: isDev ? 'development' : 'production'
    plugins: [
        new HtmlWebpackPlugin({
            template: './public/index.html',
            filename: 'index.html', //打包后的文件名
            config: config.template
        })
    ]
}

相應的,我們需要修改下我們的 public/index.html 文件(嵌入的js和css並不存在,僅作為示意):

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <% if(htmlWebpackPlugin.options.config.header) { %>
    <link rel="stylesheet" type="text/css" href="//common/css/header.css">
    <% } %>
    <title><%= (htmlWebpackPlugin.options.config.title) %></title>
</head>

<body>
</body> 
<% if(htmlWebpackPlugin.options.config.header) { %>
<script src="//common/header.min.js" type="text/javascript"></script> 
<% } %>
</html>

process.env 中默認並沒有 NODE_ENV,這里配置下我們的 package.json 的 scripts.

{
    "scripts": {
        "dev": "NODE_ENV=development webpack",
        "build": "NODE_ENV=production webpack"
    }
}

然后我們運行 npm run dev 和 運行 npm run build ,對比下 dist/index.html ,可以看到 npm run build,生成的 index.html 文件中引入了對應的 css 和 js。並且對應的 title 內容也不一樣。

你說這里是不是非得是用 NODE_ENV 去判斷?當然不是咯,你寫 aaa=1 ,aaa=2 都行(當然啦,webpack.config.js 和 scripts 都需要進行相應修改),但是可能會被后面接手的人打死。

如何在瀏覽器中實時展示效果

說了這么多,到現在還沒能在瀏覽器中實時查看效果,是不是已經有點捉急了,先看一下如何實時查看效果吧,不然都不知道自己配得對不對。

話不多說,先裝依賴:

npm install webpack-dev-server -D

修改下咱們的 package.json 文件的 scripts

"scripts": {
    "dev": "NODE_ENV=development webpack-dev-server",
    "build": "NODE_ENV=production webpack"
},

在控制台執行 npm run dev,啟動正常,頁面上啥也沒有,修改下我們的JS代碼,往頁面中增加點內容,正常刷新(也就是說不需要進行任何配置就可以使用了)。

Excuse me。怪我平時不認真咯,每次都乖乖的配個 contentBase,原來根本不需要配,帶着疑問,我又去搜尋了一番。

原來在配置了 html-webpack-plugin 的情況下, contentBase 不會起任何作用,也就是說我以前都是白配了,這是一個悲傷的故事。

不過呢,我們還是可以在 webpack.config.js 中進行 webpack-dev-server 的其它配置,例如指定端口號,設置瀏覽器控制台消息,是否壓縮等等:

//webpack.config.js
module.exports = {
    //...
    devServer: {
        port: '3000', //默認是8080
        quiet: false, //默認不啟用
        inline: true, //默認開啟 inline 模式,如果設置為false,開啟 iframe 模式
        stats: "errors-only", //終端僅打印 error
        overlay: false, //默認不啟用
        clientLogLevel: "silent", //日志等級
        compress: true //是否啟用 gzip 壓縮
    }
}
  • 啟用 quiet 后,除了初始啟動信息之外的任何內容都不會被打印到控制台。這也意味着來自 webpack 的錯誤或警告在控制台不可見 ———— 我是不會開啟這個的,看不到錯誤日志,還搞個錘子

  • stats: "errors-only" , 終端中僅打印出 error,注意當啟用了 quiet 或者是 noInfo 時,此屬性不起作用。————— 這個屬性個人覺得很有用,尤其是我們啟用了 eslint 或者使用 TS進行開發的時候,太多的編譯信息在終端中,會干擾到我們。

  • 啟用 overlay 后,當編譯出錯時,會在瀏覽器窗口全屏輸出錯誤,默認是關閉的。

  • clientLogLevel: 當使用內聯模式時,在瀏覽器的控制台將顯示消息,如:在重新加載之前,在一個錯誤之前,或者模塊熱替換啟用時。如果你不喜歡看這些信息,可以將其設置為 silent (none 即將被移除)。

本篇文章不是為了細說 webpack-dev-server 的配置,所以這里就不多說了。關於 webpack-dev-server 更多的配置可以查看官方文檔。

細心的小伙伴可能發現了一個小問題,我們在src/index.js中增加一句 console.log('aaa')

class Animal {
    constructor(name) {
        this.name = name;
    }
    getName() {
        return this.name;
    }
}

const dog = new Animal('dog');
console.log('aaa');

然后通過 npm run dev 查看效果,會發現:

這顯然不是我們源碼中對應的行號,點進去的話,會發現代碼是被編譯后的,我當前的代碼非常簡單,還能看出來,項目代碼復雜后,“親媽”看編譯后都費勁,這不利於我們開發調試,不是我們想要的,我們肯定還是希望能夠直接對應到源碼的。

7.devtool

devtool 中的一些設置,可以幫助我們將編譯后的代碼映射回原始源代碼。不同的值會明顯影響到構建和重新構建的速度。

對我而言,能夠定位到源碼的行即可,因此,綜合構建速度,在開發模式下,我設置的 devtool 的值是 cheap-module-eval-source-map

//webpack.config.js
module.exports = {
    devtool: 'cheap-module-eval-source-map' //開發環境下使用
}

生產環境可以使用 none 或者是 source-map,使用 source-map 最終會單獨打包出一個 .map 文件,我們可以根據報錯信息和此 map 文件,進行錯誤解析,定位到源代碼。

source-map 和 hidden-source-map 都會打包生成單獨的 .map 文件,區別在於,source-map 會在打包出的js文件中增加一個引用注釋,以便開發工具知道在哪里可以找到它。hidden-source-map 則不會在打包的js中增加引用注釋。

但是我們一般不會直接將 .map 文件部署到CDN,因為會直接映射到源碼,更希望將.map 文件傳到錯誤解析系統,然后根據上報的錯誤信息,直接解析到出錯的源碼位置。

不過報錯信息中只有行號,而沒有列號。如果有行列號,那么可以通過sourcemap 來解析出錯位置。只有行號,根本無法解析,不知道大家的生產環境是如何做的?怎么上報錯誤信息至錯誤解析系統進行解析。如有好的方案,請賜教。

還可以設置其他的devtool值,你可以使用不同的值,構建對比差異。

現在我們已經說了 htmljs 了,並且也可以在瀏覽器中實時看到效果了,現在就不得不說頁面開發三巨頭之一的 css 。

8.如何處理樣式文件呢

webpack 不能直接處理 css,需要借助 loader。如果是 .css,我們需要的 loader 通常有: style-loadercss-loader,考慮到兼容性問題,還需要 postcss-loader,而如果是 less 或者是 sass 的話,還需要 less-loader 和 sass-loader,這里配置一下 less 和 css 文件(sass 的話,使用 sass-loader即可):

先安裝一下需要使用的依賴:

npm install style-loader less-loader css-loader postcss-loader autoprefixer less -D
//webpack.config.js
module.exports = {
    //...
    module: {
        rules: [
            {
                test: /\.(le|c)ss$/,
                use: ['style-loader', 'css-loader', {
                    loader: 'postcss-loader',
                    options: {
                        plugins: function () {
                            return [
                                require('autoprefixer')({
                                    "overrideBrowserslist": [
                                        ">0.25%",
                                        "not dead"
                                    ]
                                })
                            ]
                        }
                    }
                }, 'less-loader'],
                exclude: /node_modules/
            }
        ]
    }
}

測試一下,新建一個 less 文件,src/index.less:

//src/index.less
@color: red;
body{
    background: @color;
    transition: all 2s;
}

再在入口文件中引入此 less:

//src/index.js
import './index.less';

我們修改了配置文件,重新啟動一下服務: npm run dev。可以看到頁面的背景色變成了紅色。

OK,我們簡單說一下上面的配置:

  • style-loader 動態創建 style 標簽,將 css 插入到 head 中.

  • css-loader 負責處理 @import 等語句。

  • postcss-loader 和 autoprefixer,自動生成瀏覽器兼容性前綴 —— 2020了,應該沒人去自己徒手去寫瀏覽器前綴了吧

  • less-loader 負責處理編譯 .less 文件,將其轉為 css

這里,我們之間在 webpack.config.js 寫了 autoprefixer 需要兼容的瀏覽器,僅是為了方便展示。推薦大家在根目錄下創建 .browserslistrc,將對應的規則寫在此文件中,除了 autoprefixer 使用外,@babel/preset-envstylelinteslint-plugin-conmpat 等都可以共用。

注意:  

loader 的執行順序是從右向左執行的,也就是后面的 loader 先執行,上面 loader 的執行順序為: less-loader ---> postcss-loader ---> css-loader ---> style-loader

當然,loader 其實還有一個參數,可以修改優先級,enforce 參數,其值可以為: pre(優先執行) 或 post (滯后執行)。

現在,我們已經可以處理 .less 文件啦,.css 文件只需要修改匹配規則,刪除 less-loader 即可。

現在的一切看起來都很完美,但是假設我們的文件中使用了本地的圖片,例如:

body{
    backgroud: url('../images/thor.png');
}

你就會發現,報錯啦啦啦,那么我們要怎么處理圖片或是本地的一些其它資源文件呢。不用想,肯定又需要 loader 出馬了。

9.圖片/字體文件處理

我們可以使用 url-loader 或者 file-loader 來處理本地的資源文件。url-loader 和 file-loader 的功能類似,但是 url-loader 可以指定在文件大小小於指定的限制時,返回 DataURL,因此,個人會優先選擇使用 url-loader

首先安裝依賴:

npm install url-loader -D

安裝 url-loader 的時候,控制台會提示你,還需要安裝下 file-loader,聽人家的話安裝下就行(新版 npm 不會自動安裝 peerDependencies):

npm install file-loader -D

在 webpack.config.js 中進行配置:

//webpack.config.js
module.exports = {
    //...
    modules: {
        rules: [
            {
                test: /\.(png|jpg|gif|jpeg|webp|svg|eot|ttf|woff|woff2)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 10240, //10K
                            esModule: false 
                        }
                    }
                ],
                exclude: /node_modules/
            }
        ]
    }
}

此處設置 limit 的值大小為 10240,即資源大小小於 10K 時,將資源轉換為 base64,超過 10K,將圖片拷貝到 dist 目錄。esModule 設置為 false,否則,<img src={require('XXX.jpg')} /> 會出現 <img src=[Module Object] />

將資源轉換為 base64 可以減少網絡請求次數,但是 base64 數據較大,如果太多的資源是 base64,會導致加載變慢,因此設置 limit 值時,需要二者兼顧。

默認情況下,生成的文件的文件名就是文件內容的 MD5 哈希值並會保留所引用資源的原始擴展名,例如我上面的圖片(thor.jpeg)對應的文件名如下:

當然,你也可以通過 options 參數進行修改。

//....
use: [
    {
        loader: 'url-loader',
        options: {
            limit: 10240, //10K
            esModule: false,
            name: '[name]_[hash:6].[ext]'
        }
    }
]

重新編譯,在瀏覽器中審查元素,可以看到圖片名變成了: thor_a5f7c0.jpeg

當本地資源較多時,我們有時會希望它們能打包在一個文件夾下,這也很簡單,我們只需要在 url-loader 的 options 中指定 outpath,如: outputPath: 'assets',構建出的目錄如下:

更多的 url-loader 配置可以查看官方文檔

到了這里,有點歲月靜好的感覺了。

不過還沒完,如果你在 public/index.html 文件中,使用本地的圖片,例如,我們修改一下 public/index.html

<img src="./a.jpg" />

重啟本地服務,雖然,控制台不會報錯,但是你會發現,瀏覽器中根本加載不出這張圖片,Why?因為構建之后,通過相對路徑壓根找不着這張圖片呀。

How?怎么解決呢?

10.處理 html 中的本地圖片

安裝 html-withimg-loader 來解決咯。

npm install html-withimg-loader -D

修改 webpack.config.js

module.exports = {
    //...
    module: {
        rules: [
            {
                test: /.html$/,
                use: 'html-withimg-loader'
            }
        ]
    }
}

然后在我們的 html 中引入一張文件測試一下(圖片地址自己寫咯,這里只是示意):

<!-- index.html -->
<img src="./thor.jpeg" />

重啟本地服務,圖片並沒能加載,審查元素的話,會發現圖片的地址顯示的是 {"default":"assets/thor_a5f7c0.jpeg"}

我當前 file-loader 的版本是 5.0.2,5版本之后,需要增加 esModule 屬性:

//webpack.config.js
module.exports = {
    //...
    modules: {
        rules: [
            {
                test: /\.(png|jpg|gif|jpeg|webp|svg|eot|ttf|woff|woff2)$/,
                use: [
                    {
                        loader: 'url-loader',
                        options: {
                            limit: 10240, //10K
                            esModule: false
                        }
                    }
                ]
            }
        ]
    }
}

再重啟本地服務,就搞定啦。

話說使用 html-withimg-loader 處理圖片之后,html 中就不能使用 vmejs 的模板了,如果想繼續在 html 中使用 <% if(htmlWebpackPlugin.options.config.header) { %> 這樣的語法,但是呢,又希望能使用本地圖片,可不可以?魚和熊掌都想要,雖然很多時候,能吃個魚就不錯了,但是這里是可以的哦,刪除html的loader,像下面這樣編寫圖片的地址就可以啦。

<!-- index.html -->
<img src="<%= require('./thor.jpeg') %>" />

圖片加載OK啦,並且 <% %> 語法也可以正常使用,吼吼吼~~~

雖然,webpack 的默認配置很好用,但是有的時候,我們會有一些其它需要啦,例如,我們不止一個入口文件,這時候,該怎么辦呢?

11.入口配置

入口的字段為: entry

//webpack.config.js
module.exports = {
    entry: './src/index.js' //webpack的默認配置
}

entry 的值可以是一個字符串,一個數組或是一個對象。

字符串的情況無需多說,就是以對應的文件為入口。

為數組時,表示有“多個主入口”,想要多個依賴文件一起注入時,會這樣配置。例如:

entry: [
    './src/polyfills.js',
    './src/index.js'
]

polyfills.js 文件中可能只是簡單的引入了一些 polyfill,例如 babel-polyfillwhatwg-fetch 等,需要在最前面被引入(我在 webpack2 時這樣配置過)。

那什么時候是對象呢?不要捉急,后面將多頁配置的時候,會說到。

12.出口配置

配置 output 選項可以控制 webpack 如何輸出編譯文件。

const path = require('path');
module.exports = {
    entry: './src/index.js',
    output: {
        path: path.resolve(__dirname, 'dist'), //必須是絕對路徑
        filename: 'bundle.js',
        publicPath: '/' //通常是CDN地址
    }
}

例如,你最終編譯出來的代碼部署在 CDN 上,資源的地址為: 'https://AAA/BBB/YourProject/XXX',那么可以將生產的 publicPath 配置為: //AAA/BBB/

編譯時,可以不配置,或者配置為 /。可以在我們之前提及的 config.js 中指定 publicPathconfig.js 中區分了 dev 和 public), 當然還可以區分不同的環境指定配置文件來設置,或者是根據 isDev 字段來設置。

除此之外呢,考慮到CDN緩存的問題,我們一般會給文件名加上 hash.

//webpack.config.js
module.exports = {
    output: {
        path: path.resolve(__dirname, 'dist'), //必須是絕對路徑
        filename: 'bundle.[hash].js',
        publicPath: '/' //通常是CDN地址
    }
}

如果你覺得 hash 串太長的話,還可以指定長度,例如 bundle.[hash:6].js。使用 npm run build 打包看看吧。

問題出現啦,每次文件修改后,重新打包,導致 dist 目錄下的文件越來越多。要是每次打包前,都先清空一下目錄就好啦。可不可以做到呢?必須可以!

13.每次打包前清空dist目錄

反正我是懶得手動去清理的,只要你足夠懶,你總是會找到好辦法的,懶人推動科技進步。這里,我們需要插件: clean-webpack-plugin

安裝依賴:

npm install clean-webpack-plugin -D

以前,clean-webpack-plugin 是默認導出的,現在不是,所以引用的時候,需要注意一下。另外,現在構造函數接受的參數是一個對象,可缺省。

//webpack.config.js
const { CleanWebpackPlugin } = require('clean-webpack-plugin');

module.exports = {
    //...
    plugins: [
        //不需要傳參數喔,它可以找到 outputPath
        new CleanWebpackPlugin() 
    ]
}

現在你再修改文件,重現構建,生成的hash值和之前dist中的不一樣,但是因為每次 clean-webpack-plugin 都會幫我們先清空一波 dist 目錄,所以不會出現太多文件,傻傻分不清楚究竟哪個是新生成文件的情況。

希望dist目錄下某個文件夾不被清空

不過呢,有些時候,我們並不希望整個 dist 目錄都被清空,比如,我們不希望,每次打包的時候,都刪除 dll 目錄,以及 dll 目錄下的文件或子目錄,該怎么辦呢?

clean-webpack-plugin 為我們提供了參數 cleanOnceBeforeBuildPatterns

//webpack.config.js
module.exports = {
    //...
    plugins: [
        new CleanWebpackPlugin({
            cleanOnceBeforeBuildPatterns:['**/*', '!dll', '!dll/**'] //不刪除dll目錄下的文件
        })
    ]
}

此外,clean-webpack-plugin 還有一些其它的配置,不過我使用的不多,大家可以查看clean-webpack-plugin

至此,我們算是完成了一個基礎配置。但是這不夠完美,或者說有些時候,我們還會有一些其它的需求。下一篇關於webpack配置的文章會介紹一些其它的情況。

參考資料

  • Peer Dependencies

  • html-webpack-plugin

  • webpack中文文檔


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM