一個合格的Webpack4配置工程師素養:第一部分

小諾哥發表於2019-01-26

標題黨

總結Webpack4常見的配置, 含DEMO, 一步步肥腸詳細,略長, 後續結束時候我們給出原始碼檔案。

準備開發環境

- 安裝node
- 安裝webpack
- npm init 初始化專案
複製程式碼

目錄結構

目錄

寫跑一個小demo

// src/index.js

import _ from 'lodash'

function create_div_element () {
    const div_element = document.createElement('div')
    div_element.innerHTML = _.join(['kobe', 'cpul'], ' ')
    return div_element
}

const div_ele = create_div_element()
document.body.appendChild(div_ele)

複製程式碼
// dist/index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>webpack4</title>
</head>
<body>
    <script src="./bound.js"></script>
</body>
</html>

複製程式碼
// webpack.config.js

const path = require('path')

module.exports = {
    entry: './src/index.js',
    mode: 'development',
    output: {
        filename: 'bound.js',
        path: path.resolve(__dirname, 'dist')
    }
}

複製程式碼

然後通過npx執行webpack進行打包。

或者配成一個script命令也可以。

"scripts": {
    "build": "npx webpack -c webpack.config.js"
 }
複製程式碼
npx webpack
複製程式碼

在瀏覽器開啟index.html就會發現程式碼執行成功了。

webpack處理CSS

假設我們現在需要在index.js引入css檔案。

// index.js

import './style/reset.css'
複製程式碼

我們需要使用專門的loader來解析css, 並把css注入到html檔案

 npm i -D css-loader style-loader
複製程式碼

修改webpack配置檔案

const path = require('path')

module.exports = {
    entry: './src/index.js',
    mode: 'development',
    output: {
        filename: 'bound.js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.css/,
                use: ['style-loader', 'css-loader'] // use的順序從右往左
            }
        ]
    }
}
複製程式碼

這個時候你在npx webpack, 打包後執行index.html你會發現css已經注入成功了。

webpack處理sass檔案

現在前端專案都是使用一些css前處理器來幫助更好的使用CSS,如Sass等。

假設我們現在index.js中需要引入一個base.scss檔案。 那麼webpack改如何處理sass/scss檔案呢?

npm install sass-loader node-sass -D
複製程式碼
// src/style/base.scss

$bd-bg: pink;
body {
    background: $bd-bg;
}
複製程式碼
// index.js

import './style/base.scss'
複製程式碼

更過配置檔案處理scss

const path = require('path')

module.exports = {
    entry: './src/index.js',
    mode: 'development',
    output: {
        filename: 'bound.js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.(sc|sa|c)ss$/,
                use: ['style-loader', 'css-loader', 'sass-loader'] // use的順序從右往左
            }
        ]
    }
}

複製程式碼

webpack為sass新增source map

配置source map是為了當出現錯誤時候方便我們進行定位除錯, 當然我們在生產環境不需要啟動這個。

像我們上面例子中, 你會發現打包後我們看不出scss來自哪個檔案。

noe-source-map

修改webpack配置檔案。

const path = require('path')

module.exports = {
    entry: './src/index.js',
    mode: 'development',
    output: {
        filename: 'bound.js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.(sc|sa|c)ss$/,
                use: [
                    {
                        loader: 'style-loader'
                    },
                    {
                        loader: 'css-loader',
                        options: {
                            sourceMap: true
                        }
                    },
                    {
                        loader: 'sass-loader',
                        options: {
                            sourceMap: true
                        }
                    }
                ]
            }
        ]
    }
}

複製程式碼

打包後在瀏覽器開啟index.html.

sourcemap

webpack為css新增CSS3字首

PostCSS是一個用 JavaScript 工具和外掛轉換 CSS 程式碼的工具, 功能強大, 我們最常用的就是利用PostCSS幫我們Autoprefixer 自動獲取瀏覽器的流行度和能夠支援的屬性,並根據這些資料幫你自動為 CSS 規則新增字首。

npm i -D postcss-loader autoprefixer postcss-import

// postcss-import: 在使用@import css檔案時候讓webpack可以監聽並編譯
// postcss-nextcss: 支援css4
複製程式碼

修改配置檔案

rules: [
    {
        test: /\.(sc|sa|c)ss$/,
        use: [
            {
                loader: 'style-loader'
            },
            {
                loader: 'css-loader',
                options: {
                    sourceMap: true
                }
            },
            {
                loader: 'postcss-loader',
                options: {
                    ident: 'postcss',
                    sourceMap: true,
                    plugins: loader => [
                        // 可以配置多個外掛
                        require('autoprefixer')({
                            browsers: [' > 0.15% in CN ']
                        })
                    ]
                }
            },
            {
                loader: 'sass-loader',
                options: {
                    sourceMap: true
                }
            }
        ]
    }
]
複製程式碼

css3字首

抽離樣式表為單獨的css檔案並打版本號

抽離css前提是我們只在生產環境這麼做, 因此你的配置檔案的mode: production。

另外抽離了css就不能在使用style-loader注入到html檔案。

npm i -D mini-css-extract-plugin
複製程式碼

配置一個script命名

"scripts": {
    "dist": "cross-env NODE_ENV=production npx webpack --progress --config webpack.prod.config.js"
  },
複製程式碼

新增一個webpack.prod.config.js.當然正式專案我們是會拆分配置檔案, 然後通過merge處理。

- webpack.base.config.js
- webpack.dev.config.js
- webpack.prod.config.js
- webpack.vue.config.js
複製程式碼

這裡demo就沒有這麼做, 所以程式碼有些冗餘。

// webpack.prod.config.js

const path = require('path')
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const devMode = process.env.NODE_ENV !== 'production'

module.exports = {
    entry: './src/index.js',
    mode: 'production',
    output: {
        filename: 'bound.js',
        path: path.resolve(__dirname, 'dist')
    },
    module: {
        rules: [
            {
                test: /\.(sc|sa|c)ss$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    {
                        loader: 'css-loader'
                    },
                    {
                        loader: 'postcss-loader',
                        options: {
                            ident: 'postcss',
                            plugins: (loader) => [
                                require('autoprefixer')({
                                    browsers: [
                                        'last 10 Chrome versions',
                                        'last 5 Firefox versions',
                                        'Safari >= 6',
                                        'ie > 8'
                                    ]
                                })
                            ]
                        }
                    },
                    {
                        loader: 'sass-loader'
                    }
                ]
            }
        ]
    },
    plugins: [
        new MiniCssExtractPlugin({
            filename: devMode ? '[name].css' : '[name].[hash:5].css', // 設定輸出的檔名
            chunkFilename: devMode ? '[id].css': '[id].[hash:5].css'
        })
    ]
}

複製程式碼

打包後你會發現

main.css

這個時候我們如果去使用只能在index.html去引用它了, 很明顯這是不方便的, 因為我們css檔案肯定很龐大, 後面會解決這個問題, 這裡就略過。

webpack壓縮JS和CSS

壓縮的作用自然是為了減小包的體積了, 提升載入效率, 因此壓縮都是配置在生產環境。

壓縮css

Webpack後面版本應該會內建CSS壓縮, 目前先手工配置。

npm i -D optimize-css-assets-webpack-plugin
複製程式碼

更改配置檔案:

const OptimizeCSSAssertsPlugin = require('optimize-css-assets-webpack-plugin')

optimization: {
    minimizer: [
        // 壓縮CSS
        new OptimizeCSSAssertsPlugin({})
    ]
}
複製程式碼

壓縮css

JS壓縮

npm i -D uglifyjs-webpack-plugin
複製程式碼

修改配置檔案

const UglifyJsPlugin = require('uglifyjs-webpack-plugin')

optimization: {
    minimizer: [
        // 壓縮JS
        new UglifyJsPlugin({
            // 有很多可以配置
            cache: true,
            parallel: true,
            sourceMap: true,
            uglifyOptions: {
                 // 在UglifyJs刪除沒有用到的程式碼時不輸出警告
                warnings: false,
                output: {
                    // 刪除所有的註釋
                    comments: false,
                    // 最緊湊的輸出
                    beautify: false
                },
                compress: {
                    // 刪除所有的 `console` 語句
                    // 還可以相容ie瀏覽器
                    drop_console: true,
                    // 內嵌定義了但是隻用到一次的變數
                    collapse_vars: true,
                    // 提取出出現多次但是沒有定義成變數去引用的靜態值
                    reduce_vars: true,
                }
            }
        })
    ]
}
複製程式碼

這個時候去打包我發現一個錯誤, ERROR in js/background.js from UglifyJs Unexpected token: keyword (const)

Uglify-js不支援es6語法,請使用terser外掛, 於是我們更改使用terser外掛試試, 其實你繼續用uglifyjs-webpack-plugin也可以, 只需要配合babel先轉下。

npm install terser-webpack-plugin -D
複製程式碼

更多使用見官網terser-webpack-plugin


optimization: {
    minimizer: [
        // 壓縮JS
        new TerserPlugin({
            cache: true,
            parallel: true,
            sourceMap: true,
            // 等等詳細配置見官網
        }),

    ]
}
複製程式碼

壓縮js

後續章節

相關文章