webpack 基础篇 (二)之 loader

前言

(ps: 本篇内容基于上一篇继续)

Webpack中必须掌握的配置

loader主要用于把模块原内容按照需求转换成新内容,可以加载非 JS 模块!
通过使用不同的Loader,Webpack可以把不同的文件都转成JS文件,比如CSS、ES6/7、JSX等。
我们来看看这些我们必须掌握的loader!

1.loader的编写

1.1 loader的使用

  • test:匹配处理文件的扩展名的正则表达式
  • use:loader名称,就是你要使用模块的名称
  • include/exclude:手动指定必须处理的文件夹或屏蔽不需要处理的文件夹
  • options:为loaders提供额外的设置选项

默认loader的顺序是从下到上从右向左执行,当然执行顺序也可以手动定义的,接下来我们依次介绍常见的loader,来感受loader的魅力!

2.处理CSS文件

2.1 解析css样式

新建 /src/index.css

1
2
3
body{
background: red;
}

我们在inde.js文件中引入css样式!

1
import './index.css';

再次执行打包时,会提示css无法解析

1
2
3
ERROR in ./src/index.css 1:4
Module parse failed: Unexpected token (1:4)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders

安装loader

  • 解析css 需要两个loader css-loader style-loader
  • css-loader 会解析css语法,将解析出来的结果传递给style-loader, style-loader 会将解析的css 变成style标签插入到页面中
1
npm install style-loader css-loader --save-dev
1
2
3
4
5
6
7
8
9
10
11
module:{
// 转化什么文件,用什么去转,使用哪些loader
rules:[
{
test:/\.css$/, // 以css结尾的文件
// 要使用那些loader
// loader 的写法 [] | {} | '',三种方式
use: ['style-loader', 'css-loader']
}
]
},

2.2 css预处理器

不同的css预处理器要安装不同的loader来进行解析

  • .scss:     node-sass   sass-loader
  • .less:      less             less-loader
  • .stylus:   stylus           stylus-loader

下面以sass为例:
npm install node-sass sass-loader --save-dev
新建/src/a.scss

1
2
3
4
5
6
$background: black;
div{
width: 100px;
height: 100px;
background: $background;
}

index.js

1
2
3
4
import './index.css';
import './a.scss';
let result = require('./a-module');
console.log(result);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
module:{
// 转化什么文件,用什么去转,使用哪些loader
rules:[
{
test:/\.css$/, // 以css结尾的文件
// 要使用那些loader
// loader 的写法 [] | {} | '' ",三种方式
use: ['style-loader', 'css-loader']
},
{ // 匹配到scss结尾的文件使用 sass-loader 来调用node-sass处理sass文件
test: /\.scss$/,
use:['style-loader', 'css-loader', 'sass-loader']
}
]
},

打包 npm run dev 可以看到页面上有个一块黑色的div

** 注意:**

在index.css文件中可能会使用@import语法引用a.css文件,被引用的a.css文件中可能还会导入a.scss 这时去打包 是不会解析a.scss文件的,会把它当做css文件直接显示在页面中。
设置options,如下 :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
module:{
rules:[
{
test:/\.css$/,
use: ['style-loader',{
loader: 'css-loaser',
options:{ // 给loader传递参数
// 如果css文件引入了其他文件@import
importLoaders: 1 // 1表示使用后面的一个即 'sass-loader',2表示使用后面的2个...以此类推
}
}, 'sass-loader']
},
{
test: /\.scss$/,
use:['style-loader', 'css-loader', 'sass-loader']
}
]
},

2.3 处理样式前缀

打包css的时候需要处理下样式前缀
index.css

1
2
3
4
body{
background: red;
transform: rotate(45deg); // 这个语法需要带前缀
}

使用postcss-loader增加样式前缀

1
npm install postcss-loader autoprefixer --save-dev
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
module:{
rules:[
{
test:/\.css$/,
use: ['style-loader',{
loader: 'css-loader',
options:{
importLoaders: 2 // *****这里改成 2
}
}, 'postcss-loader', 'sass-loader'] ']// 顺序是sass先编译完成 => 再加前缀 => 再转成css => 再放到style中 ,后面放了2个,所以上面变成2
},
{
test: /\.scss$/,
use:['style-loader', 'css-loader', 'sass-loader']
}
]
},

需要创建postcss的配置文件postcss.config.js

1
2
3
4
5
6
// 默认自动添加前缀
module.exports = {
plugins:[
require('autoprefixer')
]
}

可以配置浏览器的兼容性范围, 新建文件.browserslistrc

1
cover 95%

意思表示能兼容95%的浏览器

** 如上可知 这样配置样式,开发的时候是可以的,上线时解析css的时候就不能渲染dom(因为它是单线程的,这样会将js、css都打包到一个bundle.js文件中), 希望css可以并行和js一同加载,所以现在将css抽离出来**

2.4 抽离样式文件

只在生产模式时进行样式抽离,抽离css的好处是可以和js并行加载。

安装抽离插件

1
npm install mini-css-extract-plugin --save-dev

webpack.base.js 配置文件如下:

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
const path = require('path');
const merge = require('webpack-merge');
const dev = require('./webpack.dev');
const prod = require('./webpack.prod');
const HtmlWebpackPlugin = require('html-webpack-plugin');
// css抽离插件
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
module.exports = (env) =>{
let isDev = env.development;
const base = {
entry:'./src/index.js',
output:{
filename:'bundle.js',
path:path.resolve(__dirname,'../dist')
},
module:{
rules:[
{
test:/\.css$/, //
use: [ //是不是开发环境 如果是就用 style-loader
isDev ? 'style-loader' : MiniCssExtractPlugin.loader,
{
loader: 'css-loader',
options:{
importLoaders: 2
}
}, 'postcss-loader','sass-loader']
},
{
test: /\.scss$/,
use:['style-loader', 'css-loader', 'sass-loader']
}
]
},
plugins:[
!isDev && new MiniCssExtractPlugin({// 如果是开发模式就不要使用抽离样式的模式
filename: 'css/main.css'
}),
new HtmlWebpackPlugin({})
].filter(Boolean) // 如上line36 如果是开发模式则会返回false,这里加上Boolean进行过滤
}
if(isDev){
return merge(base,dev);
}else{
return merge(base,prod)
}
}

打包 npm run build,可以看到 /dist/css/main.css 生成了css文件,样式抽离出来了。

2.5 css压缩

在生产环境下默认只压缩js,要想压缩css需自行配置。如下:
webpack.pro.js

1
2
3
4
5
6
7
8
9
10
11
const OptimizeCSSAssetsPlugin = require('optimize-css-assets-webpack-plugin');
const TerserWebpackPlugin = require('terser-webpack-plugin');
module.exports = {
mode:'production',
optimization:{ // 优化项
minimizer:[ // 可以放置压缩方案
new OptimizeCSSAssetsPlugin(), // 用了这个 js 也得手动压缩
new TerserWebpackPlugin() // 如果不写这行,js不会压缩成一行
]
}
}

在生产环境下我们需要压缩css文件,配置minimizer选项,安装压缩插件

1
npm i optimize-css-assets-webpack-plugin terser-webpack-plugin --save-dev

2.6 文件指纹

  • Hash整个项目的hash值
  • chunkhash 根据入口产生hash值
  • contentHash 根据每个文件的内容产生的hash值

我们可以合理的使用hash戳,进行文件的缓存

1
2
3
!isDev && new MiniCssExtractPlugin({
filename: "css/[name].[contentHash].css"
})

3.处理文件类型

3.1 处理引用的图片

1
npm install file-loader --save-dev
1
2
3
4
import logo from './webpack.png';
let img = document.createElement('img');
img.src = logo;
document.body.appendChild(img);

使用file-loader,会将图片进行打包,并将打包后的路径返回

1
2
3
4
5
{
test: /\.(jpe?g|png|gif)$/,
use: 'file-loader' // file-loader 默认的功能是拷贝的作用
// 我希望当前比较小的图片可以转化成 base64 (缺点是转化后比以前大) 好处就是不用发送http请求
}

3.2 转化成base64

1
npm install url-loader --save-dev

使用url-loader将满足条件的图片转化成base64,不满足条件的url-loader会自动调用file-loader来进行处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
{
//图片的转化
test: /\.(jpe?g|png|gif)$/,
//use: 'file-loader' // file-loader 默认的功能是拷贝的作用
// 我希望当前比较小的图片可以转化成 base64 (缺点是转化后比以前大) 好处就是不用发送http请求
use:{
loader: 'url-loader',
options:{
// 如果大于8k(一般是8k)的图片会使用 file-loader
limit: 8 * 1024,
name: 'image/[contenthash].[ext]', // 可以查看 npmjs.com => 搜索file-loader
}
}
}

url-loader 不适用的场景:
一个图片好几次或大量使用时,浏览器本来是有缓存的,结果你直接生成 base64 打包到代码里面,请求速度来讲无疑是不划算的。

3.3 处理icon

二进制文件也是使用file-loader来打包

1
2
3
4
5
6
7
{
// 图标的转化
test: /\.(woff|ttf|eot|svg)$/,
use:{
loader:'file-loader'
}
}