美文网首页
Webpack dll优化实战

Webpack dll优化实战

作者: 广兰路地铁 | 来源:发表于2019-09-28 09:49 被阅读0次

    DLL是什么,用它来干啥?

      DLL(Dynamic Link Libray)原来特指windows系统中实现共享函数库的一种方式,扩展名通常为.dll。玩过老windows游戏的同学应该对这种文件不陌生,很多游戏的安装盘下就有很多.dll的文件。DLL通常是已经编译、链接的二进制文件,方便程序直接调用。

    前端应用场景

      在大型项目的开发过程中,往往会用到很多公共库,公共库的内容不同于业务代码,在很长的一个时间周期内都不会有改动。这部分公共库通常会被打包在commonChunk中,webpack配置节选如下:

        optimization: {
            splitChunks: {
                minSize: 1000000,
                cacheGroups: {
                    vendor: {
                        name: "common",
                        test: /[\\/]node_modules[\\/]/,
                        chunks: "initial",
                        minSize: 30000,
                        minChunks: 1,
                        priority: 8
                    }
                },
            }
        },
    

      这样可以把长时间不变的公共包内容打包进一个名为common的chunk中,同业务代码进行隔离,生成稳定的缓存key,以便浏览器端实现缓存。但是这也带来一个问题:尽管用户端实现了缓存,但是我们在打包的时候,webpack依然会对所有用到的公共包进行遍历,解析,处理。严重影响打包速度。
      webpack中的DLL打包优化,同windows中的DLL的原理类似。通过另写一份打包配置,把长期不变的公共包内容单独打包,然后在业务代码打包时,通用webpack内置插件DllReferencePlugin引用之前打包的动态链接内容,而不是每次都打包同样的公共包内容,从而加快打包速度。

    项目实战

    接下来笔者将以自己项目为例,进行webpack dll优化。
    使用原来的打包配置,结果如下:

    image
    打包耗时:
    image
    接下来,在项目中添加webpack.dll.config.js文件,对一些固定不变的内容提前打成dll资源:
    const webpack = require('webpack')
    const library = '[name]_dll'
    const path = require('path');
    const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
    
    module.exports = {
      entry: {
        vendors: ['react', 'mobx', 'mobx-react', 'antd', 'socket.io-client']
      },
    
      output: {
        filename: '[name]_dll.js',
        path: path.resolve(__dirname, 'dist'),
        //publicPath: path.resolve(__dirname, 'dist'),
        publicPath: './',
        library
      },
    
      plugins: [
        new webpack.DllPlugin({
          path: path.join(__dirname, 'dist/[name]-manifest.json'),
          // This must match the output.library option above
          name: library
        }),
        new BundleAnalyzerPlugin({
            analyzerPort: 8899
        })
      ],
    }
    

    打包结果如下(vendors_dll.js: 685kb):

    image
    这个dll包压缩后还有600多kb!
    接下来我们再对项目代码进行打包,在webpack配置文件中添加如下插件:
        plugins: [
            ......
            //  动态链接库
            new webpack.DllReferencePlugin({
                context: __dirname,
                manifest: require('./dist/vendors-manifest.json')
            }),
            ......
        ]    
    

    打包大小:

    image
    打包时间:
    image
      通过如上实验我们可以发现,使用DllReferencePlugin插件后,打包时间大幅缩小,从原来的16s缩减到10秒左右,这是由于相当部分的资源已经提前构建好,在业务代码改变的时候,自然就不用重复打包浪费时间了。但同时暴露出一个问题:原先的打包方式打包文件的体积大概是378kb,使用dll之后,打包体积是dll资源与业务代码之和(685kb+92kb),整整大了两倍。要知道,dll文件浏览器也是需要下载的,这样完全是无法接受的。通过对打包内容的分析,我们可以发现webpack.dll.config.js文件的入口不是业务代码,直接是各个公共包,这就意味着dll显然是无法使用treeShake等等优化特性的,比如antd这个包,优化前使用treeShake按需加载,打包体积只有168kb左右,而在dll包中,antd整个包都进行了引入,体积膨胀到了250kb左右。由此我们可以得到一个重要的实战经验:针对antd,lodash等等可以使用按需加载的公共库,不能提前打包在dll中,像react,mobx等等必然会全盘引入的公共库才是最适合放入dll中的。
      接下来我们修改一下webpack.dll.config.js的entry配置(删掉antd):
      entry: {
        vendors: ['react', 'mobx', 'mobx-react', 'socket.io-client']
      },
    

    dll打包结果(vendors_dll:84kb):

    image
    业务代码打包结果:
    image
    二者相加,打包文件体积与使用DllReferencePlugin前相仿。打包时间缩减了两秒,在不增加打包文件体积的前提下,减少了打包时间。

    如何将vendors_dll.js插入html?

      笔者在实践过程中还发现一个问题,打包后的vendors_dll.js并没有被HtmlWebpackPlugin所识别,导致输出的HTML文件里没有这个资源,解决方法如下,在html模板文件的body添加一个script标签,并且附带内容模板:

    <body>
        <div id='main'></div>
        <script type="text/javascript" src="<%= htmlWebpackPlugin.options.vendor %>"></script>
    </body>
    

    然后在webpack文件中作如下更改:

    //  头部引入打包好的文件
    const manifest = require('./dist/vendors-manifest.json'); 
    ......
    
        plugins: [
            ......
            new HtmlWebpackPlugin({
                filename: '../dist/index.html',
                template: './views/template.html',
                inject: 'body',
                //  添加vendor,替换html模板中的内容
                vendor: './' + manifest.name + '.js' //manifest就是dll生成的json
            }),
            ......
        ]
    

    最后在输出的html中将会带上我们的dll文件。


    上文中用到的例子:https://github.com/dianluyuanli-wp/chat

    相关文章

      网友评论

          本文标题:Webpack dll优化实战

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