1. 程式人生 > >webpack4.x抽取css【extract-text-webpack-plugin與mini-css-extract-plugin】

webpack4.x抽取css【extract-text-webpack-plugin與mini-css-extract-plugin】

本文主要記錄筆者在使用webpack抽取css時遇到的一些問題。

專案的初始訴求是利用webpack來管理css(合併),並增加hash(效能優化),當前專案使用webpack版本為4.6.0。

開始選擇的外掛是extract-text-webpack-plugin,安裝命令如下:

sudo npm install extract-text-webpack-plugin

此時webpack配置檔案如下:

const path = require("path");
const htmlWebpackPlugin = require('html-webpack-plugin');
const cleanWebpackPlugin = require('clean-webpack-plugin');
const extractTextPlugin = require('extract-text-webpack-plugin');

module.exports = {
    entry: "./js/main.js",
    output: {
        path: path.resolve(__dirname, "build"),
        publicPath: "/build/",
        filename: "index.[chunkhash:8].js"
    },
    module: {
        rules: [
            {
                test: /\.js$/ ,
                loader: 'babel-loader',
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                use: extractTextPlugin.extract({
                    fallback: 'style-loader',
                    use: [
                        {
                            loader: 'css-loader',
                            options: {
                                url: false
                            }
                        }
                    ]
                })
            }
        ]
    },
    devtool: 'inline-source-map',
    mode: 'development',
    plugins: [
        new htmlWebpackPlugin({
            filename: '../index.html',
            template: 'html/index.html',
            inject: 'body'
        }),
        new htmlWebpackPlugin({
            filename: '../login.html',
            template: 'html/login.html',
            inject: 'body'
        }),
        new htmlWebpackPlugin({
            filename: '../mail.html',
            template: 'html/mail.html',
            inject: 'body'
        }),
        new htmlWebpackPlugin({
            filename: '../pinboard_copy_link.html',
            template: 'html/pinboard_copy_link.html',
            inject: 'body'
        }),
        new cleanWebpackPlugin(['build']),
        new extractTextPlugin({
            filename: 'focus.index.css'
        })
    ]
};

但是構建時會報如下錯誤:

Error: Chunk.entrypoints: Use Chunks.groupsIterable and filter by instanceof Entrypoint instead

檢查以後發現原因是extract-text-webpack-plugin預設安裝的版本是3.0.2,還不支援webpack的4.x版本。其實在初始安裝時就有告警提示,只是被忽略了:

在這裡插入圖片描述

接下來看一下extract-text-webpack-plugin有沒有方案來解決這個版本配套問題,百度以後瞭解到有extract-text-webpack-plugin有一個4.0的beta版本支援webpack4.x,把前面安裝的extract-text-webpack-plugin的3.0.2版本解除安裝, 重新安裝這個beta版本,安裝命令如下:

sudo npm install --save-dev [email protected]

此時可以正常構建了,也完成了第一個訴求——合併css,接下來是為css生成hash。

webpack配置檔案的最後一部分更新為:

new extractTextPlugin({
    filename: 'focus.index.[contenthash:8].css'
})

但是構建時會報如下錯誤:

Error: Path variable [contenthash:8] not implemented in this context: focus.index.[contenthash:8].css

報錯截圖如下:

在這裡插入圖片描述

要用extract-text-webpack-plugin加hash看來是無解了,只能看看還有沒有其他外掛可以替代extract-text-webpack-plugin,又百度了一發,瞭解到可以用mini-css-extract-plugin替代extract-text-webpack-plugin,安裝命令如下:

sudo npm install mini-css-extract-plugin

webpack配置檔案更新如下(之前使用extract-text-webpack-plugin的部分已經註釋):

const path = require("path");
const htmlWebpackPlugin = require('html-webpack-plugin');
const cleanWebpackPlugin = require('clean-webpack-plugin');
// const extractTextPlugin = require('extract-text-webpack-plugin');
const miniCssExtractPlugin = require('mini-css-extract-plugin');

module.exports = {
    entry: "./js/main.js",
    output: {
        path: path.resolve(__dirname, "build"),
        publicPath: "/build/",
        filename: "index.[chunkhash:8].js"
    },
    module: {
        rules: [
            {
                test: /\.js$/ ,
                loader: 'babel-loader',
                exclude: /node_modules/
            },
            {
                test: /\.css$/,
                // use: extractTextPlugin.extract({
                //     fallback: 'style-loader',
                //     use: [
                //         {
                //             loader: 'css-loader',
                //             options: {
                //                 url: false
                //             }
                //         }
                //     ]
                // })
                use: [
                    miniCssExtractPlugin.loader,
                    {
                        loader: 'css-loader',
                        options: {
                            url: false
                        }
                    }
                ]
            }
        ]
    },
    devtool: 'inline-source-map',
    mode: 'development',
    plugins: [
        new htmlWebpackPlugin({
            filename: '../index.html',
            template: 'html/index.html',
            inject: 'body'
        }),
        new htmlWebpackPlugin({
            filename: '../login.html',
            template: 'html/login.html',
            inject: 'body'
        }),
        new htmlWebpackPlugin({
            filename: '../mail.html',
            template: 'html/mail.html',
            inject: 'body'
        }),
        new htmlWebpackPlugin({
            filename: '../pinboard_copy_link.html',
            template: 'html/pinboard_copy_link.html',
            inject: 'body'
        }),
        new cleanWebpackPlugin(['build']),
        // new extractTextPlugin({
        //     filename: 'focus.index.[contenthash:8].css'
        // })
        new miniCssExtractPlugin({
            filename: 'focus.index.[contenthash:8].css'
        })
    ]
};

最後終於構建成功了:

在這裡插入圖片描述

最後總結一下:

  1. 如果當前專案是webpack3.x版本,使用extract-text-webpack-plugin;
  2. 如果當前專案是webpack4.x版本(但已有extract-text-webpack-plugin配置),可以繼續用extract-text-webpack-plugin,但必須用對應的beta版本,且這個beta版本不支援生成hash;
  3. 如果當前專案是webpack4.x版本且是新專案,使用mini-css-extract-plugin。