美文网首页前端技术
深究 webpack 代码分离优化(一)

深究 webpack 代码分离优化(一)

作者: zbcy0012 | 来源:发表于2018-12-04 17:00 被阅读0次

    出发版本 webpack 4.26.1

    阅读之前

    需要你事先了解一点关于 webpack 的基本配置方法和理论知识。

    准备知识

    • 根据 webpack 官网介绍,第四版 webpack 已经删除掉了原 webpack.optimize.CommonsChunkPlugin,需要使用在 config 里面配置的 optimization 属性下的属性 splitChunks 替换之。所以如果你是用的是 webpack 第三版或更老的版本,请略过本文,直接搜索CommonsChunkPlugin
    • 使用 html-webpack-plugin 辅助生成 html 模板。
      你可以选择参考我的文章

    第一节、代码分离

    我们先写打包前的源码,并梳理逻辑关系。
    我们的文件分布如下

    + dist
    + node_modules
    - src
       app1.js
       app2.js
       app3.js
       app4.js
       index.js
       index2.js
       index3.js
    index.html
    index2.html
    index3.html
    package.json
    webpack.config.js
    

    src 文件夹中 index.js 用于配合 index.html 入口; index2.js 用于配合 index2.html 入口; index3.js 用于配合 index3.html 入口。
    逻辑关系如下:

    //index.js
    import './app1';
    import './app2';
    
    //index2.js
    import './app1';
    import './app2';
    import './app3';
    
    //index3.js
    import './app3';
    import './app4';
    
    //app1.js
    console.log("app1");
    ...    //八千行
    console.log("app1");
    alert("app1");
    
    //app2.js
    console.log("app2");
    ...    //八千行
    console.log("app2");
    alert("app2");
    
    //app3.js
    console.log("app3");
    ...    //八千行
    console.log("app3");
    alert("app3");
    
    //app4.js
    console.log("app4");
    ...    //八千行
    console.log("app4");
    alert("app4");
    

    【解释】我们用简单的 console.log()来表示动作发生,以数量堆积来模拟一个计算量大的包,并最终用 alert 来标记执行结束。

    1.默认效果

    我们先不使用代码分离,设置3个入口文件并设置打包查看效果

    配置 webpack.config.js
    const path = require("path");
    const HtmlWebpackPlugin = require("html-webpack-plugin");
    
    module.exports = {
        entry: {
            index: "./src/index.js",
            index2: "./src/index2.js",
            index3: "./src/index3.js"
        },
        output: {
            filename: "[name].bundle.js",
            path: path.resolve(__dirname, "dist")
        },
        plugins: [
            new HtmlWebpackPlugin({
                filename: "index.html",
                template: "./index.html",
                chunks: ["index"]
            }),
            new HtmlWebpackPlugin({
                filename: "index2.html",
                template: "./index2.html",
                chunks: ["index2"]
            }),
            new HtmlWebpackPlugin({
                filename: "index3.html",
                template: "./index3.html",
                chunks: ["index3"]
            })
        ]
    };
    

    可以清楚滴看到,三个入口命名为 index/index2/index3 ,这将指示 webpack 至少要打包出3个文件来。并且下面的每一个 HtmlWebpackPlugin 模板都配置了相应的 chunks。 这表示的是将来生成的html文件将会依赖谁,如果不注明的话,这三个html模板都将会引入全部入口文件。
    此时运行

     npm run build
    

    生成文件如下(dist文件夹内部)

    index.bundle.js          //296k
    index.html               //1k
    index2.bundle.js         //446k
    index2.html              //1k
    index3.bundle.js         //292k
    index3.html              //1k
    

    观察其打包结果: webpack 解析了每一个入口 js 文件的依赖关系并进行了按需分配,最终给每一个入口文件打包成一个文件(当中包含所有依赖)。对于小型项目这样已经可以了,但是如果是比较庞大的项目就会有进一步的优化空间。index 和 index2 都依赖了 app1 和 app2;index2 又有自己独需的 app3,假如一个请求同时要求 index 和 index2,那么毫无疑问,传输的两个 bundle 文件就会产生重复代码。这个影响是大型项目中明显的性能问题。所有已有必要进行代码分离。

    2.使用 splitChunks 去重

    使用此组件无需再安装,已经被放置在 webpack 当中(是 cli 里面还是 webpack 里面,这个我也不知道 -_-!)。所以直接配置就好。

    配置 webpack.config.js
    const path = require("path");
    const HtmlWebpackPlugin = require("html-webpack-plugin");
    
    //代码分离
    module.exports = {
        entry: {
            index: "./src/index.js",
            index2: "./src/index2.js",
            index3: "./src/index3.js"
        },
        output: {
            filename: "[name].bundle.js",
            path: path.resolve(__dirname, "dist")
        },
        optimization: {
            splitChunks: {
                chunks: "async",
                // minSize: 30000,      //指定当文件包超过多大时应该被分离出来
                minSize: 1,             //这里我们期望的实验效果是只要是可以被分离出来的复用代码,都给我出来
                minChunks: 1,
                maxAsyncRequests: 5,
                maxInitialRequests: 3,
                automaticNameDelimiter: "~",
                name: true,
                cacheGroups: {
                    commons: {
                        name: "commons",
                        chunks: "initial",
                        minChunks: 2
                    },
                    vendors: {
                        test: /[\\/]node_modules[\\/]/,
                        priority: -10
                    },
                    default: {
                        minChunks: 2,
                        priority: -20,
                        reuseExistingChunk: true
                    }
                }
            }
        },
    
        plugins: [
            new HtmlWebpackPlugin({
                filename: "index.html",
                template: "./index.html",
                chunks: ["index", "commons"]
            }),
            new HtmlWebpackPlugin({
                filename: "index2.html",
                template: "./index2.html",
                chunks: ["index2", "commons"]
            }),
            new HtmlWebpackPlugin({
                filename: "index3.html",
                template: "./index3.html",
                chunks: ["index3", "commons"]
            })
        ]
    };
    

    这里我们将3个 html 模板的依赖都加了一个 “commons”。
    执行

    npm run build
    

    生成文件如下(dist文件夹内部)

    commons.bundle.js          //446k
    index.bundle.js          //2k
    index.html               //1k
    index2.bundle.js         //2k
    index2.html              //1k
    index3.bundle.js         //143k
    index3.html              //1k
    

    现在你可以看到,凡是可以被抽离出来的复用代码都被打包进了commons.bundle.js ,形成了一个“库”,可供我们调取其中的方法。index3里面有着他自己独需的 app4,app4的内容就被封至index3 的内部了,所以比其他 index 文件大。这样我们的代码在理论上达到了最小化的“瘦身”效果,总体上来看,代码总量是最小的了,已经删去了所有不必要的重复。

    但是做到这样还是不行,因为你会发现每当你想访问 index3 时,他要加载自己的 index3.html 和 index3.bundle.js 这不必解释,但是他为了要表达 app3 的动作就还要加载 commons.bundle.js这个库。但是加载这个库就同时加载了不必要的 app1 和 app2 动作,不使用的巨量代码带来的网速迟缓也是一个大型项目中的巨大问题。如何才能只加载当前入口需要的文件呢?我认为应该进一步分割代码。
    下一节我将探索利用缓存以及 manifest 来提升应用性能?


    作者知识水平有限,如有错误,敬请交流指正。
    -------------结束线----------------

    相关文章

      网友评论

        本文标题:深究 webpack 代码分离优化(一)

        本文链接:https://www.haomeiwen.com/subject/vkwycqtx.html