04.webpack中的plugin

认识Plugin

webpack中的两个核心内容一个是loader,另外一个就是plugin。
loader用来在webpack打包的过程中用于对特定的模块类型:比如css\less,图片,字体等资源进行转换;
plugin用于将loader转化后的资源执行更加广泛和多样化的任务,比如打包体积优化、资源管理、环境变量的注入等。

CleanWebpackPlugin

CleanWebpackPlugin的作用是在每次执行npm run build打包之前,将上一次打包生成的dist文件下的资源删除,这样就可以避免我们每次执行新的打包任务前手动去删除dist目录下的资源。

  1. 安装
npm i clean-webpack-plugin -D
  1. 配置
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
module.exports = {
	plugins:[
		new CleanWebpackPlugin(),
	]
}
  1. 注意
  • 每一个webpack的plugin本质其实都是一个类,所以在配置plugin的时候需要通过new关键字来调用,本质就是执行类里面的construtor方法,从而实现插件的功能。

  • CommonJS的规范中,module.exports和exports都指向同一个内存地址那就是要导出的对象,在clean-webpack-plugin插件的源码中:

exports.CleanWebpackPlugin = CleanWebpackPlugin;

// 就等于
module.exports = {
	CleanWebpackPlugin,
}

上面代码等于导出了一个对象,该对象作为当前模块对外的接口,其内部有一个CleanWebpackPlugin的属性,属性值就是CleanWebpackPlugin这个类,只不过上面是采用了ES6的对象属性简便写法。

  • 由于这里导出的是一个对象,所以外部模块使用的时候需要将这个类解构出来。

HtmlWebpackPlugin

之前在打包的过程中对于index.html并不会打包,并且存在以下几个缺点:

  1. 需要手动创建index.html文件
  2. 需要在index.html中手动挨个引入打包之后的js脚本文件
  3. 发布部署的时候还要手动将其移入到dist文件夹中

使用HtmlWebpackPlugin插件就可以解决以上问题,HtmlWebpackPlugin插件的作用是在项目打包的过程,在最终的dist根目录下自动生成一个index.html文件,并且基于在调用插件的时候传入一些配置options,来实现诸如自定义模板、引入favicon等更多的功能。

基本使用

  1. 安装
npm i html-webpack-plugin -D
  1. 配置
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
	plugins:[
		new HtmlWebpackPlugin(),
	]
}
  • HtmlWebpackPlugin插件内部也是导出了一个类,但是它的导出语法是:module.exports = HtmlWebpackPlugin;所以在导入的时候无需解构,这一点和CleanWebpackPlugin的导出不一样。

  • 在配置之后就无需手动创建index.html,打包之后会自动在dist目录下有一个index.html文件,并且该文件中已经配置好了要导入的打包后的js脚本文件。

配置参数

  1. 配置参数title字段
    在new HtmlWebpackPlugin()的时候还可以传入一个options配置对象,该参数可以传递的字段有:
  • title:用于指定模板index.html中的title标签的值,如果不传递那么会采用默认值的写法
<title><%= HtmlWebpackPlugin.options.title %></title>
  1. 配置参数template字段
  • template:如果不想使用HtmlWebpackPlugin插件提供的默认模板,这个字段用于指定自定义模板的文件路径。

HtmlWebpackPlugin插件在生成最终的index.html文件的时候其实是采用了其源码中的default_index.ejs这个模板的,如下所示:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title><%= htmlWebpackPlugin.options.title %></title>
  </head>
  <body>
  </body>
</html>

但是在实际的项目开发中我们想对这个自动生成的index.html文件做一些特殊的配置,比如Vue脚手架创建的项目中,所有组件都需要最终挂载到id为app的元素上,比如还需要一个noscript标签等,而如果我们想使用一个自定义模板的话,就需要在调用创建的时候传入template字段。

  1. 项目根目录下新建一个public文件夹,将自定义模板放入该文件夹中
  2. 将template字段的值指向该模板路径即可

以Vue脚手架搭建项目时的自定义模板为例:

<!DOCTYPE html>
<html lang="en">

<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width,initial-scale=1.0">
  <link rel="icon" href="<%= BASE_URL %>favicon.ico">
  <title><%= htmlWebpackPlugin.options.title %></title>
</head>

<body>
  <noscript>
    <strong>We're sorry but mall doesn't work properly without JavaScript enabled. Please enable it to continue.</strong>
  </noscript>
  <div id="app"></div>
  <!-- built files will be auto injected -->
</body>

</html>

重新执行npm run build,会发现打包失败,失败的原因在于在使用我们自定义的模板生成index.html的时候遇到了一个全局常量BASE_URL,但是其未定义:

ReferenceError: BASE_URL is not defined

这就用到下面要介绍的DefinePlugin这个插件了。

DefinePlugin

DefinePlugin插件主要用于来配置全局常量,配置好的全局常量可以在全局多个地方使用。需要注意的是DefinePlugin插件是一个webpack内置的插件,是无需单独安装的。使用方法如下:

const { DefinePlugin } = require('webpack');
module.exports = {
	plugins:[
		new HtmlWebpackPlugin({
			title:"webpack test",
			template:"public/index.html"
		}),
		new DefinePlugin({
			BASE_URL:"'./'", // 
		})
	]
}

配置此插件的时候只需要注意两个地方:

  1. 该插件是webpack内置的,所以可以直接从webpack中导入然后解构即可
  2. 当传入options来定义全局变量的时候,如果某个全局变量的值是一个字符串,那么会将该字符串当做代码片段来加载,所以直接写BASE_URL:'./'会解析报错,正确的做法是:
// 字符串外部再用一个字符串包裹
new DefinePlugin({
	BASE_URL:"'./'", // 
})

// 使用JSON.stringify方法进行转义
new DefinePlugin({
	BASE_URL:JSON.stringify('./'), 
})

CopyWebpackPlugin

经过配置上述几个plugin之后,现在我们打包还需要实现一个功能,那就是将public文件夹下的favicon.ico这个文件经过打包之后复制到最终的打包build目录下,这样最终生成的index.html模板才可以读取到该目录下的favicon文件并生效。

CopyWebpackPlugin就是用来将某个文件夹下的资源全部复制到打包之后的dist文件夹下的一个插件,在复制的过程中还可以通过传入参数的方法来控制哪些资源会被复制,而哪些资源在打包的过程中会被过滤而不被复制,比如public下的index.html是自定义的模板文件,就不应该被复制。

  1. 安装
npm i copy-webpack-plugin -D
  1. 配置
    配置此插件的时候需要注意:
  • to字段可以不配置,因为CopyPlugin插件会自动去读取output字段下的打包文件出口目录
  • 在配置ignore字段过滤不想复制的资源的时候,必须要按照规定的写法**/文件名*来声明要过滤的资源名称,否则是无法过滤成功的。
const CopyPlugin = require('copy-webpack-plugin'); // 直接导入
module.exports = {
	plugins:[
		new CopyPlugin({
			patterns:[
				{
					from:"public",
					to:"", // 可忽略
					globOptions:{
						ignore:[
							"**/index.html*",
							"**/1.txt*"
						]
					}
				}
			]
		})
	]
}
posted @ 2022-03-06 11:21  小高同学1997  阅读(162)  评论(0编辑  收藏  举报