0%

webpack(二)--Loader

打包静态文件

Loader

前序问题:

  1. webpack 是什么?
  2. 模块是什么
  3. webpack 配置文件的作用是什么?

回答:1.webpack 是模块打包工具。

  1. 模块是项目中的 js 文件、css、或者是一张图片等。
  2. 配置文件是配置如何去打包模块

打包图片文件

webpack 可以打包 js 文件,但是非 js 文件需要手动在模块中定义如何打包。以 jpg 文件为例,看代码中如何配置.其他类型的文件同理,需要用对应的 loader 去配置

1
2
3
4
5
6
7
8
9
10
11
12
13
[webpack.config.js];
module.exports = {
module: {
rules: [
{
test: /\.jpg$/,
use: {
loader: "file-loader",
},
},
],
},
};

module 是个对象,包含的 rules 是数组,数组中定义了以 jpg 结尾的文件名(正则表达式),这样的文件用file-loader这个 loader 来打包。

当然,需要用 npm 安装这个 file-loader。

file-loader 做了什么?

它发现有.jpg 结尾的文件后,就把它打包移动到 output 目录(这里是 dist)并重命名(名字也可以在配置文件中自定义)。得到图片名称后,会把名字作为返回值,返回给引入模块的变量中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[index.js];
var Header = require("./header.js");
var Sidebar = require("./sidebar.js");
var Content = require("./content.js");
var avatar = require("./avatar.jpg");

console.log(avatar);
//打包后在dist中的图片名称:\dist\e49823921af3dad34a48ed93700b95ac.jpg

new Header();
new Sidebar();
new Content();

var img = new Image();
img.src = avatar;
var root = document.getElementById("root");
root.appendChild(img);

vue 文件同理要用 vue-loader

自定义静态文件打包后的名字/路径等信息

通过配置 loader 的 option 参数。

1
2
3
4
5
6
7
8
9
10
11
12
{
test: /\.jpg$/,
use: {
loader: "file-loader",
options: {
//name就是图片文件本身的name
//ext是图片本身的后缀
name: "[name].[ext]",
outputPath: "images/", //打包到dist下的images文件夹下
},
},
},

name: "[name].[ext]"这种语法叫 placeholder 占位符。在官网可以查到各种占位符如[hash]等等。

url-loader

这个 loader 同样可以打包 jpg|png|gif 等图片文件,但不是把图片打包到 dist 文件夹的方式,而是把图片转换为 base64 编码,直接放入 bundle.js 文件中。节省一次 http 请求,但会浪费加载时间。

所以 url-loader 有一个配置 limit,如果图片大于 limit,就打包成图片文件,如果小于 limit,就打包到 bundle.js 中,配置如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//rules
{
test: /\.jpg$/,
use: {
loader: "file-loader",
options: {
//name就是图片文件本身的name
//ext是图片本身的后缀
name: "[name].[ext]",
outputPath: "images/", //打包到dist下的images文件夹下
limit : 10240 //10kb
},
},
},

打包样式文件

需要用到 [“style-loader”, “css-loader”]

1
2
3
4
5
//module
{
test: /\.css$/,
use: ["style-loader", "css-loader"],
},

css-loader:分析出几个 css 文件之间的关系,最终把这几个 css 文件合并成一段 css。

style-loader:把 css-loader 生成的 css 代码片段挂载到页面的 header 部分。

scss less stylus

.scss 结尾的需要额外的 sass-loader 去把.scss 文件翻译成 css 文件

1
2
3
4
5
//module
{
test: /\.css$/,
use: ["style-loader", "css-loader" , "sass-loader"],
},

loader 的执行是有顺序的, 顺序是从下到上,从右到左

自动添加厂商前缀

1
2
3
4
5
//module
{
test: /\.css$/,
use: ["style-loader", "css-loader", "sass-loader", "postcss-loader"],
},

通过查看 webpack 官网的 loader,发现 postcss-loader 需要配置文件。

1
2
3
4
5
[postcss.config.js];
module.exports = {
//使用了autoprefixer来自动添加厂商前缀
plugins: [require("autoprefixer")],
};

并安装这个 autoprefixer 插件,就可以实现自动添加厂商前缀的效果了,可以在打包后的 html 文件用浏览器打开查看。

css-loader 中的 importLoaders

  • 官网解释:

importLoaders

查询参数 importLoaders,用于配置「css-loader 作用于 @import 的资源之前」有多少个 loader。

webpack.config.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
test: /\.css$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
importLoaders: 2 // 0 => 无 loader(默认); 1 => postcss-loader; 2 => postcss-loader, sass-loader
modules : true //开启模块化打包,下小结详细讲解
}
},
'postcss-loader',
'sass-loader'
]
}

在模块系统(即 webpack)支持原始 loader 匹配后,此功能可能在将来会发生变化。

  • 适用情况:

当一个 scss 文件中@import 了新的 scss 文件,此时对原文件的打包已经按顺序加载到了 css-loader 的功能,引入的 scss 文件用 css-loader 加载就会出错。这个importLoaders用来使引入的 scss 文件依然从 sass-loader 开始加载。

css 打包的模块化

在入口文件中引入的样式文件会作用在全局,可能会出现意外的样式覆盖问题,所以引入 css 模块化概念。

只需要加一句modules:true即可开启。

对应的,在入口文件中也需做修改,注意:如果依然按全局引入的话样式会不生效。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
[index.js]入口文件
import avatar from "./avatar.jpg";
import Avatar from "./avatar";

//import "./avatar"; //在这里引入的样式作用在全局,容易出现样式冲突
import style from "./index.scss"; //使用模块化的css,配合css-loader的option:{modules:true}

Avatar();

var root = document.getElementById("root");
var img = new Image();
img.classList.add(style.avatar); //模块引入的使用方法
//img.classList.add("avatar"); //全局引入的使用方法
img.src = avatar;
root.append(img);

打包后:
<img class="_17cnVz87yzSOO5TpFdnLsk" src="images/avatar.jpg">

在其他 js 文件中使用同理。

打包字体文件

如 iconfont 的eot .ttf .svg .woff等,需要额外的 loader 去进行打包。这里使用的是 file-loader。配置与 url-loader 类似。

最后附上完整文件,github 地址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
[webpack.config.js];

const path = require("path");
module.exports = {
mode: "development", //添加mode,否则在打包时会有警告,默认值是 production
entry: { main: "./src/index.js" },
output: {
filename: "bundle.js",
path: path.resolve(__dirname, "dist"), //这里必须使用绝对路径,所以引入node的核心模块path,生成一个绝对路径,__diename就是当前文件所在目录
},
module: {
rules: [
{
test: /\.(jpg|png|gif)$/,
use: {
loader: "url-loader",
options: {
name: "[name].[ext]",
outputPath: "images/", //打包到dist下的images文件夹下
limit: 10240, //limit 图片小于10k则变成base64写入bundle.js,大于10k则单独打包到image文件夹中
},
},
},
{
test: /\.(eot|ttf|svg|woff)$/,
use: {
loader: "file-loader",
options: {
name: "[name].[ext]",
outputPath: "font/", //打包到dist下的font文件夹下
},
},
},
{
test: /\.scss$/,
use: [
"style-loader",
{
loader: "css-loader",
options: {
//配置「`css-loader 作用于 `@import` 的资源之前」有多少个 loader。
importLoaders: 2, // 0 => 无 loader(默认); 1 => postcss-loader; 2 => postcss-loader, sass-loader
//modules: true,
},
},
"postcss-loader",
"sass-loader",
],
},
],
},
};