About the use of Webpack DLL, I do not do too much introduction, there are a lot of online, today I would like to say is in the use of DLL plugin in the process of a package dependency problem, this problem leads to the package will contain duplicate code.

Optimize the background

Recently, when I was optimizing the company’s project, the size of uploaded files in the internal CDN was limited to 500K, so I used WebPack DLL to split and pack the files. I divided the split packages into three parts:

  • Vue Eco-Pack (vue,vuex,vue-router,vuex-class,vue-class-componentAnd other surrounding ecological libraries)
  • Vue Plug-in package (vee-validateInternal UI library, image preview and other VUE plug-in library)
  • Third Party Packages (axiosInternal error statistics, reporting, employee watermarking, etc., which are separated from the third party library of VUE)

The package names of the three parts are vue.dll. Js, plugin.dll. Js and lib.dll

But after the DLL packaging, I was surprised to find that vue.dl.js and plugin.dl.js contained the dist code of vUE duplication

The following is the bundle analysis diagram of the first two parts

You can see that both DLLS contain vUE

So to analyze the cause of the problem, let’s talk about the configuration of my DLL

DLL configuration

Because Webpack supports multi-entry, so generally multi-entry DLL packaging, the first consideration will be a Webpack configuration, multiple entry, so it may appear

// webpack.dll.conf.js

module.exports = {
    // Other configurations are omitted
        entry: {
             vue: ['vue'.'vuex'.'vue-router'. ] .plugin: ['vee-validate'.'Internal UI Library'. ] .lib: ['axios'.'dayjs'. ] },plugins: [
        new webpack.DllPlugin({
            / / DLL. Configuration}})]Copy the code

But the personal test so packaged documents still have the above problems

Therefore, in combination with the webpack Multi Compiler method I practiced in my previous company, REFERRING to webpack Multi Compiler, I divided the configuration of Webpack into three, and each DLL package has one Webpack configuration, that is

// config.js exports.dll = [ { name: 'vue', libs: ['vue', 'vuex', 'vue-router', 'vuex-class', 'vue-class-component'] }, { name: 'lib', libs: [axios', 'dayjs',' third party libraries']}, {name: 'plugin' libs: [' vee - validate ', 'v - viewer', 'vue plug-in library]}]Copy the code
// webpack.dll.conf.js

module.exports = config.dll.map(function (vendor) {
    return {
        // Omit other configurations
        entry: {
            [vendor.name]: vendor.libs
        },
        plugins: [
            new webpack.DllPlugin({
                / / DLL. Configuration})]}})Copy the code
// dll.js

const dllConfig = require('./webpack.dll.conf')

webpack(dllConfig, function (err, stats) {
    if (err) throw err
    // Handle stats related information
})

Copy the code

I thought this would solve the problem, but it didn’t, so I had to analyze the problem first

To analyze problems

After careful investigation, it is found that the internal UI library alone references vUE, that is, in the library

import Vue from 'vue'

// ...
// Vue related operations
/ / the Vue. Prototype. $isServer, etc
Copy the code

This results in duplicate packages in both multi-entry packaging and multi Compiler mode

The solution

Analyze the principle of DLL, in fact, DLL packaging will be all contained libraries to do an index, write in a MANIFEST file, and then reference DLL when only need to reference the MANIFEST file

So I was wondering, if plugin.dll.js depends on vue in vue.dll.js, is it possible to package vue.dll.js first and then reference vue.dll.js when packaging plugin.dll.js?

Give it a try and make the following changes

// config.js exports.dll = [ { name: 'vue', libs: ['vue', 'vuex', 'vue-router', 'vuex-class', 'vue-class-component'] }, { name: 'lib', libs: [axios', 'dayjs',' third party libraries']}, {name: 'plugin' libs: [' vee - validate ', 'v - viewer', 'vue plug-in library'], ref: 'vue'}]Copy the code
// webpack.dll.conf.js

// generate config
const gen = function (vendors) {
    return vendors.map(function (item) {
        const base = {
            entry: {
                [item.name]: item.libs
            },
            plugins: [
                new webpack.DllPlugin({
                    / / DLL configuration}})]if (item.ref) {
            // That's the point
            // In the DLL configuration with ref, insert the PLUGIN in the DLL reference, containing the manifest of the dependent DLL package
            base.plugins.push(new webpack.DllReferencePlugin({
                // DLL reference Other configurations
                manifest: 'Path to the manifest file of the dependent DLL package'}}))return base
    })
}

// Distinguish base config from ref config depending on whether there are ref dependencies
const [baseVendors, refVendors] = config.dll.vendors.reduce((config, v) = > {
    config[v.ref ? 1 : 0].push(v)
    return config
}, [
    [],
    []
])

// Generate base config
const getConfig = function () {
    return gen(baseVendors)
}

// Generate ref config
const getRefConfig = function () {
    return gen(refVendors)
}

module.exports = {
    getConfig,
    getRefConfig
}
Copy the code
// dll.js

const dllConfig = require('./webpack.dll.conf')

// Because ref config depends on base config, make sure base config is packaged first
const runWebpack = function (config) {
    return new Promise(function (resolve) {
        webpack(config, function (err, stats) {
            if (err) throw err
            // ...
            resolve()
        })
    })
}

module.exports = function run () {
    runWebpack(dllConfig.getConfig())
        .then((a)= > runWebpack(dllConfig.getRefConfig()))
}

Copy the code

The whole thing becomes the following structure

The most important step is that plugin.dll.js will reference the manifest file of vue.dll.js, so that the common part of vue will only appear in vue.dll.js. The bundle analysis diagram of plugin.dll.js is shown below

You can obviously see that the Vue Dist is no longer present in plugin.dll.js, and the package size has been optimized ✌️

Items can be optimized

What if plugin.dll. Js relies on both vue.dll. Js and lib.dll. What if vue.dll. Js also relies on lib.dll.

If the above situation occurs, please consider whether the DLL package should be split first. Does a split make sense?

Then think about how to think about the packaging order in terms of the dependency order, and what to do if there are cyclic dependencies.

Since this situation has not yet occurred in optimization requirements (it should be very, very, very rare), I have not solved these problems on my side

conclusion

Refer to the general packaging method of the DLL reference plugin to reference the MANIFEST of the DLL package. If there are dependencies in multiple DLL packages, resulting in repeated packaging, The DLL reference plugin can be used to refer to the DLL manifest of the dependent package. However, in this case, it is necessary to pay attention to the packaging sequence of the DLL package. The DLL of the dependent package should be packaged before the DLL of the dependent package

Optimization of webpack DLL packaging duplication problem