使用 Webpack 的 DllPlugin 提高项目构建速度

本文介绍了 Webpack 中 DllPlugin 插件的使用,以及配合使用 AddAssetHtmlPlugin 将构建好的 JS 文件插入到 html 页面中。html

本文 Demo 地址

本文项目代码位置:源码地址node

欢迎 Star!react


DLLPlugin 和 DllReferencePlugin 简介

DLLPlugin 就是将包含大量复用模块且不会频繁更新的库进行编译,只须要编译一次,编译完成后存在指定的文件(这里能够称为动态连接库)中。在以后的构建过程当中不会再对这些模块进行编译,而是直接使用 DllReferencePlugin 来引用动态连接库的代码。所以能够大大提升构建速度。通常会对经常使用的第三方模块使用这种方式,例如 react、react-dom、lodash 等等。只要这些模块不升级更新,这些动态连接库就不须要从新编译。webpack


在 Webpack 中进行使用

须要插件

Webpack 已经内置了对动态连接库的支持,须要经过两个内置插件的配合使用。它们分别是:git

  • DllPlugin 插件:用于打包出一个个单独的动态连接库文件
  • DllReferencePlugin 插件:用于在主配置文件中去引入 DllPlugin 插件打包好的动态连接库文件

建立项目

找一个空文件夹,打开命令行,执行命令

# 建立项目目录
$ mkdir webpack-dll-demo

# 初始化 package.json 文件
$ npm init -y 

# 建立 src 文件夹
$ mkdir src

# 建立 public 文件夹
$ mkdir public

# 安装须要用到的插件
$ npm install webpack webpack-cli html-webpacl-plugin clean-webpacl-plugin friendly-errors-webpack-plugin -D

# 安装 lodash 插件,用于演示 DllPlugin 用法
$ npm install lodash
复制代码

在 public 目录下建立 index.html 文件

index.htmlgithub

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Webpak DllPlugin 的使用</title>
</head>
<body>
    <div id="root"></div>
</body>
</html>
复制代码

在 src 目录下建立 index.js 文件

index.jsweb

import { join } from 'lodash';

function createSpan(){
    const element = document.createElement('span');
    element.innerHTML = join(['Hello', 'DllPlugin'], ' , ');
    return element;
}

document.querySelector('#root').appendChild(createSpan());
复制代码

当前项目目录结构

webpack-prod-demo
|- /public
  |- index.html
|- /src
  |- index.js
|- package.json
复制代码

使用 DllPlugin 和 DllReferencePlugin(分为三步)

1、先编写一个配置文件专门用来编译生成动态连接库(使用 DllPlugin)

webpack_dll.config.jsnpm

const path = require('path');
const webpack = require('webpack');
const CleanWebpaclPlugin = require('clean-webpack-plugin');
const FirendlyErrorePlugin = require('friendly-errors-webpack-plugin');

module.exports = {
    mode: 'production',
    entry: {
        // 将 lodash 模块做为入口编译成动态连接库
        lodash: ['lodash']
    },
    output: {
        // 指定生成文件所在目录
        // 因为每次打包生产环境时会清空 dist 文件夹,所以这里我将它们存放在了 public 文件夹下
        path: path.resolve(__dirname, 'public/vendor'),
        // 指定文件名
        filename: '[name].dll.js',
        // 存放动态连接库的全局变量名称,例如对应 lodash 来讲就是 lodash_dll_lib
        // 这个名称须要与 DllPlugin 插件中的 name 属性值对应起来
        // 之因此在前面 _dll_lib 是为了防止全局变量冲突
        library: '[name]_dll_lib'
    },
    plugins: [
        new CleanWebpaclPlugin(['vendor'], {
            root: path.resolve(__dirname, 'public')
        }),
        new FirendlyErrorePlugin(),
        
        // 接入 DllPlugin
        new webpack.DllPlugin({
            // 描述动态连接库的 manifest.json 文件输出时的文件名称
            // 因为每次打包生产环境时会清空 dist 文件夹,所以这里我将它们存放在了 public 文件夹下
            path: path.join(__dirname, 'public', 'vendor', '[name].manifest.json'),
            // 动态连接库的全局变量名称,须要和 output.library 中保持一致
            // 该字段的值也就是输出的 manifest.json 文件 中 name 字段的值
            // 例如 lodash.manifest.json 中就有 "name": "lodash_dll_lib"
            name: '[name]_dll_lib'
        })
    ]
}
复制代码

2、编写配置文件用来打包项目(使用 DllReferencePlugin)

webpack.config.jsjson

const path = require('path');
const webpack = require('webpack');
const HTMLWebpackPlugin = require('html-webpack-plugin');
const CleanWebpaclPlugin = require('clean-webpack-plugin');
const FirendlyErrorePlugin = require('friendly-errors-webpack-plugin');

module.exports = {
    mode: 'production',
    devtool: 'source-map',
    entry: './src/index.js',
    output: {
        path: path.resolve(__dirname, 'dist'),
        filename: 'build-[hash:5].js'
    },
    plugins: [
        new HTMLWebpackPlugin({
            title: 'Webpak DllPlugin 的使用',
            template: './public/index.html'
        }),
        new CleanWebpaclPlugin(['dist']),
        new FirendlyErrorePlugin(),
        new webpack.DefinePlugin({
            'process.env.NODE_ENV': JSON.stringify('production')
        }),
        // 告诉 Webpack 使用了哪些动态连接库
        new webpack.DllReferencePlugin({
            // 描述 lodash 动态连接库的文件内容
            manifest: require('./public/vendor/lodash.manifest.json')
        })
    ]
}
复制代码

3、在 index.html 文件中引入动态连接库

因为动态连接库咱们通常只编译一次,以后就不用编译,复用模块都被打包到了动态连接库中,所以入口的 index.js 文件中已经不包含这些模块了,因此要在 index.html 中单独引入。数组

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Webpak DllPlugin 的使用</title>
</head>
<body>
    <div id="root"></div>
    <script src="../public/vendor/lodash.dll.js"></script>
</body>
</html>
复制代码

注意:因为在打包项目的时候会清理掉 dist 文件,因此我将生成的动态连接库放到了 public 目录下,因此这里是引入 public 下的动态连接库。

咱们在 package.json 中添加两条指令:

  • build:打包项目
  • build:dll:编译生成动态连接库

package.json

...
"scripts": {
    "build": "webpack --config webpack.config.js",
    "build:dll": "webpack --config webpack_dll.config.js"
}
...
复制代码

运行

根据上面所说的三个步骤,Dll 的用法已经结束了。如今咱们运行一下看看结果。

打开命令行,执行命令

# 生成动态连接库,只须要运行一次这个指令,之后打包项目不须要再执行这个指令
$ npm run build:dll

# 打包项目
$ npm run build
复制代码

在浏览器中打开 dist 文件夹下的 index.html 文件,能够看到浏览器上出现:Hello , DllPlugin。说明项目配置成功。

DllPlugin 和 DllReferencePlugin 分别作了什么

运行 npm run build:dll 指令以后,能够看到项目中 public 目录下多出了一个 vendor 的文件夹,能够看到其中包含两个文件:

  • lodash.dll.js 里面包含 lodash 的基础运行环境,也就是 lodash 模块
  • lodash.manifest.json 也是由 DllPlugin 生成出,用于描述动态连接库文件中包含哪些模块

lodash.dll.js

var lodash_dll_lib=...  // 此处代码过多,进行省略
复制代码

lodash.manifest.json

{"name":"lodash_dll_lib","content":{"./node_modules/lodash/lodash.js":{"id":1,"buildMeta":{"providedExports":true}},"./node_modules/webpack/buildin/global.js":{"id":2,"buildMeta":{"providedExports":true}},"./node_modules/webpack/buildin/module.js":{"id":3,"buildMeta":{"providedExports":true}}}}
复制代码

对比以后能够明白

  • 一个动态连接库文件中包含了大量模块的代码,这些模块存放在一个数组里,用数组的索引号做为 ID。 而且还经过 lodash_dll_lib 变量把本身暴露在了全局中,也就是能够经过 window.lodash_dll_lib 能够访问到它里面包含的模块

  • manifest.json 文件清楚地描述了与其对应的 dll.js 文件中包含了哪些模块,以及每一个模块的路径和 ID

至此,Dll 的使用以及配置完成了。可是这里还有值得思考的地方:目前看来,项目能够正常运行,可是如今动态连接库是存放到 public 目录下的,若是咱们须要将项目打包上线的话,如何可以让动态连接库自动也存放到 dist 目录下呢?如何在咱们不手动添加脚本的状况下,自动将动态连接库引入到 index.html 文件中呢?若是有兴趣的话,能够继续往下来看一看配合 add-asset-html-webpack-plugin 的使用。


add-asset-html-webpack-plugin 的使用

上面也已经说了,虽然 Dll 的使用和配置没有问题了,可是还不是很满意,打包的时候不能将动态连接库自动的存放到 dist 文件夹,也不能自动在 html 文件中引入动态连接库脚本。因此这时候 add-asset-html-webpack-plugin 就派上用场了。

安装插件

$ npm install add-asset-html-webpack-plugin -D
复制代码

使用

在 webpack.config.js 文件中进行使用

webpack.config.js

...;
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');

module.exports = {
    ...,
    plugins: [
        ...,
        // 该插件将把给定的 JS 或 CSS 文件添加到 webpack 配置的文件中,并将其放入资源列表 html webpack插件注入到生成的 html 中。
        new AddAssetHtmlPlugin([
            {
                // 要添加到编译中的文件的绝对路径,以及生成的HTML文件。支持globby字符串
                filepath: require.resolve(path.resolve(__dirname, 'public/vendor/lodash.dll.js')),
                // 文件输出目录
                outputPath: 'vendor',
                // 脚本或连接标记的公共路径
                publicPath: 'vendor'
            }
        ])
    ]
}
复制代码

此时能够删除 index.html 文件中手动引入的脚本了

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Webpak DllPlugin 的使用</title>
</head>
<body>
    <div id="root"></div>
    <!-- 删除下面这行引入脚本 -->
-    <script src="../public/vendor/lodash.dll.js"></script>
</body>
</html>
复制代码

运行项目

打开命令行,执行命令:

# 打包项目
$ npm run build
复制代码
  • 如今查看项目中 dist 文件夹,能够看到 public 目录下 vendor 文件夹中的 js 文件已经所有自动拷贝到 dist 目录中的 vendor 文件夹下了

  • 打开 dist 文件夹中的 index.html 文件,能够看到已经自动将生成的脚本文件引入了

  • 在浏览器中打开 index.html,能够看到 'Hello , DllPlugin' 也可以正常显示

add-asset-html-webpack-plugin 更多配置请参考 github 地址:AddAssetHtmlPlugin 配置


总结

  • Dll 动态连接库的使用能够提升项目构建速度,由于对于大量复用的模块能够提早进行编译,且只须要编译一次,以后的开发中,使用这些模块的地方都不会再从新进行编译

  • DllPlugin 和 DllReferencePlugin 须要配合使用

    • DllPlugin 用于打包出一个个单独的动态连接库文件并生成对应的主清单文件用于描述动态连接库中包含哪些模块
    • DllReferencePlugin 用于在主清单文件中去引入 DllPlugin 插件打包好的动态连接库文件
  • 可使用 AddAssetHtmlPlugin 将生成的动态连接库文件拷贝到出口文件夹下,而后 HTMLWebpackPlugin 就会自动的将脚本文件注入到生成的 html 文件中去

  • **注意:**如想测试一下构建速度是否有提高,能够将 webpack.config.js 中的 DllReferencePlugin 和 AddAssetHtmlPlugin 使用注释起来,运行 npm run build,观察打包时间;再将注释打开,运行 npm run build,观察打包时间,进行对比,便可发现区别

如是第一次打包,请先运行 npm run build:dll 生成动态连接库。

本文 Demo 地址:源码地址。 欢迎 Star!

相关文章
相关标签/搜索