1. 程式人生 > 實用技巧 >從 0 配置 webpack(二)

從 0 配置 webpack(二)

寫在前面

在上篇部落格中,我們介紹了 webpack 基本配置 js、html、css 的方法和本地預覽 webpack-dev-server 的使用。經過上篇部落格的配置,我們已經可以使用 webpack 打包只含有 html+css+js 的前端專案了。

但是我們在日常開發中,使用的功能遠不止於此,因此在專案中使用更高階的語言和功能時要手動配置相關編譯出口和規則。

1. 使用兩個 webpack.config.js

在上述引入 css 的配置過程中,有兩種引入方式,一種是生成 <style> 標籤的形式,一種是抽離成 css 檔案的形式。抽離成 css 檔案的方式肯定要比 <style>

標籤的形式要載入地慢些。在我們使用 webpack-dev-server 預覽時,肯定希望越快越好,因此,在開發過程中使用 <style> 標籤的形式更好些。但是在專案打包時,反到是抽離成 css 檔案的方式要更好些。

由於開發環境和生產環境對 webpack 的配置有不同的要求,因此就產生了使用兩個 webpack.config.js 來滿足不同的需求的開發模式。

webpack 和 webpack-dev-server 的打包和執行都依賴 webpack.cofig.js 檔案。這兩個命令在執行時都預設呼叫 webpack.config.js 或 webpackfile.js(詳可使用 webpack --help檢視)。webpack 允許我們使用 --config 來手動設定呼叫的配置檔案的資訊。

1.1 手動拆分 webpack.config.js

將預設的 webpack.config.js 複製一份命名為 webpack.config.prod.js ,用於生產環境的配置。預設的是開發環境下的配置,也可以改名為 webpack.config.dev.js。然後將二者的 mode 模式修改成對應的模式,並且,在開發模式中使用 <style> 標籤的配置,在生產模式中使用抽離 css 檔案的配置。

上述方式雖然手動劃分成了兩個 webpack.config.js 檔案,但是二者有很多重複的部分,如入口、出口的配置等。因此可以簡化一下,再抽離出一個 webpack.config.base.js

檔案進行繼承和引入。

webpack 的配置檔案本質就是 js 檔案,因此就是按照 js 的方式繼承。如下:

webpack.config.base.js

const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = {
    entry: './src/index.js',
    output: {
        filename: '[name].[contenthash].js'
    },
    plugins: [
        new HtmlWebpackPlugin({
            title: 'My App',
            template: 'src/assets/index.html'
        })
    ]
};

webpack.config.dev.js

const path = require('path');
const base = require('./webpack.config.base')

module.exports = {
    ...base,
    mode: 'development',
    devServer: {
        contentBase: './dist',
    },
    module: {
        rules: [
            {
                test: /\.css$/i,
                use: ['style-loader', 'css-loader']
            },
        ],
    }
};

webpack.config.prod.js

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const base = require('./webpack.config.base')

module.exports = {
    ...base,
    mode: 'production',
    plugins: [
        ...base.plugins,
        new MiniCssExtractPlugin({
            filename: '[name].[contenthash].css',
            chunkFilename: '[id].[contenthash].css',
            ignoreOrder: false,
        })
    ],
    module: {
        rules: [
            {
                test: /\.css$/i,
                use: [
                    {
                        loader: MiniCssExtractPlugin.loader,
                        options: {
                            publicPath: '../'
                        }
                    },
                    'css-loader'
                ]
            },
        ],
    }
};

package.json

"scripts": {
    "build": "rm -rf dist && webpack --config config/webpack.prod.js",
    "start": "webpack-dev-server --config config/webpack.dev.js",
    "test": "echo \"Error: no test specified\" && exit 1"
},

1.2 使用 webpack-merge 工具

也可以使用 webpack config merge 相關的工具 webpack-merge 來進行生產環境和開發環境配置檔案的分離。詳看 webpack-merge

拆分原理是一樣的,也是分成基本、開發、生產三個配置檔案,只不過 webpack-merge 提供了 merge 方法,用於合併配置物件。

安裝 webpack-merge

yarn add webpack-merge --dev

//npm install webpack-merge --save-dev

將上述改成使用 webpack-merge 的方法如下:

config / webpack.common.js

const HtmlWebpackPlugin = require('html-webpack-plugin');
const path = require('path');

module.exports = {
    entry: './src/index.js',
    output: {
        filename: '[name].[contenthash].js'
    },
    plugins: [
        new HtmlWebpackPlugin({
            title: 'My App',
            template: 'src/assets/index.html'
        })
    ]
};

config / webpack.dev.js

const path = require('path');
const common = require('./webpack.common');
const merge = require('webpack-merge');

module.exports = merge(common,{
    mode: 'development',
    devServer: {
        contentBase: './dist',
    },
    module: {
        rules: [
            {
                test: /\.css$/i,
                use: ['style-loader', 'css-loader']
            },
        ],
    }
});

config / webpack.prod.js

const path = require('path');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const common = require('./webpack.common');
const merge = require('webpack-merge');

module.exports = merge(common,{
    mode: 'production',
    plugins: [
        new MiniCssExtractPlugin({
            filename: '[name].[contenthash].css',
            chunkFilename: '[id].[contenthash].css',
            ignoreOrder: false,
        })
    ],
    module: {
        rules: [
            {
                test: /\.css$/i,
                use: [
                    {
                        loader: MiniCssExtractPlugin.loader,
                        options: {
                            publicPath: '../'
                        }
                    },
                    'css-loader'
                ]
            },
        ],
    }
});

package.json

"scripts": {
    "build": "rm -rf dist && webpack --config config/webpack.prod.js",
    "start": "webpack-dev-server --config config/webpack.dev.js",
    "test": "echo \"Error: no test specified\" && exit 1"
  },

以上只是 webpack-merge 的基本用法,更多用法待解鎖。

2. loader 和 plugin 的區別

  1. loader 是載入器,plugin 是外掛
  2. loader 是用來載入某些資原始檔的,比如 babel-loader 會將 js 轉化為所有瀏覽器都支援的 js 檔案格式,style-loader 會將 css 檔案載入成 <style> 標籤放在 html 裡
  3. plugin 外掛是用來擴充套件那 webpack 功能的,比如 HtmlWebpackPlugin 是用來自動生成 html 檔案的,MiniCssExtractPlugin 是用來抽取出單獨的 css 檔案的