【webpack系列】從零搭建 webpack4+react 腳手架(二)


html文件如何也同步到dist目錄?bundle.js文件修改了,萬一被瀏覽器緩存了怎么辦?如何為導出的文件加md5?如何把js引用自動添加到html?非業務代碼和業務代碼如何分開打包?如何搭建開發環境?如何實現開發環境的熱更新?

在上一節我們已經搭建了一個最基本的webpack環境, 這一節我們帶着上節的一些疑問,繼續優化我們的react工程。
 
1.整合html-webpack-plugin
 
public的index.html應該自動編譯到dist目錄,並且所有的js引用是自動添加的。你可以使用html-webpack-plugin插件來處理這個優化。
(1)安裝html-webpack-plugin:
npm install --save-dev html-webpack-plugin
(2)在webpack.prod.conf.js中配置plugins屬性。
    const merge = require('webpack-merge');
    const baseWebpackConfig = require('./webpack.base.conf.js');
    const HtmlWebpackPlugin = require('html-webpack-plugin');

    module.exports = merge(baseWebpackConfig, {
        mode: 'production',
        plugins: [
            new HtmlWebpackPlugin({
                template: 'public/index.html',
                inject: 'body',
                minify: {
                    removeComments: true,
                    collapseWhitespace: true,
                    removeAttributeQuotes: true
                },
            })
        ]
    });
(3)刪除index.html中手動引入的script標簽

index.html的代碼應該是這樣的:

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>從零開始搭建react工程</title>
    </head>
    <body>
    <div id="root"></div>
    </body>
    </html>
(4)重新執行編譯
npm run build

查看dist文件夾,index.html也被加載進來了,並且已經自動加上了script標簽。

 

2.為導出的js文件添加內容hash
 
當我們的業務有修改,bundle被重新打包,很可能在客戶的電腦上並沒有奏效,你告訴客戶,應該是被緩存了,需要刷新瀏覽器,清理下瀏覽器緩存。這也許能解決問題,但是太糟糕了,我們有更好的方式,讓導出的js文件加上文件hash,從而每次修改,轉譯出的js文件名稱都不相同,那么js文件當然不會被緩存了。
添加文件hash的方法很簡單,只要修改 output.filename 屬性即可,這里我們做一個小小的優化,把導出的文件存放在js目錄下,並且直接使用name+chunkhash的方式來命名。
filename: "js/[name].[chunkhash:16].js"
其中,name就是模塊名稱,我們在entry中進行過配置,chunkhash是文件內容的hash,webpack默認采用md5的方式對文件進行hash。16是hash的長度,如果不設置,webpack會設置默認值為20。
現在,你的webpack.prod.conf.js文件看起來應該是這樣:
    const merge = require('webpack-merge');
    const baseWebpackConfig = require('./webpack.base.conf.js');
    const HtmlWebpackPlugin = require('html-webpack-plugin');

    module.exports = merge(baseWebpackConfig, {
        mode: 'production',
        output: {
            filename: "js/[name].[chunkhash:16].js",
        },
        plugins: [
            new HtmlWebpackPlugin({
                template: 'public/index.html',
                inject: 'body',
                 minify: {
                    removeComments: true,
                    collapseWhitespace: true,
                    removeAttributeQuotes: true
                },
            })
        ]
    });

 

3.編譯前清理dist目錄
 
現在,如果你修改了你的業務代碼,然后重新編譯,你會發現在dist/js文件夾出現多個js文件。因為導出的js文件hash已經不相同,每次編譯都會增加新的js文件,原來的文件沒有被刪除。所以,我們需要在編譯前進行清理dist文件夾。
(1)安裝clean-webpack-plugin
npm install --save-dev clean-webpack-plugin
(2)修改webpack.prod.conf.js,使用clean-webpack-plugin
    const merge = require('webpack-merge');
    const baseWebpackConfig = require('./webpack.base.js');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const CleanWebpackPlugin = require('clean-webpack-plugin');

    module.exports = merge(baseWebpackConfig, {
        mode: 'production',
        output: {
            filename: "js/[name].[chunkhash:16].js",
        },
        plugins: [
            new HtmlWebpackPlugin({
                template: 'public/index.html',
                inject: 'body',
                minify: {
                    removeComments: true,
                    collapseWhitespace: true,
                    removeAttributeQuotes: true
                },
            }),
            new CleanWebpackPlugin(['../dist'], { allowExternal: true })
        ]
    });
(3)執行試試看
npm run build

編譯過程,注意查看控制台輸出,你會發現webpack刪除了dist目錄。

 

4.非業務代碼單獨打包
 
在build結束,webpack會在終端顯示打包文件的大小,我們可以看到這個app.js包大概在96.9KB

 

隨着我們業務代碼的增加,這個包將會越來越大。
你每次發布,這個文件都會被重新下載。你的代碼有修改,用戶需要重新下載無可厚非。可是,你別忘了這個app.js內還包含了很多不變的代碼,比如react,react-dom。我們需要把這些不變的代碼分開打包。
在webpack.base.conf.js,我們添加一個入口配置。entry有2個入口。

    entry: {
            app: './app/index.js',
            framework:['react','react-dom'],
        },

重新執行npm run build,再看看。

的確,react和react-dom 被編譯成framework.js。可是,你會發現,app.js並沒有減少,還是96.9KB。因為我們還缺少一步,就是抽離app.js中公共的代碼。
webpack3版本是通過配置CommonsChunkPlugin插件來抽離公共的模塊。webpack4版本,官方廢棄了CommonsChunkPlugin,而是改用配置optimization.splitChunks的方式,更加方便。
在webpack.prod.conf.js增加如下代碼:

    optimization: {
            splitChunks: {
                chunks: "all",
                minChunks: 1,
                minSize: 0,
                cacheGroups: {
                    framework: {
                        test: "framework",
                        name: "framework",
                        enforce: true
                    }
                }
            }
        }

cacheGroups對象,定義了需要被抽離的模塊,其中test屬性是比較關鍵的一個值,他可以是一個字符串,也可以是正則表達式,還可以是函數。如果定義的是字符串,會匹配入口模塊名稱,會從其他模塊中把包含這個模塊的抽離出來。name是抽離后生成的名字,和入口文件模塊名稱相同,這樣抽離出來的新生成的framework模塊會覆蓋被抽離的framework模塊,雖然他們都叫framework。
重新執行npm run build你看到app.js的體積變小了 才1kb。

注意查看生成的文件的hash,接下去我們隨意修改app/index.js的代碼。重新執行npm run build編譯。看看編譯后的結果:

看到了嗎,app的hash發生了改變(它不能被瀏覽器緩存),而framework沒有改變(它會被瀏覽器緩存),這達到了我們預期的結果。

5.壓縮js文件
 
打開build后的js文件看看,js文件沒有被壓縮。在prod環境,我們希望js已經被壓縮了,這樣做的好處是減少文件體積,更快地被用戶加載。js壓縮,用到了uglifyjs-webpack-plugin,在optimization內進行配置。
(1)安裝uglifyjs-webpack-plugin
npm install --save-dev uglifyjs-webpack-plugin
(2)在webpack.prod.conf.js頁面上引入
const UglifyJSPlugin = require('uglifyjs-webpack-plugin');
(3)optimization內配置minimizer參數
    minimizer: [
        new UglifyJSPlugin()
    ],

你的optimization參數現在應該是這樣:

     optimization: {
            minimizer: [
                new UglifyJSPlugin()
            ],
            splitChunks: {
                chunks: "all",
                minChunks: 1,
                cacheGroups: {
                    framework: {
                        priority: 200,
                        test: "framework",
                        name: "framework",
                        enforce: true,
                        reuseExistingChunk: true
                    },
                    vendor: {
                        priority: 10,
                        test: /node_modules/,
                        name: "vendor",
                        enforce: true,
                        reuseExistingChunk: true
                    }
                }
            }
        }
(4)重新執行npm run build
npm run build

 

6.整合dev環境
 
我們不可能每次修改代碼都去手動編譯,等編譯出來再去打開文件查看效果。webpack提供了開發環境服務,並且支持熱更新,這在開發環境是非常有必要的。
webpack-dev-server這個模塊提供了開發服務的支持,通過在webpack.dev.conf.js文件配置devServer可以方便地整合webpack-dev-server。
(1)安裝webpack-dev-server
npm install --save-dev webpack-dev-server
(2)在build中添加webpack.dev.conf.js文件
    const path = require('path');
    const merge = require('webpack-merge');
    const baseWebpackConfig = require('./webpack.base.conf.js');
    const HtmlWebpackPlugin = require('html-webpack-plugin');
    const webpack = require('webpack');

    module.exports = merge(baseWebpackConfig, {
        mode: 'development',
        output: {
            filename: "js/[name].[hash:16].js",
        },
        plugins: [
            new HtmlWebpackPlugin({
                template: 'public/index.html',
                inject: 'body',
                minify: {
                    html5: true
                },
                hash: false
            }),
            new webpack.HotModuleReplacementPlugin()
        ],
        devServer: {
            port: '8080',
            contentBase: path.join(__dirname, '../public'),
            compress: true,
            historyApiFallback: true,
            hot: true,
            https: false,
            noInfo: true,
            open: true,
            proxy: {}
        }
    });

HotModuleReplacementPlugin是webpack熱更新的插件,設置devServer.hot為true,並且在plugins中引入HotModuleReplacementPlugin插件即可。
還需要注意的是我們開啟了hot,那么導出不能使用chunkhash,需要替換為hash。

(3)在package.json增加一個npm scripts
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
(4)執行dev命令
npm run dev

打開 http://localhost:8080 查看,你可以嘗試改動index.js的代碼,瀏覽器自動更新了,說明整合webpack-dev-server成功。
你可能注意到,對於css相關的技術棧,我只字未提,別急,下一節我們會詳細針對css相關的技術棧進行整合。


免責聲明!

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



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