DLL(Dynamic Link Library)文件为动态链接库文件,在Windows中,许多应用程序并不是一个完整的可执行文件,它们被分割成一些相对独立的动态链接库,即DLL文件,放置于系统中。当我们执行某一个程序时,相应的DLL文件就会被调用。

之前我们所有第三方库都是打包在vendors文件中,形式vendors~[hash].js,每次打包时,都要重新分析这样会影响打包速度。我们知道像这种第三方模块代码基本不会变的,对第三方代码做优化,可以把第三方插件单独打包生成一个文件,只在第一次打包时分析,之后再做打包时利用上一次分析的结果,这样就可以提高webpack打包速度。

1.文件结构

myProject
|-build
   |-base
       |-path.js
       |-config.js
   |-mode.js
   |-entry.js
   |-devtool.js
   |-module.js
   |-plugins.js
   |-devServer.js
   |-optimization.js
   |-output.js
   |-resolve.js
 |-dist
 |-node_modules
 |-src
    |-api
        |-apiPath.js
     |-util
        |-math.js
     |-assets
        |-css
            |-index.css
        |-less
            |-index.less     
        |-sass
            |-index.scss
        |-images
            |-wali_logo.png
     |-index.html
     |-index.js
 |-package.json
 |-webpack.config.js
+|-webpack.dll.js
 |-postcss.config.js
 |-.babelrc
 |-.eslintignore
 |-.eslintrc.js
 |-package-lock.json
 |-stats.json

安装jquery

yarn add jquery

webpack.dll.js

const path = require('path');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');  //清除

module.exports = {
    mode:"production",
    entry:{
        vendors:['loadsh','jquery']
    },
    plugin:[
        new CleanWebpackPlugin()
    ],
    output:{
        path: path.resolve(__dirname, 'dll'),
        filename:'[name].dll.js',
        library: '[name]'
    }
}

package.json

...
"scripts": {
    "dev": "npx webpack-dev-server --colors --mode=development",
    "prod": "npx webpack --colors --mode=production",
    "build": "npx webpack --colors --mode=development",
    "analyse": "npx webpack --profile --json> stats.json --colors  --mode=development",
+    "dll": "npx webpack --config webpack.dll.js --mode=production --colors"
  },
...

运行dll命令

yarn run dll

在项目下生成dll/vendors.dll.js文件,就是将loadsh和jquery打包在一起并暴露出去。

测试dll

在dll目录下新建一个dll.html

<!doctype html>
<html lang="en">
<head>
	<meta charset="UTF-8">
	<title>Document</title>
</head>
<body>
	
</body>
</html>
<script src="./vendors.dll.js"></script>

用浏览器打开dll.html,在控制台中直接可以使用$,_证明将loadshjquery打包到一个文件并暴露出去。

_.join(['欢迎','来到','瓦力','博客'],'+');
//"欢迎+来到+瓦力+博客"

$('body')

2.项目中使用dll

第一步我们已经将第三方打包成一个文件,那么我们在项目中如何使用呢?

安装add-asset-html-webpack-plugin

yarn add add-asset-html-webpack-plugin

build/base/path.js

const path = require('path');   

let dirPath = {};
dirPath.rootDir = path.resolve(__dirname, '../../');   //根路径
dirPath.nodeModule = path.resolve(dirPath.rootDir, './node_modules');  //包路径
dirPath.src = path.resolve(dirPath.rootDir,'./src');   //源文件
dirPath.dist = path.resolve(dirPath.rootDir,'./dist'); //生成线上
+ dirPath.dll = path.resolve(dirPath.rootDir,'./dll');   //dll目录

dirPath.assets = 'assets';               //静态资源
dirPath.css = 'assets/css';              //css
dirPath.sass = 'assets/sass'             //sass
dirPath.less = 'assets/less';            //less
dirPath.images = 'assets/images';        //images
dirPath.iconfont = 'assets/iconfont';    //iconfont


//将srcPath 挂载出去
module.exports = dirPath;

build/pulgin.js

const dirpath = require('./base/path');
const config = require('./base/config');

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');    //生成html文件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');  //清除
const MiniCssExtractPlugin = require("mini-css-extract-plugin");  //css样式提取
+ const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');


let plugins = [
	new HtmlWebpackPlugin({
		title: '瓦力博客',
		template: dirpath.src + '/index.html'   //以src/index.html为编译模板
	}),
+	new AddAssetHtmlPlugin({
+		filepath: dirpath.dll + '/vendors.dll.js'
+	}),
	new  MiniCssExtractPlugin({
		filename: config.NODE_ENV == 'development'?'[name.css]': `${dirpath.css}/[name].[hash].css`,
		chunkFilename: config.NODE_ENV == 'development'?'[id].css': `${dirpath.css}/[id].[hash].css`
	}),   //css提取
	new webpack.ProvidePlugin({
		_:'loadsh',
		url: ['../src/api/apipath', 'url']
	}),
	new webpack.DefinePlugin({ 
		IS_PRODUCTION: config.NODE_ENV == 'development'?JSON.stringify(false):JSON.stringify(true),
	}),
	new CleanWebpackPlugin()
]

if('development' == config.NODE_ENV){
	plugins.push(new webpack.HotModuleReplacementPlugin());
}

module.exports = plugins;

运行build

yarn run build

在dist目录下打开index.html,看到vendros.dll.js已经被添加进去了

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>title</title>
</head>
<body>
<h1>欢迎来到瓦力博客</h1>
<span class="iconfont wali-icon-fuzhi"></span>
<img src="assets/images/wali_logo2BQg9e7.png" alt="">
<script type="text/javascript" src="/vendors.dll.js"></script><script type="text/javascript" src="/runtimechunk~main.js"></script><script type="text/javascript" src="/main.js"></script></body>
</html>

3.webpack引入dll文件

我们已经将第三方模块loadshjquery打包到了vendors变量中,但是在

{
"dev": "npx webpack-dev-server --colors --mode=development",
"prod": "npx webpack --colors --mode=production",
"build": "npx webpack --colors --mode=development"
}

还没有使用vendors第三方模块,还是使用的是node_module里的第三方模块,为了能让上面的命令运行使用我们自己打包第三方库,需要添加映射关系

webpack.dll.js

const path = require('path');
+ const webpack = require('webpack');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');  //清除

module.exports = {
    mode:"production",
    entry:{
        vendors:['loadsh','jquery']
    },
    plugins:[
        new CleanWebpackPlugin(),
+        new webpack.DllPlugin({
+            context: __dirname,
+            name: '[name]',
+            path: path.join(__dirname, 'dll', '[name].manifest.json')
+        })
    ],
    output:{
        path: path.resolve(__dirname, 'dll'),
        filename:'[name].dll.js',
        library: '[name]'
    }
}

运行dll

yarn run dll

检查dll目录下面有没有vendors.manifest.json文件生成,有就证明映射关系生成好了,没有生成vendors.manifest.json检查下配置是否正确

build/plugin.js

const dirpath = require('./base/path');
const config = require('./base/config');

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');    //生成html文件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');  //清除
const MiniCssExtractPlugin = require("mini-css-extract-plugin");  //css样式提取
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');


let plugins = [
	new HtmlWebpackPlugin({
		title: '瓦力博客',
		template: dirpath.src + '/index.html'   //以src/index.html为编译模板
	}),
	new AddAssetHtmlPlugin({
		filepath: dirpath.dll + '/vendors.dll.js'
	}),
+	new webpack.DllReferencePlugin({
+		manifest: dirpath.dll + '/vendros.manifest.json'
+	}),
	new  MiniCssExtractPlugin({
		filename: config.NODE_ENV == 'development'?'[name.css]': `${dirpath.css}/[name].[hash].css`,
		chunkFilename: config.NODE_ENV == 'development'?'[id].css': `${dirpath.css}/[id].[hash].css`
	}),   //css提取
	new webpack.ProvidePlugin({
		_:'loadsh',
		url: ['../src/api/apipath', 'url']
	}),
	new webpack.DefinePlugin({ 
		IS_PRODUCTION: config.NODE_ENV == 'development'?JSON.stringify(false):JSON.stringify(true),
	}),
	new CleanWebpackPlugin()
]

if('development' == config.NODE_ENV){
	plugins.push(new webpack.HotModuleReplacementPlugin());
}

module.exports = plugins;

运行prod

yarn run prod

ssl

注释build/plugin.js

const dirpath = require('./base/path');
const config = require('./base/config');

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');    //生成html文件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');  //清除
const MiniCssExtractPlugin = require("mini-css-extract-plugin");  //css样式提取
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');


let plugins = [
	new HtmlWebpackPlugin({
		title: '瓦力博客',
		template: dirpath.src + '/index.html'   //以src/index.html为编译模板
	}),
	new AddAssetHtmlPlugin({
		filepath: dirpath.dll + '/vendors.dll.js'
	}),
-	new webpack.DllReferencePlugin({
-		manifest: dirpath.dll + '/vendros.manifest.json'
-	}),
	new  MiniCssExtractPlugin({
		filename: config.NODE_ENV == 'development'?'[name.css]': `${dirpath.css}/[name].[hash].css`,
		chunkFilename: config.NODE_ENV == 'development'?'[id].css': `${dirpath.css}/[id].[hash].css`
	}),   //css提取
	new webpack.ProvidePlugin({
		_:'loadsh',
		url: ['../src/api/apipath', 'url']
	}),
	new webpack.DefinePlugin({ 
		IS_PRODUCTION: config.NODE_ENV == 'development'?JSON.stringify(false):JSON.stringify(true),
	}),
	new CleanWebpackPlugin()
]

if('development' == config.NODE_ENV){
	plugins.push(new webpack.HotModuleReplacementPlugin());
}

module.exports = plugins;

运行prod

yarn run prod

ssl

从上面两张截图中可以比较出来,dll提高了打包构建的速度。

4.dll文件分组

上面的配置中

entry:{
    vendors:['loadsh','jquery']
}

我们在实际项目中用到的第三方模块可能更多如vue,vue-router等等。全部打包到一个文件也不是很合适。

安装vue,vue-router

yarn add vue
yarn add vue-router

webpack.dll.js

const path = require('path');
const webpack = require('webpack');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');  //清除

module.exports = {
    mode:"production",
    entry:{
        vendors: ['loadsh','jquery'],
+        vue: ['vue', 'vue-router']
    },
    plugins:[
        new CleanWebpackPlugin(),
        new webpack.DllPlugin({
            context: __dirname,
            name: '[name]',
            path: path.join(__dirname, 'dll', '[name].manifest.json')
        })
    ],
    output:{
        path: path.resolve(__dirname, 'dll'),
        filename:'[name].dll.js',
        library: '[name]'
    }
}

运行dll

yarn run dll

ssl

生成了两个dll和对应manifest.json文件,所以在引用的时候也要引入多个

build/plugin.js

const dirpath = require('./base/path');
const config = require('./base/config');

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');    //生成html文件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');  //清除
const MiniCssExtractPlugin = require("mini-css-extract-plugin");  //css样式提取
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');


let plugins = [
	new HtmlWebpackPlugin({
		title: '瓦力博客',
		template: dirpath.src + '/index.html'   //以src/index.html为编译模板
	}),
	new AddAssetHtmlPlugin({
		filepath: dirpath.dll + '/vendors.dll.js'
	}),
	new webpack.DllReferencePlugin({
		manifest: dirpath.dll + '/vendors.manifest.json'
	}),
+    new AddAssetHtmlPlugin({
+		filepath: dirpath.dll + '/vue.dll.js'
+	}),
+    new webpack.DllReferencePlugin({
+		manifest: dirpath.dll + '/vue.manifest.json'
+	}),
	new  MiniCssExtractPlugin({
		filename: config.NODE_ENV == 'development'?'[name.css]': `${dirpath.css}/[name].[hash].css`,
		chunkFilename: config.NODE_ENV == 'development'?'[id].css': `${dirpath.css}/[id].[hash].css`
	}),   //css提取
	new webpack.ProvidePlugin({
		_:'loadsh',
		url: ['../src/api/apipath', 'url']
	}),
	new webpack.DefinePlugin({ 
		IS_PRODUCTION: config.NODE_ENV == 'development'?JSON.stringify(false):JSON.stringify(true),
	}),
	new CleanWebpackPlugin()
]

if('development' == config.NODE_ENV){
	plugins.push(new webpack.HotModuleReplacementPlugin());
}

module.exports = plugins;

5.自动添加dll

上一步,我们每新建一个dll分组,就需要在plugins中添加new AddAssetHtmlPluginnew webpack.DllReferencePlugin。当一个项目用的第三方模块稍微多一点的时候,那么手动添加new AddAssetHtmlPluginnew webpack.DllReferencePlugin添加也会越来越多。下面我们来将这块代码优化下,实现不管添加多少个模块,我们让代码自动帮助我们添加到plugins中。

build/plugin.js

const dirpath = require('./base/path');
const config = require('./base/config');

const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');    //生成html文件
const { CleanWebpackPlugin } = require('clean-webpack-plugin');  //清除
const MiniCssExtractPlugin = require("mini-css-extract-plugin");  //css样式提取
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin');
+ const fs = require('fs');



let plugins = [
	new HtmlWebpackPlugin({
		title: '瓦力博客',
		template: dirpath.src + '/index.html'   //以src/index.html为编译模板
	}),
-	new AddAssetHtmlPlugin({
-		filepath: dirpath.dll + '/vendors.dll.js'
-	}),
-	new webpack.DllReferencePlugin({
-		manifest: dirpath.dll + '/vendors.manifest.json'
-	}),
-   new AddAssetHtmlPlugin({
-		filepath: dirpath.dll + '/vue.dll.js'
-	}),
-   new webpack.DllReferencePlugin({
-		manifest: dirpath.dll + '/vue.manifest.json'
-	}),
	new  MiniCssExtractPlugin({
		filename: config.NODE_ENV == 'development'?'[name.css]': `${dirpath.css}/[name].[hash].css`,
		chunkFilename: config.NODE_ENV == 'development'?'[id].css': `${dirpath.css}/[id].[hash].css`
	}),   //css提取
	new webpack.ProvidePlugin({
		_:'loadsh',
		url: ['../src/api/apipath', 'url']
	}),
	new webpack.DefinePlugin({ 
		IS_PRODUCTION: config.NODE_ENV == 'development'?JSON.stringify(false):JSON.stringify(true),
	}),
	new CleanWebpackPlugin()
]

+ let files = fs.readdirSync(dirpath.dll);
+ files.forEach(val=>{
+	if(/\.js$/.test(val)){
+		plugins.push(new AddAssetHtmlPlugin({ 
+			filepath: `${dirpath.dll}/${val}`
+		}))		
+	}
+
+	if(/\.json$/.test(val)){
+		plugins.push(new webpack.DllReferencePlugin({
+			manifest: `${dirpath.dll}/${val}`
+		}))
+	}
+ })


if('development' == config.NODE_ENV){
	plugins.push(new webpack.HotModuleReplacementPlugin());
}

module.exports = plugins;

运行build

yarn run build

dist目录中检查html文件是否引入vendorsvue。如果引入了,证明这块代码没问题了。

webpack4.x 教程

webpack 准备工作(1) webpack 手写最基本的配置(2) webpack 打包样式(3) webpack 让打包更便捷(4) webpack 打包图片(5) webpack iconfont打包(6) webpack devServer本地开发(7) webpack 处理ES6语法(8) webpack SourceMap配置(9) webpack Tree Shaking(10) webpack js代码分割(11) webpack 懒加载(12) webpack 打包分析,Preloading,Prefetching(13) webpack 模块化区分开发和生产(14) webpack 样式文件的代码分割(15) webpack 浏览器缓存(16) webpack shimming(17) webpack 环境变量(18) webpack Esline(19) webpack 解析resolve(20) webpack Library的打包(21) webpack dll(22) webpack 多页面打包配置(23) webpack 搭建vue脚手架(24)