DllPlugin
场景需求举例
我们在打包一个react的项目的时候,会把react和react-dom这两个库打包起来。而这两个库很大且基本不会变,所以如果每次打包都要打包这两个第三方包的话,浪费时间,消耗性能。所以,我们一般会采取如下操作:
将react和react-dom单独打包好,然后动态链接引入即可。如果第二次打包,那么发现react和react-dom已经被打包好了,那么就不需要再打包了,这样就大大提升了性能。
实现
- 在src下新建test.js
module.exports = 'yh';
- 新建webpack.config.react.js用于单独打包react和react-dom
let path = require('path');
module.exports = {
mode:'development',
entry:{
test:'./src/test.js'
},
output:{
filename:'[name].js',
path:path.resolve(__dirname,'dist')
}
}
- 执行npx webpack --config webpack.config.react.js,得到dist/test.js。
/******/ (function(modules) { // webpackBootstrap
/******/ var installedModules = {};
/******/
/******/ function __webpack_require__(moduleId) {
/******/
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ module.l = true;
/******/ return module.exports;
/******/ }
/******/
/******/ __webpack_require__.m = modules;
/******/
/******/ __webpack_require__.c = installedModules;
/******/
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ __webpack_require__.p = "";
/******/
/******/ return __webpack_require__(__webpack_require__.s = "./src/test.js");
/******/ })
/******/ ({
/***/ "./src/test.js":
/***/ (function(module, exports) {
eval("module.exports = 'yh';\n\n//# sourceURL=webpack:///./src/test.js?");
/***/ })
/******/ });
- 我们原本打包这个test.js是为了得到module.exports的内容’yh’,但是事实上,打包后的test.js并没有把这个值返回出来让一个变量去接收,所以我们也就无法去使用这个值。这时候,如果我们var一个a去接收,那么就可以把这个结果打印出来,如下(下面的代码只需要看第一行跟最后一行):
var a = (function(modules) { // webpackBootstrap
/******/ var installedModules = {};
/******/
/******/ function __webpack_require__(moduleId) {
/******/
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;
/******/ }
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };
/******/
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
/******/
/******/ module.l = true;
/******/ return module.exports;
/******/ }
/******/
/******/ __webpack_require__.m = modules;
/******/
/******/ __webpack_require__.c = installedModules;
/******/
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, { enumerable: true, get: getter });
/******/ }
/******/ };
/******/
/******/ __webpack_require__.r = function(exports) {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/
/******/ __webpack_require__.t = function(value, mode) {
/******/ if(mode & 1) value = __webpack_require__(value);
/******/ if(mode & 8) return value;
/******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;
/******/ var ns = Object.create(null);
/******/ __webpack_require__.r(ns);
/******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value });
/******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));
/******/ return ns;
/******/ };
/******/
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
/******/ function getDefault() { return module['default']; } :
/******/ function getModuleExports() { return module; };
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };
/******/
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
/******/
/******/ __webpack_require__.p = "";
/******/
/******/ return __webpack_require__(__webpack_require__.s = "./src/test.js");
/******/ })
/******/ ({
/***/ "./src/test.js":
/***/ (function(module, exports) {
eval("module.exports = 'yh';\n\n//# sourceURL=webpack:///./src/test.js?");
/***/ })
/******/ });
console.log(a);
- 如果我们每次都这么做的话,那就太麻烦了,所以我们可以给每次输出的时候添加下配置:
let path = require('path');
module.exports = {
mode:'development',
entry:{
test:'./src/test.js'
},
output:{
filename:'[name].js',
path:path.resolve(__dirname,'dist'),
library:'ab',//这样打包后的结果就被变量ab接收
libraryTarget:'var',//commonjs、umd、var、this等等,默认var,这样就相当于var ab = 打包后的结果
}
}
- 上面是以test.js为例来打包,那么如果我们打包的是react,就应该写成如下:
let path = require('path');
module.exports = {
mode:'development',
entry:{
react:['react','react-dom']
},
output:{
filename:'_dll_[name].js',//产生的文件名_dll_react.js
path:path.resolve(__dirname,'dist'),
library:'_dll_[name]',//_dll_react
// libraryTarget:'var',
}
}
- 这时候我们还需要利用一个插件去生成一个清单,每次打包的时候,先去查找下清单里是否已经存在这个依赖,如果已经存在,则不打包,如果还没存在,则需要打包。
- 生成清单需要使用webpack的内置插件webpack.DllPlugin()
let path = require('path');
let webpack = require('webpack');
module.exports = {
mode:'development',
entry:{
react:['react','react-dom']
},
output:{
filename:'_dll_[name].js',//产生的文件名_dll_react.js
path:path.resolve(__dirname,'dist'),
library:'_dll_[name]',//_dll_react
// libraryTarget:'var',
},
plugins:[
new webpack.DllPlugin({
name:'_dll_[name]',//这个name要与output中的library同名
path:path.resolve(__dirname,'dist','manifest.json')
})
]
}
-
这样打包出来的话,会在dist生成两个文件,一个是_dll_react.js,一个是清单manifest.json
-
然后在index.html去引用这个打包后的文件
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<div id="root"></div>
<script type="text/javascript" src="/_dll_react.js"></script>
</body>
</html>
- 但是现在,我们引用react或react-dom的时候,我们需要判断是否在清单里,这时候,我们就需要在我们正式的webpack.config.js里进行配置
- 需要使用到webpack内置插件new webpack.DllReferencePlugin
let path = require('path');
let webpack = require('webpack');
let HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
devServer:{
port:3000,
open:true,
contentBase:'./dist'
},
mode:'development',
entry:'./src/index.js',
output:{
filename:'bundle.js',
path:path.resolve(__dirname,'./dist')
},
module:{
rules:[
{
test:/\.js$/,
use:{
loader:'babel-loader',
options:{
presets:[
'@babel/preset-env',
'@babel/preset-react'
]
}
}
}
]
},
plugins:[
new webpack.DllReferencePlugin({
manifest:path.resolve(__dirname,'dist','manifest.json')
}),
new HtmlWebpackPlugin({
template:'./src/index.html',
filename:'index.html'
})
]
}
-
这时候再打包,就会发现react和react-dom不打包了,自然打包出的文件就小很多了
-
注意:如果第一次打包,那么要先打包下react和react-dom,即:
npx webpack --config webpack.config.react.js