读懂webpack4,看这一篇就够了

概述,在webpack里面有四个概念: 入口、出口、插件和loader,进行模块化打包,支持CMD、ADM、commonJS、import等模块化操做。css

安装说明:在webpack安装的时候,须要先安装一个全局的webpack,而后在须要的文件夹中安装局部的依赖,webpack webpack-cil脚手架,在webpack3的版本中,它们是集成在一块儿。本次笔记是针对于:webpack4.x以上的版本html

npm install webpack -g 	//先安装全局的webpack,安装完成后,才能够实验webpack命令,直接打包
npm install webpack webpack-cli  -D  // 在须要的目录安装webpack

webpack  // 在cmd或者vscode中运行这个,就能够打包了,其它的配置,且看后面
复制代码

安装完成后,须要在项目根目录新建一个webpack-config.js的配置文件;没有新建这个文件,也能够打包,由于webpack有默认配置。前端

若是没有安装全局webpack的话,就没法直接使用webpack直接打包,固然,也能够单独是配置脚本,例:vue

scripts: {
    dev: webpack --config webpack-config.js
}
复制代码

在4.0之后的版本里面,新增了一个多入口打包命令:webpack app.js app1.ja -o bulid.jsnode

在webpack中有生产模式(production)和开发模式(development),默认为开发设置,用,mode参数去设置模式,例:react

module.exports = {
  mode: 'production' // 模式选择,生产和开发两种
};
复制代码

特别说明:须要指定mode属性,否则控制台会报出一个警告信息jquery

入口(entry)

入口(entry point),表示 webpack 应该使用哪一个模块;进入入口之后,webpack 会找出有哪些模块和库是入口起点(直接和间接)依赖的。webpack

入口能够是单入口和多入口(使用一个数组或者对象表示),在实际操做中,为了便于优化以及首屏加载问题,会更倾向于第三种方式,既对象的形式。ios

可是使用对象写法(entry代码分离),会有一些小问题;假设entry引入了2个js文件,分别是a.jsb.js,可是这个两个文件都引入了同一个依赖,打包之后,就会形成代码重复,很是不利于优化,因此须要使用SplitChunksPlugin来进行防止重复或者是动态倒入的方法。点击查看这种方式的坑点:代码分离git

module.exports = {
  entry: './app.js' // 写法一
  entry: ['./app.js, main.js'] //写法二
  entry: {
    app: './app.js',
    main: './main.js'
} //写法三
};
复制代码

出口(output)

若是使用(output)属性表示,这个属性是用来告诉webpack输出它所建立的内容,默认的目录是dist文件夹,在项目的根目录中,也能够指定一个目录导出。

const path = require('path');
module.exports = {
  entry: './path/to/my/entry/file.js', // 入口
  output: { // 出口
    path: path.resolve(__dirname, 'dist'),
    filename: 'my-first-webpack.bundle.js' // 单文件合并的写法
    filename: '[name].js', // 多入口多文件
    chunkFilename: [name][contenthash].js, // 防止缓存,只有在更新之后才会生成随机码
    publicPath: 'CDN地址' // 设置CDN服务器地址, 理论上是能够直接打包到CDN服务器上,前提是有权限
  }
};
复制代码

入口文件有配置的,就走filename这个属性,若是是其它文件导入的,就走下面这个,既chunkFilename,在使用的时候,目的就是解决代码更新,而浏览器读取缓存获取不到更新。

output中,filename属性是用来告诉webpack打包后的文件名称;而path是告诉webpack须要建立的文件夹的位置信息,这个要调用node里面一个模块,既path模块,__dirname是node里面的一个关键字,表示路径,绝对路径

提示:在webpack里面,多个入口若是要合并文件,只能使用数组的方式; 若是须要打包多文件的时,入口须要使用对象,出口使用一个动态的写法,如上代码"多入口文件", [name].js,若是入口是一个对象,出口必定是一个动态写法,不然就会致使打包不正常。

loader

loader 让 webpack 可以去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 能够将全部类型的文件转换为 webpack 可以处理的有效模块,而后你就能够利用 webpack 的打包能力,对它们进行处理。

loader的执行顺序,是从下到上,从右到左的执行顺序,因此在设置loader的时候,顺序不能放错,不然,可能会致使打包异常。

我的理解: loader就至关因而一个翻译器,将咱们写的代码,进行翻译并处理。使用方法,以下:babel为例

注意:在lodaer里面,配置正则(test)的时候,必定不能加引号,不然会提示lodaer错误。

babel

介绍:babe就是将ES6转成ES5的一个编译器,须要安装3个依赖;虽然Babel能够将ES6的语法转成ES5的语法,可是若是是ES6+里面的内置API就没法去转换了,所以安装一个垫片@babel/polyfill,它主要是为了兼容低版本的浏览器,

babel-loader @babel/core  // 主要是语法转换
@babel/preset-env  // 这个用来指定ES的版本
@babel/polyfill // 全局垫片,用于转换内置API支持ES5的语法
/* 局部垫片须要安装的依赖项 */
@babel/plugin-transform-runtime
@babel/runtime
复制代码

webpack配置方式

module: {
  rules: [
    {
      test: /\.m?js$/, // 匹配文件的后缀名
      exclude: /(node_modules|bower_components)/, // 须要剔除的目录
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env'], // 垫片使用
          plugins: ['@babel/plugin-proposal-object-rest-spread'] //额外的
        }
      }
    }
  ]
}
复制代码

关于属性use的操做,若是配置项目不是不少的时候,能够不用use这个属性,它们两个是等价的,直接写,例:

rules: [{
    test: /\.m?js$/, // 匹配文件的后缀名
    loader: 'babel-loader', // 加载的loader
    exclude: /(node_modules|bower_components)/, // 须要剔除的目录
    options: { 	//配置项
   		presets: ['@babel/preset-env'], // 默认写法,不使用配置的写法
        presets: [["@babel/preset-env", { // 第二种写法,配置一个babel/polyfill垫片
        useBuiltIns: "usage", // 按需加载 entry | usage
        targets: {
          chrome: "68"  // 浏览器目标,也能够跟随一个浏览器的市场份额
        }
      }]
      ]
    }
}]
复制代码

关于@babel/polyfill的使用:先安装,须要在被打包的文件中引入 @babel/polyfill这个模块,默认是会打包全部的API内置模块,所以须要一个按需加载,写法:useBuildIns: 'usage'

默认会报出一个警告,解决方案:若是配置了usage的话,就不须要在被打包的文件种引入@babel/polyfill,若是须要引入的话:则须要用entry替换(局部方式,按照文件需求)

关于局部垫片的使用说明:若是是写的一个插件,就不能使用全局垫片,使用局部垫片须要有两个依赖@babel/plugin-transform-runtime@babel/runtime

.babelrc配置方法

在项目根目录须要新建一个单文件,文件名:.babelrc,格式是一个标准的JSON,因此须要使用标准的JSON格式,下面已局部垫片配置为例:

{
	"presets":["@babel/preset-env"],
	"plugins": [["@babel/plugin-transform-runtime", { 
         "absoluteRuntime": false,
         "corejs": 2, // corjs须要改为2,不改的话会形成打包异常,官方默认是false,可选数字和布尔
         "helpers": true,
         "regenerator": true,
         "useESModules": false
      }]
  ]
}
/* ================ 正常模式下 使用文件名的方式 配置 ========================*/
{
      "presets": [["@babel/preset-env", {
          "useBuiltIns": "usage",
          "targets": {
          "chrome": "68"  // 浏览器目标,也能够跟随一个浏览器的市场份额,也能够是:last 100 versions
        }
      }]
      ]
}
复制代码

关于异常的处理:corejs官方的默认值是false,可是这样会有异常,结果就是不会转换;所以在corejs的属性后面要跟上一个数字2,可是这样,仍是不行,所以须要下载一个@babel/runtime-corejs2依赖项,用来改变以前的@babel/runtime

注意:在设置presets属性的时候,若是须要配置,第二个对象是放在嵌套数组里面,如:[['xxx',{} ]],而且,不能够在在webpack里面设置了之后,再去单独的.babelrc里面去设置,根据试验证实:会报错。

插件(plugins)

想要使用一个插件,你只须要 require() 它,而后把它添加到 plugins 数组中。多数插件能够经过选项(option)自定义。你也能够在一个配置文件中由于不一样目的而屡次使用同一个插件,这时须要经过使用 new 操做符来建立它。

这是官方的说法,我本身的理解就是,给webpack扩展一个功能,这个功能极其强大,能够用来处理各类各样的任务,插件的使用方法以下:

const HtmlWebpackPlugin = require('html-webpack-plugin'); // 经过 npm 安装的模块
const webpack = require('webpack'); // 用于访问内置插件
const path = require('path') //这是一个文件路径的内置模块,在使用resolve属性时,就必需要有这个

const config = { // 多文件配置的写法
  module: {
    rules: [
      { test: /\.txt$/, use: 'raw-loader' }
    ]
  },
  plugins: [
    new HtmlWebpackPlugin({
        template: './src/index.html'
    })
  ]
};
module.exports = config 
复制代码

HtmlWebpackPlugin的使用

HtmlWebpackPlugin插件,该插件将为你生成一个 HTML5 文件, 其中包括使用 script 标签的 body 中的全部 webpack 包。 使用的时候,须要安装这个插件html-webpack-plugin,基本具体配置以下:

var HtmlWebpackPlugin = require('html-webpack-plugin'); // 引入插件
plugins: [
    new HtmlWebpackPlugin({ // 能够配置更多的值,好比title
        title: 'webpack', // 生成HTML标题
        templat: './index.html' // 配置的模板文件
        hash: true, // 防止缓存,给生成的JS文件添加一个hash值,包含css
        cache: true // 仅在内容被更改时才更新文件
        inject: true, // JS注入的位置,true,默认底部 
        chunks:['xxx', 'entry入口文件名'], // 多入口文件,会根据配置生成JS文件,默认所有引用 
        minify: {
        	removeAttributeQuotes: true, // 是否移除属性的引号 默认false
    }
    })
]
复制代码

参考资料: npm原文连接webpack4 之html-webpack-plugin。更多配置查看前面的NPM原文连接

clean-webpack-plugin的使用

clean-webpack-plugin插件能对配置的输出文件进行清除,在build命令开始执行的时候,会自动的去检查,若有有就会去先清除掉,这样就永远地保证了这个目录里面的文件都是最新的。可是也能够自定义删除某个目录,文档请戳这里

const { cleanWebpackPlugin } = require('clean-webpack-plugin') // 先引入这个包,须要使用这种方式
plugins: [
	new cleanWebpackPlugin()  // 使用,默认不须要进行传参, 根据实测,在3.X的版本,能够直接引入
]
复制代码

多个loader或多插件配置

若是要使用多个lodaer,只须要将规则rules属性下面,放一个数组,里面能够有多个对象

module: {
rules: [{  // 关于多个loader配置以下,每一个loader都是一个对象
		test: /\.tsx?$/,
		use: 'ts-loader',
		exclude: /node_modules/ 
	},{
      test: /\.m?js$/, // 匹配文件的后缀名
      exclude: /(node_modules|bower_components)/, // 须要剔除的目录
      use: {
        loader: 'babel-loader',
        options: {
          presets: ['@babel/preset-env'],
          plugins: ['@babel/plugin-proposal-object-rest-spread']
        }
      }
    }]
}
复制代码

提示:其实,每个loader或者插件均可以使用单文件的方式,这样可让webpack文件变得不是那么的庞大,可是会形成项目根目录文件的变得不少,具体根据本身得项目来进行配置。

关于TS文件的打包

在转换TS文件的时候,须要下载typescript ts-loader的依赖,安装好之后,须要在项目根目录新建一个为tsconfig.json的JSON文件,配置以下:

{
  "compilerOptions": {
    "outDir": "./dist/",  // 输出的文件,若是webpack已经配置了,就不须要了
    "noImplicitAny": true, 
    "module": "es6",	// 已什么模块的方式引入文件,主要有ES6和commonJS
    "target": "es5",	// 须要编译成什么类型的语法,ES5
    "jsx": "react",	  // 使用jsx语法,
    "allowJs": true   // 在TS文件种是否存在ES的语法,默认true
  },
  "include": ['./src/', './'], // 引入的文件目录,须要编译的文件
  "exclude": /node_modules/  // 剔除不须要编译的目录,多个使用(xx|xx)这种方式
}
复制代码

编译typescriptwebpack的配置以下:

module: {
	rules: [{
		test: /\.tsx?$/,
		use: 'ts-loader',
		exclude: /node_modules/ 
	}]
},
复制代码

lodash是一个一致性、模块化、高性能的 JavaScript 实用工具库,主要用于代码类型约束。在TS里面使用types/lodash能够对TS进行类型约束。**提示:**lodash具备针对性,若是须要对jquery进行类型约束,则须要下载对应的lodash依赖包。

图片打包

在图片打包之前,须要下载一个loader,使用file-loader能够对图片进行打包,webpack经常使用配置以下:

module: {
	rules: [{
		test: /\.(png|jpg|gif)$/,
        use: [{
            loader: 'file-loader',
            options: {
            	name: '[path][name].[ext]' // 自定义名字,[name]名字[ext]扩展名,还能够加混淆好比哈希值
                outputPath: 'images/'  //将打包的文件,生成打包相对文件(dist)的images/的目录下
            }
		}]
	}]
}
复制代码

说明:图片打包,默认文件名使用哈希进行混淆,也能够自定义配置。具体查看webpack官方的url-loader说明,示例上仅仅只是显示了一部分。

若是图片须要进行BASE64的打包,须要下载url-loader的一个loader,可是须要注意的是,file-loadeurl-loader的处理是同样的,惟一不同的就是url-loader要比file-loade的功能更增强大,使用的方法和file-loade的方法如出一辙,并无什么区别,可是url-loade拥有更多的配置项。

module: {
	rules: [{
		test: /\.(png|jpg|gif)$/,
        use: [{
            loader: 'url-loade',
            options: {
            	name: '[path][name].[ext]', // 自定义名字,[name]名字[ext]扩展名,还能够加混淆好比哈希值
                outputPath: 'images/',  //将打包的文件,生成打包相对文件(dist)的images/的目录下
                limit: '1024', // 图片打包base的大小限制,单位是字节
            }
		}]
	}]
}

复制代码

使用url-loader会默认的将图片打包成了base64的文件,可是在正常状况下,只有在图片比较小的话,才会打成base的格式,所以须要在options里面进行图片大小进行配置

CSS模块化打包

在打包css的时候,须要下载一个css-loaderstyle-loaderlodaer去作编译,若是要使用预编译,则须要安装对应的预编译loader。例如:sass须要 sass-loadernode-sass这两个loader,根据实验,只须要sass-loader就能够了。

css-loader用来打包css

style-loader用来挂在页面,将这个loader自动挂在到html页面上,通常方式在html头部

基本配置信息以下(包含了sass预处理器):

module.exports = {
    module: {
    rules: [{
        test: /\.css$/,  // /\.sass$/
        use: [ 'style-loader', 'css-loader' , 'sass-loader']
      }]
  }
}

复制代码

给CSS3添加前缀须要使用postcss-loaderlodaer和 autoprefixer插件,继续使用上面的例子,基本配置以下:

module.exports = {
    module: {
    rules: [{
        test: /\.css$/,  // /\.sass$/
        use: [ 'style-loader', 'css-loader' , 'sass-loader','postcss-loader'] // 写法1
        use: [ 'style-loader', 'css-loader' ,'sass-loader',{ // 写法2,能够对每一个lodaer作单独配置
        	loader:'postcss-loader',
        	options: {
            	plugins: [
                	require("autoprefixer") /* 生成浏览器前缀 */
             ]}
    	}] 
      }]
  }
}

复制代码

若是要让它自动添加前缀的话,须要在项目根目录新建一个文件(也能够是其它文件夹,全局配置通常都放在根目录),postcss.config.js,在里面进行一个配置,也能够如上代码那样,写在webpack.config.js中;基本配置信息以下:

module.exports = {
	 plugins: [ //插件的方式
     	 require'autoprefixer'// 加载模块 默认写法
         require('autoprefixer')({ // webpack或者postcss.config.js配置,
    		overrideBrowserList: 'last 100 versions'
		})
     ]
}

复制代码

autoprefixer在默认的配置下,只能自动的添加webkit的前缀信息,若是须要添加更多的配置,还须要添加额外的参数。

须要在package.json里面添加一个属性,属性名是browserslist,对应的是一个数组,里面填入浏览器、或者node版本的名称,例如:"last 100 versions"

若是须要在webpack里面配置的话,就须要使用overrideBrowserList属性去替换browserslist这个属性,不然在编译的时候,webpack会有错误提示。关于browserslist的具体用法,请点击这里

CSS模块化机制,简单配置:

module.exports = {
    module: {
    rules: [{
        test: /\.css$/,  // /\.sass$/ // 匹配的后缀名
        use: [ 'style-loader', {  // 配置须要的加载器,loader
            loader: 'css-loader',
            options: {
                modules: {
                 	 localIdentNane: '[name]_[hash:base64:10]' // 自定义class的名字,bese须要截取
                }
            }
        }, 'sass-loader']
      }]
  }
}

复制代码

若是开启了模块化操做,那么在模块化导入的时候,文件就只能是局部的方式导入,不然webpack在编译的时候,会出错,例子以下:

import 'xxx.css'  // 全局引入
import xxx from 'xxx.ss' // 局部引入

复制代码

打包字体:打包字体和打包文件同样,loader用的也是打包图片的那个file-loader

module: {
	rules: [{
		test: /\.(woff|woff2|svg|ttf|eot )$/,  // 字体文件后缀名
        use: [{
            loader: 'file-loader',
            options: {
            	outputPath: 'font/'  //生成的文件夹,将打包的文件,放在里面
                name: [name].[ext]   // 修改输出文件名,这样就默认原来的文件名和后缀名
            }
	}]
	}]
}

复制代码

devServer经常使用配置

webpack-dev-server 可以用于快速开发应用程序,因此简称devServer;devServer是用来提升开发效率的,不是用devServer来作打包,它提供了一些配置项,能够用于改变devServer的默认行为,要配置devServer,除了能够在配置文件里经过devServer传入参数,还能够经过命令行传入参数。

/* 截取的vue cli的例子 经过命令传递的参数*/
"dev": "webpack-dev-server --host 0.0.0.0 --inline --progress --config build/webpack.dev.conf.js",

复制代码

可是须要注意的是:devServer 只适用于开发模式

开启本地服务

webpack开启本地服务器安装一个内置插件webpack-dev-server来帮咱们开启一个本地服务,虽然webpackDevServer插件是内置的,可是依然须要下载,只是不须要引入,须要在webpack.config.jspackage.json文件进行配置,配置内容以下:

/* webpack.config.js 配置 */
module.exports = {
	devServer: {
		contentBase: './dist' // 配置打包的路径
        open: true, // 设置是否默认打开
        prot: "8080", // 端口
        hot: true , // 开启热更新
	}
}
/* package.json 配置 */
"scripts": {
    "dev": "webpack-dev-server --open"
}

复制代码

在正确配置了webpack-dev-server之后,从dist目录中提供文件,默认地址是:localhost:8080,也能够自定义配置,配置方案如上代码。更多配置点击这里,可是这种方法,会更新全部数据,能够理解成是"页面刷新"

webpack-dev-server在编译后不会写任何输出文件。相反,它将捆绑文件保存在内存中并为它们提供服务,就好像它们是安装在服务器根路径上的真实文件同样。若是您的页面但愿在不一样的路径中找到捆绑包文件,则可使用publicPathdev服务器配置中的选项更改此选项。

webpack 热更新

在使用webpack热更新的时候,须要有一个插件HotModuleReplacementPlugin,简称是HMR,这个插件是webpack集成的一个内置插件,在使用的时候,不须要下载,可是要导入webpack

可是HotModuleReplacementPlugin这个插件不能用于生产模式,热更新也是devServer里面的一个小项。 HotModuleReplacementPlugin里面的配置项,能够忽略,官方说是实验性的,不推荐配置。

const webpack = require('webpack') 
plugins:[
 	new webpack.HotModuleReplacementPlugin({
		multiStep: true, // 将分两步构建 - 首先编译热更新块,而后编译剩余的普通资产
		fullBuildTimeout: Number // 时间,表示启用 multiStep 这个之间的延迟
        requestTimeout: Number // 时间(毫秒) 用于下载清单的超时时间
	});   
 ]

复制代码

请注意,webpack.HotModuleReplacementPlugin彻底启用HMR是必需的。若是webpack或者webpack-dev-server使用该--hot选项启动,则会自动添加此插件,所以您可能不须要将此添加到您的webpack.config.js

"dev": "webpack-dev-server --host 0.0.0.0 "  // 上述说明的实例,不须要webpack.config.js配置

复制代码

webpack 预加载

webpack 反向代理

dev-server 使用了很是强大的 http-proxy-middleware 包。更多高级用法,请查阅其文档;在咱们作开发的时候,会由于跨域问题致使没法进行数据请求,所以须要借助wenpack提供的反向代理,既porxy,使用方法以下:

/* 省略其它代码 */
devServer: {
    porxy: {
    	"/api": "http://localhost:3000"// 基础用法,将/api绑定到目标服务器。
        "/api": { // 采用配置的用法,用法二
         	target: "http://localhost:3000", // 目标服务器
            pathRewrite: {"^/api" : ""},  //路径重写,这样在前端访问的时候,就不须要传/api
            secure: false, // 配置是否须要使用https的方式,默认是不容许
        }
    }, // 多个API请求同一服务器的写法
     porxy:[{
     	context: ["/auth", "/api"], // 多个请求
  		target: "http://localhost:3000", // 目标服务器
     }]
}
/*** 前端请求,已axions为例 ***/
   axios.get('/api/xxx').then(red => { xxx })  
 axios.get('// xxx').then(red => { xxx })  // 配置请求的方式访问 忽略掉/api

复制代码

假设有多个API请求都在同一个服务器,可使用context上下文的方式跟上一个数组,代码如上例子,关于webpack proxy的更多配置,请戳这里访问官网更多说明。

webpack 预加载

SourceMap的设置

其实配置devtool就是在配置SourceMap,意为:源文件映射,可以快速找到代码出错的位置,可是这种方式,须要打包完了之后才能看到是否出错;可是也有折中的解决方案,须要在package.json里面设置一个脚本,能够自动的为咱们打包,但它是一个文件协议,正常来讲,页面须要手动刷新,全部仍是使用devServer的方式会比较好点儿。

module.export = {
    /* cheap-module-eval-source-map 开发环境使用,速度快,包含三方模块 仅提示行错误*/
    /* cheap-module-source-map 生产环境使用, 其实也能够不使用*/ 
    /* source-map 源文件映射 inline-source-map(精准告诉你哪行那列出错)*/
    devtool: 'cheap-module-eval-source-map'
}
/*================================= package.json ===============================*/
"scripts": {
    "dev": "webpack --watch" 
  }

复制代码

devtool您可使用SourceMapDevToolPlugin, 而不是使用该选项,EvalSourceMapDevToolPlugin由于它有更多选项。切勿同时使用devtool选项和插件,该devtool选项在内部添加插件,所以您最终会将插件应用两次。

devtool您可使用SourceMapDevToolPlugin, 而不是使用该选项,EvalSourceMapDevToolPlugin由于它有更多选项其实这句话,我也不太理解是什么意思? 若是须要更加细粒度的控制,就使用SourceMapDevToolPlugin这个插件,可是不能同时使用,缘由上面也说了。 其实就我我的以为,自带的就够了。

Tree Shaking的配置

Tree Shaking翻译过来就是摇晃树枝 ,因此简称摇树;举个简单的例子:秋天的马路,马路两边种了不少行道树,有的叶子枯黄、有的叶子任然是绿色,由于枯黄的叶子随风飘落,为了更好的解决落叶的问题,就找了一个大型的器械,抓着树干使劲摇晃,枯黄的叶子也就掉落了下来,剩下的就是不易掉落的绿色叶子。

可是反过来能够这样理解,就是说,对于webpack来讲,入口就至关因而一棵树干,入口上面有不少模块,这些模块就是树枝,可是这些依赖模块并无所有使用,或者只使用了模块中的某一个功能,这时就须要借助Tree Shaking它将不须要的模块给摇掉,也就是说:在打包后文件里面,代码都是精简且须要的。原理请戳这里:Tree-Shaking性能优化实践 - 原理篇

tree shaking 是一个术语,一般用于描述移除 JavaScript 上下文中的未引用代码(dead-code)。它依赖于 ES2015 模块系统中的静态结构特性,例如 importexport。这个术语和概念其实是兴起于 ES2015 模块打包工具 rollup

新的 webpack 4 正式版本,扩展了这个检测能力,经过 package.json"sideEffects" 属性做为标记,向 compiler 提供提示,代表项目中的哪些文件是 "pure(纯的 ES2015 模块)",由此能够安全地删除文件中未使用的部分。

说了这么多? 那在webpack里面应该怎样使用呢?须要在package.json中配置

{
  "sideEffects": false, // 简单版本,
  "sideEffects": [ // 使用数组的方式,我的理解:就是将不须要摇的东西给剔除出来,。
      "@babel/polyfill",
      "./src/some-side-effectful-file.js",
      "*.css"
  ]
}

复制代码

这样只是标记“未使用代码(dead code)”,可是须要是在编译后(bulid)删除,所以:咱们须要切换到生产模式(production)来表示,命令模式(--optimize-minimize);使用配置的方式,代码以下:

mode: 'production',  // 必须是生产模式
optimization: {	 // 设置删除为标记的 未使用代码,也就是死代码
	usedExports: true
}

复制代码

总结:Tree Shaking只在生产模式有效,开发模式无效,而且只能使用ESmodul的方式,详细说明请戳这里

单独的webpack配置

在vue cli 2.x的版本里面有不少webpack配置,一开始我也不知道为何须要这么配置,经过后来的了解才知道,在webpack里面有不少模式,好比:生产模式、开发模式,介于它们之间的还有各类配置文件、公共模块等,如下是vue cli的webpack配置目录。

.
|—— vue cli
|—— config
|	|——	dev.env.js
|	|——	index.js
|	|——	prod.env.js
|	|__	test.env.js
|——	build
|	|——	build.js
|	|——	check-versions.js
|	|——	utils.js
|	|——	vue-loader.conf.js
|	|——	webpack.base.conf.js
|	|——	webpack.dev.conf.js
|	|__	webpack.prod.conf.js
|
.

复制代码

但是有这么多的单独的文件,最终须要怎么才能合并在一块儿呢? 是直接引入仍是须要使用插件呢?这里须要使用一个插件,这个插件的名字是:webpack-merge,在使用它的时候,须要先去安装这个插件。

若是将上面的目录进行一个拆分,假设就只有webpack.prod.conf.jswebpack.dev.conf.jswebpack.base.conf.js这么三个文件,其中webpack.base.conf.js是一个公共文件,另外两个表示生产模式和开发模式。使用webpack-merge的方法以下:

/* ======= 以生产模式为例 webpack.prod.conf.js======= */
const merge = require('webpack-merge');
const common = require('./webpack.prod.conf.js');

module.exports = merge(common, { 
	mode: 'production',
	devtool: 'source-map'
});

复制代码

还须要在npm里面进行配置,仍然已vue cli目录为例,在package.json中加入如下内容:

scripts": {
	"dev": "webpack-dev-server --open --progress --config build/webpack.dev.conf.js",
	"build": "webpack --config build/webpack.prod.conf.js"
}
/* --progress 显示进度条的意思 */

复制代码

环境变量的使用

就只想使用一个文件入口,在里面配置一个环境变量,而后就能按照本身的须要,产生不一样的编译结果,实施方法能够按照以下操做。

那里面的commonConfig文件和prodConfig还有这个devConfig它们也是一个单独的文件,为了不一个文件很大,因此在使用的过程当中,仍是单独分开写的比较好,只不过在具体配置的时候,使用一个环境变量来判断。

module.export = (env) => {
    if(env && env.production){ // 条件判断
        return merge(commonConfig, prodConfig); // 生产模式(线上模式)
    } else {
        return merge(commonConfig, devConfig); // 开发模式
    }
}

复制代码

看了上面的代码,会想到一个问题,条件判断的变量env && env.production是从哪里来的,其实这个变量是从package.json``里面配置得来的,也就是说:若是须要使用这种方式的话,就须要去更改启动脚本,代码以下:

scripts": {
	"dev": "webpack-dev-server --open --progress --config build/webpack.base.conf.js",
	"build": "webpack --env.production. --config build/webpack.base.conf.js"
}
/* --progress 显示进度条的意思 */

复制代码

能够很清除的看到devbuild这两个方法启动的目录文件都是同一个,可是在build里面多了一个env.production这个属性,其实,这个变量就是上面的条件判断语句所须要的参数。

环境变量还能够这样使用,就nodeJS提供的process.env.NODE_ENV,具体的时候方法,参考简书NodeJs/Vue项目中对process.env的使用

在Webpack中配置Esint

在不少时候,咱们都须要使用eslint来帮助咱们进行代码检查和规范,这样每每在团队中,能作到风格统一,很是有利于团队协做、后期维护等,但配置eslint是很是繁琐的,下面一块儿来看看,咱们如何在webpack中如何配置eslint吧?在慕课手记中也有关于自定义的详细说明,更多查看请戳这里

eslint在使用前,须要先安装eslint这个包,更多安装方法戳这里查看官方教程,安装方法以下:

npm install eslint --save-dev // 下载eslint这个安装包
npx eslint --init // 运行这个命令进行eslint的详细配置

复制代码

关于eslint配置说明,当运行npx eslint --init的时候,会弹出以下信息:

? How would you like to use ESLint? (Use arrow keys)  //如何配置eslint这个文件,你想如何使用
  To check syntax only  // 仅检查语法
> To check syntax and find problems // 检查语法并找出问题
  To check syntax, find problems, and enforce code style //检查语法、发现问题和强制代码样式
/* 我选择的是检查语法并找出问题,而后就有了下面的配置信息 */

? What type of modules does your project use? // 你想使用什么类型的模块呢?
  JavaScript modules (import/export) // 基于ES6
> CommonJS (require/exports)	// 这个主要是node中使用
  None of these // 这些都不是 

  /* 由于在个人实验中,用的是vue,所需须要使用esmodule这种语法,而后弹出的信息以下 */
  ? Which framework does your project use? (Use arrow keys) // 你想使用那个框架
   React
 > Vue.js  // 由于我是vue,全部选择vue
  None of these // 其它框架
  
  /* 当选择vue后,配置如以下,问你是在那个地方运行,能够多选,使用空格点亮,而后回车 */
  ? Where does your code run? (Press <space> to select, <a> to toggle all, <i> to invert selection)
>(*) Browser // 浏览器
 ( ) Node    // node 
/* 当我选择之后,会出现以下配置 固然是使用JS文件的方式,我的爱好*/
? What format do you want your config file to be in? (Use arrow keys) // 使用什么文件做为配置文件
> JavaScript
  YAML
  JSON

  /* 问你是否想安装它们,这里固然选择是了 */
  ? Would you like to install them now with npm? (Y/n) // y 基础配置过程就完毕了

复制代码

当一些列配置完毕后,会发如今项目的根目录中有一个.eslintrc.js的配置文件,这个文件就是eslint的配置文件啦,更多配置请戳这里,也能够选择第三方公司的编码配置,安装方法参考eslint配置(使用Airbnb编码规则),比较变态的就是airbnb规则了,很是的严格。

虽然这样在vscode(前提是webpack中有插件)中可使用了,可是对于其它的代码编辑器,却不会怎么报错? 因此还须要下载一个eslint-loader才能够,具体操做方法以下:

npm install eslint-loader --save-dev

复制代码

下载好了之后,基本配置以下,可是必定要将eslint-loader放在最后面,由于loader的执行顺序是从后往前:

module.exports = {
  module: {
    rules: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        use: ["babel-loader", "eslint-loader"] 
      }
    ]
  }
};

复制代码

仅仅是这样(若是不作以下配置,只能在cmd控制台显示),仍是不行滴,还须要一点儿额外的其它配置,配置以下:

module.exports = {
  devServer: {
    overlay: true  // 在浏览器上弹出一个层,也就是在浏览器中显示全屏覆盖
  }
};

复制代码

但都知道在vue cli2 的版本中,当检测到警告信息,会输出在浏览器的控制台显示,可是这个问题,我还木有解决,有知道的小伙伴,能够告诉我如下。

overlay:{
    warnings: false, 
    errors: true
}

复制代码

我也按照vue cli源代码进行了一个配置,发现并无按照个人意愿来。

打包第三方库(shimming)

在刚学Vue.js的时候,那时候运用的不是很熟,有时候须要操做DOM,可是Vue.js操做DOM很是的不方便;有时候须要获取到 一个列表里面全部的标签,那时候就想到了使用Jquery来帮我操做DOM,当时就觉得像其它JS文件同样全局导入就能够了,可在实际运用的时候却傻眼了,就发现,可以在控制台输出Jquery对象,可是却没法操做DOM,这让我很抓狂。

通过学习,知道webpakc自己就已经提供了一套关于shimming解决方案:使用webpack内置的ProvidePlugin插件和expose-loader,在网上找了不少文档,在使用webpack内置的ProvidePlugin插件的时候,虽然勉强解决这个问题,可是仍是有一些小问题,就eslint报错的问题。后来发现使用expose-loader的方式也能够解决这个问题。

webpack.ProvidePlugin

ProvidePluginwebpack内置插件,所以在使用前须要导入webpack,它主要的功能是:自动加载模块,而没必要处处 importrequire , 这也是webpack推荐的使用方法。

可是:对于 ES2015 模块的 default export,你必须指定模块的 default 属性,由于它的名字;以jquery为例: 它实际上就是 import $ from 'jquery',具体例子请看以下代码。更多例子请戳这里,查看官方示例说明。

const webpack = require('webpack')
/* 省略其它代码 */
plugins: [
    new webpack.ProvidePlugin({
        $: 'jquery',  // 后面的jquery其实就是 import $ from 'jquery'
        JQuery: 'jquery'
    })
]

复制代码

expose-loader

能够经过expose-loaderwebpack注入一个全局的公共模块,假设用了这个方法导入了jquery的话,是能够全局使用,能够理解成绑定到了window上,所以,在使用它的时候,须要下载这个expose-loader,以jquery为例,使用方法以下:

module: {
  rules: [{
    test: require.resolve('jquery'), // 导入jquery模块,但这个方法是node.js提供,和webpack无关
    use: [{
      loader: 'expose-loader', 
      options: 'jQuery' // 全局使用的名称, window.jQuery
    },{
      loader: 'expose-loader',
      options: '$' // 全局使用名称, window.$ 
    }]
  }]
}

复制代码

可是这种方法,须要在局部导入(也就是说,须要每一个页面都须要导入),而后才能进行全局暴露,可是若是须要全局注入的话,显然这种方式不太稳当。

防止重复(SplitChunksPlugin)

webpack提供了一个Code Splitting拆分代码,点击这里,能够查看代码分离的方式以及介绍。

使用CommonsChunkPlugin用于避免它们的重复依赖,可是没法进一步优化;在webpack4的版本之后,删除了optimization.splitChunks这个属性;SplitChunksPlugin方法使用以下:

module.exports = {
    splitChunks: {
        chunks: "all",  // 同步和异步都作分割
        cacheGroups: { // 缓冲组
            vendors:false,
            default: false
        }
    }
}

复制代码

SplitChunksPlugin的更多配置以下,具体参考官方说明,戳这里点击官方文档

module.exports = {
  //...
  optimization: {
    splitChunks: {
      chunks: 'async', // async 默认推荐使用,异步加载作分割, initial 同步 all 同步和异步都作分割
      minSize: 30000, // 字节 引入的包或者模块大于这个这个值,才会作代码分割,只针对同步加载
      maxSize: 0, // 超过 minSize 之后,会进行二次打包,默认不配置,不能强拆
      minChunks: 1, // 引入次数,引入次数为多个,能够打包
      maxAsyncRequests: 5, // 请求超过5个的部分不拆分,通常默认值
      maxInitialRequests: 3, // 页面初始化同时发送的请求数量最大不能3个,超过之后就不会被拆分,默认值就会
      automaticNameDelimiter: '~', // 用以代码分离打包的文件名默认链接符,cacheGroups里面的vendors
      automaticNameMaxLength: 30, // 最长字节数,不能超过这个值
      name: true, // 拆分的名字, true表示根据模块名和cacheGroups组的key来自动生成文件名
      cacheGroups: { // 缓存配置,一个文件import多个库,若是须要多个库打包成一个文件,则使用这个缓存组
        vendors: {
          test: /[\\/]node_modules[\\/]/, // 检测引人的库是不是node_modules下面的
          priority: -10, // 权重,决定哪一个组的优先配置
          name: "vendors" // 自定义名字,不须要后缀名
        },
        default: { // 前面没有匹配上,则使用这个组,一般是业务代码
          minChunks: 2, // 引入超过2次才重新打包成一个新文件
          priority: -20, // 权重
          reuseExistingChunk: true // 当为true后就不会重复打包,会进行自动复用。
        }
      }
    }
  }
};

复制代码

chunks的时候,还须要走cacheGroups缓冲组,分离出来的文件名是:cacheGroups里面的vendors,中间的链接符是automaticNameDelimiter,例vendors-main.js

cacheGroups能够自定义多个组,若是多个组都知足要求,则以权重大的组为准。

webpack为了更好的提高性能,最好的仍是使用异步的方式,这也是官方推荐。

Lazy Loding(动态导入懒加载)

当涉及到动态代码拆分时,webpack 提供了两个相似的技术。对于动态导入,第一种,也是优先选择的方式是:ES7提出的一个草案,既import()语法。第二种,则是使用 webpack 特定的 require.ensure。先来讲说第一种:

动态导入最大的好处就是实现了懒加载,用到那个模块就才会调用那个模块,很是适合ASP导入,能够大大的减小等待时间,但使用这个须要用到babel去转,也就是须要下载@babel/plugin-syntax-dynamic-import这个插件,使用方法以下:

{
  "plugins": ["@babel/plugin-syntax-dynamic-import"] // 使用插件,在webpack plugins里面添加
}

复制代码

在页面添加动态import导入懒加载的方式,这种方式会返回一个promise对象,代码以下:

/* 声明这个方法 须要一个函数 */ 
function getComponent() {
	import(/* webpackChunkName: "lodash" */ 'lodash').then( _ => {
            var element = document.createElement('div');
            element.innerHTML = _.join(['Hello', 'webpack'], ' ');
            return element;
		 }).catch( error => 'An error occurred while loading the component');
 }
/* 调用这个方法 若是不调用则不执行*/
getComponent().then(component => {
	document.body.appendChild(component);
})

复制代码

这种方法,则会对代码进行分离,将动态打入的第三方模块,会单独的打一个文件,而本身所写的业务代码,则会被打包到新的一个文件里面。

/* webpackChunkName: "lodash" */ 'lodash'魔法字符串,懒加载,配合SplitChunksPlugin使用,能够进行一个单独配置,其实这个配置和SplitChunksPlugin是共用。

module.exports = {
    splitChunks: {
        cacheGroups: { // 缓冲组
            vendors: {
              test: /[\\/]node_modules[\\/]/, // 检测引人的库是不是node_modules下面的
              priority: -10, // 权重,决定哪一个组的优先配置
              name: "vendors" // 自定义名字,不须要后缀名
        	},
            default: false
        }
    }
}

复制代码

可是使用懒加载的时候,会有一个弊端,就是当用户须要一个模块的时候,只有触发之后,才能去加载对应的模块,这就会形成一个网络的延时,有一个等待期,不利于用户体验,因此就须要另一个技术,也就是预加载,当页面自动加载出来之后,利用闲置的带宽,去加载其它可能须要的模块。

预加载(Prefetching)

这个是webpack 4.6.0新增的一个功能,用通俗的话来讲,就是在网络空闲的时候,才去自动下载其它的非必要模块,这种方式极大的提高了用户体验,也解决了等待延时问题,但是要怎么使用呢?

/* 使用方法和上面的 懒加载是同样的,只是这个魔法字符串里面的参数不同 */
import(/* webpackPrefetch: true */ 'LoginModal');

复制代码

在声明导入时使用这些内联指令容许webpack输出“Resource Hint”,使用方法如上,它告诉浏览器:

  • prefetch:将来可能须要资源
  • preload:当前可能须要资源

区别:preload是和核心代码一块儿加载,prefetch预加载

缓存带来的代码提高是有限的,因此使用懒加载代码优化是如今性能优化的主要使用方式。

webpack打包分析

关于打包分析,官网为咱们提供了一个内置插件Bundle Analysis,在guider下面的Code Splitting里面的Bundle Analysis,他有几种类型,webpack-chart:(交互式饼图)等类型,具体请戳这里。使用方法也很简单,只须要在package.json中配置一段脚本便可,例子以下:

scripts": {
	"build": "webpack  --profile --json > stats.json --env.production. --config build/webpack.base.conf.js"
}

复制代码

其实也能够直接使用webpack --profile --json > stats.json, 打包完成后,会生成一个stats.json文件,这个文件就是结果分析,而后须要将这个文件上传到这个网站,进行数据分析,可是这个表,感受很是不人性化,我的以为很难看,因此须要使用webpack-bundle-analyzer插件。

Webpack Bundle Analyzer也是一个打包分析,它和webpack-chart不一样的是,Webpack Bundle Analyzer 是一个很直观的平面图,这是一个插件,因此在使用的时候,须要进行下载安装,npm install --save-dev webpack-bundle-analyzer

若是使用了这个之后,在打包的时候,控制台不会输出打包信息,好比文件、 打包时间、chunk等信息,这也算是一个弊端。

在使用它的时候,也须要有如上的package.json中配置(实测,可不须要使用),在webpack里面的基本配置以下,更多配置请戳这里

// 导入插件
const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
// 使用它
module.exports = {
  plugins: [
    new BundleAnalyzerPlugin()
  ]
}

复制代码

CSS的代码分离

它默认是打包在js文件里面,这样就会致使文件变得很大,因此将CSS代码分离出来是颇有必要的,使用CSS代码分析则须要使用一个插件来帮咱们完成,这个通常只作线上版本,在开发版本则不须要,这个插件的名字是MiniCssExtractPlugin,点击这里查看更多官方配置。

npm install --save-dev mini-css-extract-plugin  // 须要先安装

复制代码

简单的配置说明,在使用的时候须要将style-loader替换为MiniCssExtractPlugin.loader,若是须要在开发环境中使用热更新,须要从新进行一个设置。

const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 导入插件
module.exports = {
  plugins: [
    new MiniCssExtractPlugin({ // 方法同output里面的方法,最好就是加一个hash值,防止缓存
      filename: '[name].css',  // 生成的文件名
      chunkFilename: '[id].css', // 构建时生成,主要是防止文件更新浏览器不更新,缓存致使的
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader, // 替换style-loader
            options: { // 其它的配置项
              publicPath: '../', // 指定的地址,同等与output里面的publicPath
              hmr: process.env.NODE_ENV === 'development', // 环境变量
            },
          },
          'css-loader',
        ],
      },
    ],
  },
};

复制代码

CSS代码分离,默认是不会被压缩,若是想要代码压缩,则须要使用optimize-css-assets-webpack-plugin插件,但须要注意的是:设置optimization.minimizer会覆盖webpack提供的默认值,所以须要指定,JS minimalizer, 使用方法以下:

const TerserJSPlugin = require('terser-webpack-plugin'); // 不添加则JS不会被压缩
const MiniCssExtractPlugin = require('mini-css-extract-plugin'); // 导入CSS分离插件
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin'); // CSS代码压缩
module.exports = {
  optimization: { // 添加一个属性,
    minimizer: [new TerserJSPlugin({}), new OptimizeCSSAssetsPlugin({})],
  },
  plugins: [
    new MiniCssExtractPlugin({
      filename: '[name].css',
      chunkFilename: '[id].css',
    }),
  ],
  module: {
    rules: [
      {
        test: /\.css$/,
        use: [MiniCssExtractPlugin.loader, 'css-loader'],
      },
    ],
  },
};

复制代码

设置optimization.minimizer会致使重写,因此须要下载terser-webpack-plugin这个插件,去压缩JS,若是没有这个插件就会致使,CSS代码被压缩了,可是JS代码则不会被压缩。

配置模块的解析方式(resolve)

Webpack 在启动后会从配置的入口模块出发找出全部依赖的模块,Resolve 配置 Webpack 如何寻找模块所对应的文件。 Webpack 内置 JavaScript 模块化语法解析功能,默认会采用模块化标准里约定好的规则去寻找,但你也能够根据本身的须要修改默认的规则。

关于resolve的基本配置以下,更多配置戳这里查看官方教程。

const path = require('path') // node提供的文件路径模块
module.exports = {
  resolve: {
    extensions: ['.wasm', '.mjs', '.js', '.json'],  // 自动解析肯定的扩展,能够省略的扩展名
    alias: { //建立 import 或 require 的别名,来确保模块引入变得更简单。
        "@": path.resolve(__dirname, '../src'),
        xyz$: path.resolve(__dirname, 'XXX.js') // 精确匹配 xyz 
    }
  }
};

复制代码

vue loader的使用

在搭建vue脚手架以前,须要下载两个loader,分别是:vue-loadervue-template-compiler,具体的安装方法查看Vue loader官方说明。

npm install -D vue-loader vue-template-compiler // 安装

复制代码

须要注意的问题:每一个 vue 包的新版本发布时,一个相应版本的 vue-template-compiler 也会随之发布。编译器的版本必须和基本的 vue 包保持同步,这样 vue-loader 就会生成兼容运行时的代码。这意味着你每次升级项目中的 vue 包时,也应该匹配升级 vue-template-compiler。

main.js中加入最基本的代码,这也是最基本的入口配置信息

import Vue from 'vue'

window.vm = new Vue({
  el: '#app',
  render: h => h(App),
  components: { App },
  template: '<App/>'
})


复制代码

正常来讲,webpack在编译的时候,是不认识.vue的后缀名,所以须要咱们手动的在webpack里面新增一个loader,用于识别.vue文件,基本配置以下:

// webpack.config.js
const VueLoaderPlugin = require('vue-loader/lib/plugin')

module.exports = {
  mode: 'development',
  module: {
    rules: [
      {
        test: /\.vue$/,
        loader: 'vue-loader'
      },
      // 它会应用到普通的 `.js` 文件
      // 以及 `.vue` 文件中的 `<script>` 块
      {
        test: /\.js$/,
        loader: 'babel-loader'
      },
      // 它会应用到普通的 `.css` 文件
      // 以及 `.vue` 文件中的 `<style>` 块
      {
        test: /\.css$/,
        use: [
          'vue-style-loader',
          'css-loader'
        ]
      }
    ]
  },
  plugins: [
    // 请确保引入这个插件来施展魔法
    new VueLoaderPlugin()
  ]
}
复制代码

vue loader15+的版本都须要去使用一个vue-loader/lib/plugin插件,这个插件不用单独下载,在使用vue-loader的时候,这个插件就已经有了。

webpack打包优化(DllPlugin)

为了更快的使用打包优化,须要及时更新nodeJS以及webpack的版本,尽量的减小一些loader的转换,而且须要剔除一些没必要要的目录,好比:node-modules的文件夹,插件尽量得时候使用官方推荐。 还可使用webpack内置的DllPlugin插件去帮咱们进行打包速度优化。

DllPlugin插件专门用于单独的webpack配置中,以建立仅限dll的捆绑包。它建立了一个manifest.json文件,用于DllReferencePlugin映射依赖项(先建立一个,而后进行复制,这样就提高了打包效率)。

更多的方法戳这里查看官方教程,一般是建立一个webpack.dll.js文件,用来专门配置dllplugin,目的是为了将一些公共的库,打包成一个文件,后续打包不会从新打包,只会去引用打包好的包。

const path = require('path') // 导入node 模块
module.exports = {
    mode: 'production', // 生产模式
    entry: {
        vendors: ['vue','jquery'] // 入口文件,自定义属性
    },
    output:{
        filename: '[name].dll.js', // 输出,多个文件打包成一个文件
        path: path.resolve(__dirname, '../dll'), // 打包的文件夹目录
        library: '[name]' // 导出全局变量,用于其它文件
    }
}
复制代码

可是这种方法,不会自动添加到html页面中,所以须要一个插件add-asset-html-webpack-plugin,来帮我咱们将webpack.dll.js打包后文件自动添加到html中,关于更多说明戳这里查看NPM教程

cnpm i add-asset-html-webpack-plugin -D  // 安装
复制代码

使用它的时候,此时就不能写在webpack.dll.js文件中,应该写在公共的文件当中,好比webpack.base.conf.js文件里面,基本配置方法以下:

const HtmlWebpackPlugin = require('html-webpack-plugin'); // 导入自动生成html插件
const AddAssetHtmlPlugin = require('add-asset-html-webpack-plugin'); // 自动添加插件
const webpackConfig = {
  entry: 'index.js',
  output: {
    path: 'dist',
    filename: 'index_bundle.js',
  },
  plugins: [
    new HtmlWebpackPlugin(),// 更多说明请看前面的 HtmlWebpackPlugin 配置
     // require.resolve和 path.resolve, 在这里的用法是同样的,
    new AddAssetHtmlPlugin({ filepath: require.resolve('../dll/vendors.dll.js') }),
  ],
};
复制代码
相关文章
相关标签/搜索