6.资源处理
在上一章,我们讲解了四种资源模块引入外部资源。除了资源模块,我们还可以通过 loader引入其他类型的文件。
什么是loader
webpack
只能理解 JavaScript
和JSON
文件,这是 webpack 开箱可用的自带能力。 loader 让 webpack 能够去处理其他类型的文件,并将它们转换为有效 模块,以供 应用程序使用,以及被添加到依赖图中。
在 webpack 的配置中,loader
有两个属性:
test
属性,识别出哪些文件会被转换。use
属性,定义出在进行转换时,应该使用哪个 loader。
6.1 HTML资源
在index.html
中是采用手动修改路径,然后才引入的,这样并不方便。我们想要实现的是webpack打包完成后自动帮助我们引入相关的资源。
于是就可以使用社区插件中的HtmlWebpackPlugin
插件。
自动引入资源
1、下载 html-webpack-plugin 插件
pnpm i html-webpack-plugin - D
2、在 webpack.config.js 文件中引入插件并调用
使用,当直接new HtmlWebpackPlugin()
的时候,会在dist文件夹下生成一个index.html
,但是它只有一些基础的配置。如果想要自行配置,则需要一个自己给定的模板index.html,然后增加一些配置,配置的参考文档:https://github.com/jantimon/html-webpack-plugin#options
该插件将为你生成一个 HTML5 文件, 在 body 中使用 script
标签引入你所有 webpack 生成的 bundle。 只需添加该插件到你的 webpack 配置中
-
不传参的情况:
new HTMLWebpackPlugin()
:会在配置的output文件夹创建一个空的html, 自动引入打包输出的所有资源,包括js, css…; -
设置参数template:复制设置的
'./src/index.html'
文件到配置的output文件夹,并自动引入打包输出的所有资源。
const HtmlWebpackPlugin = require('html-webpack-plugin');
module.exports = {
/*
html-webpack-plugin 没有任何配置会生成一个自动引入js文件的index.html
*/
plugins: [
new HtmlWebpackPlugin({
// 可以用于html模板的title标签内容
title: 'dselegent',
template: './index.html', // 打包生成的文件的模板
filename: 'app.html', // 打包生成的文件名称。默认为index.html
// 设置所有资源文件注入模板的位置。可以设置的值
// true|'head'|'body'|false,默认值为 true
inject: 'body',
压缩html代码 production环境使用
minify: {
// 移除空格
collapseWhitespace: true,
// 移除注释
removeComment: true
}
}),
],
};
模板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" />
<title><%= htmlWebpackPlugin.options.title %></title>
</head>
<body></body>
</html>
如果你有多个 webpack 入口,他们都会在已生成 HTML 文件中的 <script>
标签内引入。
如果在 webpack 的输出中有任何 CSS 资源(例如,使用 MiniCssExtractPlugin 提取的 CSS),那么这些资源也会在 HTML 文件 <head>
元素中的 <link>
标签内引入。
打包:
查看 app.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" />
<title>我是dselegent</title>
</head>
<body>
<script defer src="bundle.js"></script>
</body>
</html>
这次打包应用到了我们的模板文件 index.html , 并且生成了新的文件 app.html , 文 件里自动引用的 bundle.js 也从 迁移到了里。
Webpack 会在输出目录中新创建一个 HTML 文件,在原始的 HTML 文件中无需引入 JS 文件,通过 Webpack 编译后的 HTML 文件会自动引入。
官方说明:https://webpack.docschina.org/plugins/html-webpack-plugin/
配置选项:https://github.com/jantimon/html-webpack-plugin#options
6.2 样式资源
Webpack 本身是不能识别样式资源的,所以我们需要借助 Loader 来帮助 Webpack 解析样式资源
我们找 Loader 都应该去官方文档中找到对应的 Loader,然后使用
官方文档找不到的话,可以从社区 Github 中搜索查询
.css文件:style-loader, css-loader
;
css-loader
:将css文件转换成commonjs模块加载到js中,css代码被转换成了样式字符串。(转换后得到的commonjs模块可以理解为:用js给元素动态添加样式的那种代码);style-loader
:创建style标签
,将css-loader
生成的样式资源插入进去,添加到head中,使样式生效。
.less文件:style-loader, css-loader, less-loader
;
less-loader
:将less文件编译成css文件;- 注:要想
less-loader
生效,还需要下载less
(npm install less -D
)。
.scss/.sass文件:style-loader, css-loader, sass-loader
;
sass-loader
:将sass或scss文件编译成css文件;- 注:要想
sass-loader
生效,还需要下载node-sass
(npm install node-sass -D
)。
6.2.1 css
下载包
pnpm add css-loader style-loader -D
注意:需要下载两个 loader
功能介绍
css-loader
:负责将 Css 文件编译成 Webpack 能识别的模块style-loader
:会动态创建一个 Style 标签,里面放置 Webpack 中 Css 模块内容
此时样式就会以 Style 标签的形式在页面上生效
配置
module.exports = {
...
module: {
rules: [
{
// 用来匹配 .css 结尾的文件
test: /\.css$/i,
// 写法一:
// use 数组里面 Loader 执行顺序是从右到左
use: [
'style-loader', // 创建style标签,将'css-loader'整合到js中的样式字符串放到style标签中。
'css-loader' // 将css文件转换成commonjs模块加载到js中,css代码被转换成了样式字符串。
],
// 写法二:
use: [
{
loader: 'style-loader' },
{
loader: 'css-loader' }
]
}
]
}
}
模块 loader
可以链式调用。链中的每个 loader
都将对资源进行转换。链会逆序执 行。第一个 loader
将其结果(被转换后的资源)传递给下一个 loader
,依此类推。 最后,webpack
期望链中的最后的 loader
返回 JavaScript
。
应保证 loader 的先后顺序: 'style-loader'
在前,而 'css-loader'
在后。如果 不遵守此约定,webpack 可能会抛出错误。webpack
根据正则表达式,来确定应该 查找哪些文件,并将其提供给指定的 loader
。在这个示例中,所有以 .css
结尾的 文件,都将被提供给 style-loader
和css-loader
。
这使你可以在依赖于此样式的 js 文件中 import './style.css'
。现在,在此模块执行过程中,含有 CSS 字符串的 <style>
标签,将被插入到html
文件的<head>
中。
通过在项目中添加一个新的style.css
文件,并将其import
到我 们的 index.js
中:
07-manage-assets/src/style.css
hello {
color: #f9efd4;
}
在入口文件index.js
里导入.css
文件:
// 引入 Css 资源,Webpack才会对其打包
import './style.css'
document.body.classList.add('hello')
你应该看到页面背景颜色是浅黄色。要查看 webpack 做了什么,请检查页面(不要 查看页面源代码,它不会显示结果,因为<style>
标签是由 JavaScript 动态创建 的),并查看页面的 head 标签,包含 style
块元素,也就是我们在 index.js
中 import 的 css 文件
中的样式。
6.2.2 less&sass
下载样式处理解析器
pnpm i sass-loader sass -D
pnpm i less-loader less -D
sass-loader
:负责将 Sass 文件编译成 css 文件sass
:sass-loader
依赖sass
进行编译
在配置文件中添加解析器
module.exports = {
...
module: {
rules: [
{
test: /\.s[ac]ss$/i,
use: [
// 在 head 中创建 style 标签
'style-loader',
// 将 css 文件整合到 js 文件中
'css-loader',
// 编译 sass 文件为 css 文件
'sass-loader'
]
},
{
test: /\.less$/,
use: ["style-loader", "css-loader", "less-loader"],
},
]
}
}
在项目 src
目录下创建 style.less
文件:
@color: red;
body {
color: @color;
}
在 index.js
文件中导入 less
文件
import './style.less'
document.body.classList.add('world')
由预览的效果可见,页面的文字都添加了“红色”的样式。
不同的样式文件会新建一个
style
标签
6.2.3 抽离CSS
Css 文件目前被打包到 js 文件中,当 js 文件加载时,会创建一个 style 标签来生成样式,这样对于网站来说,会出现闪屏现象,用户体验不好,我们应该是单独的 Css 文件,通过 link 标签加载性能才好。
在多数情况下,我们也可以进行压缩CSS,以便在生产环境
中节省加载时间,同时还 可以将CSS文件抽离成一个单独的文件。实现这个功能,需要 mini-css-extractplugin
这个插件来帮忙。安装插件:
下载包
pnpm i mini-css-extract-plugin -D
本插件会将取代style-loader
, 将 CSS 提取到单独的文件中,为每个包含 CSS 的 JS 文件创建一个 CSS 文件,并且支持 CSS 和 SourceMaps 的按需加载。
本插件基于 webpack v5
的新特性构建,并且需要 webpack 5 才能正常工作。
之后将 loader
与plugin
添加到你的 webpack
配置文件中:
配置
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
module.exports = {
...
module: {
rules: [
{
// 用来匹配 .css 结尾的文件<