asset module type
在webpack5之前,加载文件资源我们需要使用一些loader,比如raw-loader 、url-loader、file-loader
在webpack5之后,我们可以直接使用资源模块类型(asset module type),来替代上面的这些loader
| 资源模块名 | 功能 |
|---|---|
| asset/resource | 发送一个单独的文件并导出 URL。之前通过使用 file-loader 实现 |
| asset/inline | 导出一个资源的 data URI。之前通过使用 url-loader 实现 |
| asset/source | 导出资源的源代码。之前通过使用 raw-loader 实现 |
| asset | 在导出一个 data URI 和发送一个单独的文件之间自动选择。之前通过使用 url-loader,并且配置资源体积限制实现 |
{
test: /\.(png|jpe?g|gif|svg)/,
type: 'asset/inline'
}
{
test: /\.(png|jpe?g|gif|svg)/,
type: 'asset/resource',
generator: {
// tips: 这里ext是有点的,这和file-loader是不一样的
filename: 'imgs/[name].[hash:5][ext]'
}
}
{
test: /\.(png|jpe?g|gif|svg)/,
type: 'asset',
generator: {
filename: 'imgs/[name].[hash:5][ext]'
},
parser: {
// 这里和file-loader的limit配置项是一致的
dataUrlCondition: {
maxSize: 100 * 1024
}
}
}
除了上述配置外,还有一种可以全局配置资源存放位置和名称的方式
output: { // 在顶层output中进行设置
path: path.resolve(__dirname, 'dist'),
filename: 'main.js',
// 一般不用,因为这是全局配置,一般需要对具体的资源进行单独设置
// 局部和全局同时存在,局部配置覆盖全局配置
assetModuleFilename: 'imgs/[name].[hash:5][ext]'
}
raw-loader
将资源内容解析为字符串,再进行引入,一般适用于在模块中引入txt等格式文件的时候使用
# 安装
$ npm i raw-loader -D
{
test: /\.txt/,
loader: 'raw-loader'
}
字体打包
对于一些其它资源,如视频,音频和字体文件,直接使用file-loader打包成链接引入即可,或直接使用asset/resource
{
test: /\.eot|ttf|woff2?/,
type: 'asset/resource',
generator: {
filename: 'font/[name].[hash:6][ext]'
}
}
插件
Loader是用于特定的模块类型进行转换
Plugin可以用于执行更加广泛的任务,比如打包优化、资源管理、环境变量注入
CleanWebpackPlugin
前面我们练习的过程中,每次修改了一些配置,重新打包时,都需要手动删除dist文件夹
这个操作可以借助于一个插件来帮助我们自动完成,这个插件就是CleanWebpackPlugin
# 安装
$ npm i clean-webpack-plugin -D
// 配置 部分
/*
1. 绝大部分plugin导出都是使用默认导出,但是CleanWebpackPlugin使用的是普通导出,所以在引入的时候需要注意
2. 多少情况下,plugin是一个个的类,所以导入的名称首字母是大写的,且使用的时候使用new来创建对应的实例对象
*/
const { CleanWebpackPlugin } = require('clean-webpack-plugin')
// ...... 此处为省略的其它配置
module.exports = {
plugins: [
new CleanWebpackPlugin()
]
}
HtmlWebpackPlugin
之前练习的时候,我们的HTML文件是编写在根目录下的,而最终打包的dist文件夹中是没有index.html文件的
在进行项目部署时,必然也是需要有对应的入口文件index.html
其次,我们打包后的js文件也是应该自动在index.html中进行引入的,而不是手动引入,因为每一个项目的js名称是不一样的
而且可能会对打包后的文件进行分包处理,所以手动引入显然是不合适的
此时我们就需要一个插件帮助我们自动完成上述功能, 即HtmlWebpackPlugin
# 安装
$ npm i html-webpack-plugin -d
// js配置 --- 部分
const HtmlWebpakcPlugin = require('html-webpack-plugin')
// .... 部分配置省略
plugins: [
new HtmlWebpakcPlugin() // 如果没有设置html模板,会使用内置的默认html模板(default_index.ejs)
]
有的时候,我们想在自己的模块中加入一些比较特别的内容
- 如添加一个noscript标签,在用户的JavaScript被关闭时,给予响应的提示
- 如在开发vue或者react项目时,我们需要一个可以挂载后续组件的根标签
// 自定义配置
const HtmlWebpakcPlugin = require('html-webpack-plugin')
// ....
plugins: [
new HtmlWebpakcPlugin({
title: 'webpack tutorial', // 这个配置项会被加入到options中
// 一般,我们会将一个公共全局的静态资源存放在根目录下的public文件夹中 如index.html,favicon.ico
template: './public/index.html', // 这个配置项会被作为html模板去进行使用
// 设置于meta中的属性,会被自动添加到head标签中
meta: {
'x-version': '1.0.0'
}
})
]
index.html
<!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">
<!-- 模板默认是使用ejs来进行编写的 title的值就是传入的配置中的title的值,默认值是Webpack App -->
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body>
</body>
</html>
DefinePlugin
DefinePlugin允许在编译时创建配置的全局常量,是一个webpack内置的插件(不需要单独安装)
// 配置 --- 部分
const { DefinePlugin } = require('webpack')
// ...
plugins: [
new DefinePlugin({
// DefinePlugin中配置的key-value的值会做作为字符串进行解析,所以其值需要被设置成字符串类型
// 注意,其取值的时候,会将引号中的内容单独取出,作为值来使用 (比较特别)
// 所以'./'会被看成是./ 所以会报错,因此需要写成"'./'"
BASE_URL: "'./'",
// 配置在DefinePlugin中的key,可以在任何地方被引用,包括vue文件,js文件
// webpack在编译的时候会对这些变量进行统一的解析和处理
ENV: JSON.stringify('development')
})
]
此時我们就可以在全局,也就是任何地方,使用我们在DefinePlugin中定义的全局变量
例如,在index.html模板中
<link rel="icon" href="<%= BASE_URL %>favicon.ico">
if (ENV === 'development') {
// 开发环境适用的代码
} else {
// 生产环境适用的代码
}
CopyWebpackPlugin
如果我们将一些文件放到public的目录下,需要在编译的时候,将这个目录会被复制到dist文件夹下
这个复制的功能,我们可以使用CopyWebpackPlugin来完成
# 安装
$ npm install copy-webpack-plugin -D
// 配置 --- 部分
const CopyWebpackPlugin = require('copy-webpack-plugin')
new CopyWebpackPlugin({
patterns: [
{
from: 'public',
// to: 'dist', ===> to 可以省略,默认值为打包后存放代码的那个文件夹即output.path的值
globOptions: { // 对于每一个pattern的option
ignore: [
// 忽略 注意如果忽略public下的文件资源的时候,需要加上**/作为前缀,
// 直接写index.html的时候,CopyWebpackPlugin插件是不会有效的帮助我们忽略index.html文件的
'**/index.html', // 也不需要复制,因为我们已经通过HtmlWebpackPlugin完成了index.html的生成
'**/.DS_Store' // mac目录下回自动生成的一个文件,描述当前文件夹的相关信息
]
}
}
]
})
friendly-errors-webpack-plugin
friendly-errors-webpack-plugin可以优化webpack为我们的提示信息,但是friendly-errors-webpack-plugin这个插件本身已不再支持webpack5,所以这里使用的是社区的@soda/friendly-errors-webpack-plugin
const FriendlyErrorsWebpackPlugin = require('@soda/friendly-errors-webpack-plugin')
// 在node环境中可以获取本机IP地址的包
const internalIp = require('internal-ip')
plugins: [
new FriendlyErrorsWebpackPlugin({
compilationSuccessInfo: {
messages: [
`You application is running here http://localhost:${devServer.port}`,
`You application is running here http://${internalIp.v4.sync()}:${devServer.port}`
]
}
})
]
internal-ip
internal-ip是一个在node环境下运行的库
const internalIp = require('internal-ip');
(async () => {
console.log(await internalIp.v6());
//=> 'fe80::1'
console.log(await internalIp.v4());
//=> '10.0.0.79'
})();
console.log(internalIp.v6.sync())
//=> 'fe80::1'
console.log(internalIp.v4.sync())
//=> '10.0.0.79'