• 【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相关的技术栈进行整合。

  • 相关阅读:
    十一作业
    11.20
    11.13 第十二次、
    11.13 第十一次、
    11.06第十次、
    11.06第九次、
    10.30
    10.23
    10.16
    10.9
  • 原文地址:https://www.cnblogs.com/nianzhilian/p/10229122.html
Copyright © 2020-2023  润新知