The so-called DLL: dynamic link library. This is a Windows category.

In recent days, I have done some research on DllPlugin and DllReferencePlugin, which come with Webpack, and I feel they are more suitable for performance optimization in the development stage.

The core idea of this scheme is space for time: first, use DllPlugin to generate DLL package (including 1 JS and a corresponding JSON); When used, THE Dll User invokes these resources through the DllReferencePlugin without recompiling this part of the code, thus improving the compilation efficiency and development efficiency.

To generate a DLL

// Note that there are multiple entries
entry: {
    react: ['react'.'react-dom'.'react-router'].antd: ['antd'],},plugins: [
    new CleanWebpackPlugin(),
    new DllPlugin({
    	// Note the use of dynamic file names
        path: path.resolve(__dirname, '.. /dll/manifest_[name].json'),	
        name: '[name]_[chunkhash:4]'.context: __dirname,
    })
]
Copy the code

After running, the following files are generated in the DLL directory of the project:

staff  1521019  2 25 15:06 antd_bbcd.js
staff   131724  2 25 15:06 manifest_antd.json
staff     3766  2 25 15:06 manifest_react.json
staff   160646  2 25 15:06 react_e0f4.js
Copy the code

Note: OnlineDllPluginThe examples are all generated singlyvendor; In the example above, multiple entries + dynamic file names produce multiple entriesdllFile. There will also be a difference in citation.

Call the DLL

It’s a bit of a hassle. After running the DLL file generation command, you also need:

  1. Change the WebPack configuration, usingDllReferencePluginPoint to a DLL file;
  2. To write SRC references to these DLL files in the HTML file.

My dev development configuration is a DllUser. Take this example:

1. Change the WebPack configuration

Start by changing dev’s WebPack configuration. In the case of multiple DLL files, multiple DllReferencePlugin plug-ins are used to introduce them.

Pay attention tocontextThe entry must have, and must be withDllPluginThe configurations are consistent.

plugins: [
    new HtmlWebpackPlugin({
        template: './src/client/index.html'.inject: 'body',}).new DllReferencePlugin({
        manifest: require(path.resolve(__dirname, '.. /dll/manifest_react.json')),
        context: __dirname,
    }),
    new DllReferencePlugin({
        manifest: require(path.resolve(__dirname, '.. /dll/manifest_antd.json')),
        context: __dirname,
    }),
],
Copy the code

NPM run dev works fine at this point, but the page console will report an error

Uncaught ReferenceError: antd_bbcd is not defined
Copy the code

Open the external file on the console and see the following code:

module.exports = antd_bbcd;
Copy the code

Is it suddenly clear?

2. Change the HTML template

Let’s introduce it in HTML. Dev-server is configured to ensure that DLL files can be accessed:

devServer: {
    contentBase: path.join(__dirname, '.. /dll'),
    port: 9100
}
Copy the code

In the HTML head add:

<script type="text/javascript" src="antd_bbcd.js"></script>
<script type="text/javascript" src="react_e0f4.js"></script>
Copy the code

Then re-npm run dev and the page is displayed normally.

Process optimization

Since we added the chunkhash suffix when we generated the DLL, the filename is likely to change. With each change, the WebPack configuration and HTML template need to be modified, plus there are multiple DLLS, so each change is cumbersome.

Since we generate the file, which is stored separately in the DLL directory, we can read this directory and dynamically generate the configuration.

Write a function to read a directory file:

const fs = require('fs')

const getFiles = (dir) = > {
    if(! fs.existsSync(dir) || ! fs.statSync(dir).isDirectory()) {return[]}return fs.readdirSync(dir, 'utf-8').filter(n= > !/ ^ \. /.test(n))
}

module.exports = getFiles
Copy the code

1. Modify the WebPack configuration

// ...

const getFiles = require('./utils/get-files')

/** * When installing multiple DLLS, plugins should load react first. * After getFiles is used to obtain the file name list, antD is first in alphabetical order by default, so ANTD DLL is loaded earlier than React, causing an error. * So simply use reverse() to change the loading order. Multiple DLLS are a bit of a hassle. *@param {string} dir 
 * @param {string} context 
 */
const getDllReferencePlugin = (dir, context = __dirname) = > {
    return getFiles(dir).filter(n= > /\.json$/.test(n)).reverse().map(name= > {
        return new DllReferencePlugin({
            manifest: require(path.join(dir, name)),
            context,
        })
    })
}

module.exports = {
	/ /...
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/client/index.html'.inject: 'body',}),... getDllReferencePlugin(path.resolve(__dirname,'.. /dll'), __dirname),
    ]
}
Copy the code

2. Use plug-ins to dynamically transform HTML

In my last article, I briefly introduced how to write the Webpack plug-in, which is also a dynamic modification of HTML within the scope of the HTML-webpack-plugin. Here will not repeat, directly post plug-in code code:

/* plugins/jsdir-html-inject.js */
const path = require('path')
const { JSDOM } = require('jsdom')
const getFiles = require('.. /utils/get-files')

const getJsFiles = (dir) = > {
    return getFiles(dir).filter(n= > /\.js$/.test(n))
}

class JSDirHtmlInject {
    constructor(options) {
        this.options = options || {}
    }
    apply(compiler) {
        compiler.plugin('compilation'.(compilation, options) = > {
            compilation.plugin('html-webpack-plugin-before-html-processing'.(data) = > {

                const { dir, base = '. ' } = this.options
                if(! dir) {return
                }
                const files = getJsFiles(dir)
                if(files.length < 1) {
                    return
                }

                const dom = new JSDOM(data.html)
                const head = dom.window.document.querySelector('head')
                files.forEach(src= > {
                    const script = dom.window.document.createElement('script')
                    script.setAttribute('type'.'text/javascript')
                    script.setAttribute('src', path.join(base, src))
                    head.appendChild(script)
                })
                data.html = dom.serialize()
            })
        })
    }
}

module.exports = JSDirHtmlInject
Copy the code

Change the WebPack configuration again

const JSDirHtmlInject = require('./plugins/jsdir-html-inject')
// ...
module.exports = {
	// ...
    plugins: [
        new HtmlWebpackPlugin({
            template: './src/client/index.html'.inject: 'body',}).new JSDirHtmlInject({
            dir: path.resolve(__dirname, '.. /dll'),
            base: '. '
        }),
        ...getDllReferencePlugin(path.resolve(__dirname, '.. /dll'), __dirname),
    ]
}
Copy the code

This allows you to run the NPM Run DLL as needed before each development start.

From the development level, developers do not care about DLL output, normal run NPM run dev.

It seems to be quite convenient.

The above.