Webpack之DLL

文章目录

引入

在我们的项目中,免不了要引入许多的第三方模块。这些第三方模块在打包的时候就会被打包进最后生成的文件之中。导致最后生成的文件过大的同时也增加了打包的时间。

这时我们就会想,如果这些第三方模块能只打包一次,之后就直接使用这些打包好的模块多好,毕竟这些第三方的模块代码不会有变动。

那么,我们再次打包目标代码时就不需要再从node_modules中去寻找第三方模块,而是从我们预先打包出的文件中去寻找。

这种想法颇似动态链接库(DLL)。

流程

由于需要单独打包第三方模块,也就意味着我们需要一个独立的Webpack配置文件,我命名为webpack.dll.js。内容如下:

const path = require('path');
const webpack = require('webpack');
module.exports = {
    mode: 'production',
    entry: {
        react: ['react', 'react-dom'],
        vendors: ['lodash']
    },
    output: {
        path: path.resolve(__dirname, 'dll'),
        filename: '[name].dll.js',
        library: '[name]'
    },
    plugins: [
        new webpack.DLLPliugin({
            name: '[name]',
            path: path.resolve(__dirname, 'dll')
        })
    ]
}

这个配置文件的含义是指将reactreact-dom打包进react.dll.js这个文件中,而lodash则打包进vendors.dll.js里面。同时分别对外暴露两个全局变量,分别叫做reactvendors

plugins内我使用了一个DLLPlugin,这个插件会在path字段所给出的路径生成一个manifest.json。这个json文件包含了importrequire请求到模块ID的映射。这个文件在正式打包项目代码的时候会用到。

接下来就是该正式打包项目代码了,项目代码打包使用的Webpack配置文件如下:

const webpack = require('webpack');
const path = require('path');
module.exports = {
    ...,
    plugins: [
        new webpack.DLLReferencePlugin({
            manifest: path.resolve(__dirname, 'dll/react.manifest.js')
        }),
        new webpack.DLLReferencePlugin({
            manifest: path.resolve(__dirname, 'dll/vendors.manifest.js')
        })
    ]
}

通过引用 dll 的 manifest.json来把依赖的名称映射到模块的 id 上,之后再在需要的时候通过内置的 __webpack_require__ 函数来 require 他们。

接下来就可以直接打包了,应该会发现打包速度快了不少。

可是打开页面会发现,页面并不能显示出任何内容,原因是因为,打包出的dll.js们并没有被网页引入,因此我们还需要一个add-asset-html-webpack-plugin

这是一个为html-webpack-plugin生成的页面再添加静态资源的插件。

以下是完整的plugins设置。

plugins: [
        new CleanWebpackPlugin(),
        new HtmlWebpackPlugin({
            template: './src/index.html'
        }),
        new webpack.HotModuleReplacementPlugin(),
        new AddAssetHtmlWebpackPlugin({
            filepath: path.resolve(__dirname, 'dll/react.dll.js')
        }),
        new AddAssetHtmlWebpackPlugin({
            filepath: path.resolve(__dirname, 'dll/vendors.dll.js')
        }),
        new webpack.DllReferencePlugin({
            manifest: path.resolve(__dirname, 'dll/react.manifest.json')
        }),
        new webpack.DllReferencePlugin({
            manifest: path.resolve(__dirname, 'dll/vendors.manifest.json')
        })
    ]

重新打包,这下子就可以在网页中看到正常现实的内容了。

问题

可能大家也都注意到了,就是项目文件的Webpack配置文件的plugins写的非常繁琐。

假如,打包成DLL的文件又多了几个。那么这边的plugins是不是还要自己手写多个new webpack.DLLReferencePluginnew AddAssetHtmlWebpackPlugin

很显然,有更智能的写法。需要借助Node.js的fs模块。

const fs = require('fs');
const plugins = [
    new CleanWebpackPlugin(),
    new HtmlWebpackPlugin({
        template: './src/index.html'
    }),
    new webpack.HotModuleReplacementPlugin(),
]

fs.readdirSync(path.resolve(__dirname, 'dll')).forEach(file => {
    const filePath = path.resolve(__dirname, `./dll/${file}`);
    if(/.*\.dll.js/.test(file)){
        plugins.push(
            new AddAssetHtmlWebpackPlugin({
                filepath: filePath
            })
        );
    }

    if(/.*\.manifest.json/.test(file)){
        plugins.push(
            new webpack.DllReferencePlugin({
                manifest: filePath
            })
        );
    }
});

这段代码即是检测dll目录下都有哪些manifest.jsondll.js文件,并往plugins中添加相应插件。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章