前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >webpack实战——预处理器(loader)【上篇】

webpack实战——预处理器(loader)【上篇】

作者头像
流眸
发布2020-07-28 15:30:03
9340
发布2020-07-28 15:30:03
举报

写在前面

这是webpack实战系列笔记的第5篇记录,前几篇记录如下:

  • 打包第一个应用
  • 模块化与模块打包
  • 资源输入与输出
  • 一切皆模块

上一篇简单描述了一切皆模块的思想,学以致用,来实践下~

1. 关于 loader

每个loader本质上都是一个函数,可用公式表达其本质:

output = loader(input)

  • input可能是工程源文件的字符串,也可能是上一个loader转化后的结果,包含:
    • 字符串(转化后的结果)
    • source map
    • AST对象(抽象语法树)
  • output同样包含上述几种信息。如果是最后一个loader,其结果直接被送到webpack中做后续处理;否则作为下一个loader的input向后传递

举个例子

当使用 babel-loader 将 ES6+ 代码转化为 ES5 时,带入公式:

ES5 = babel-loader(ES6+)

上述描述说过,loader本身是一个函数那么loader是如何工作的呢?

代码语言:javascript
复制
module.exports = function loader (content, map, meta) {
    var callback = this.async();
    var result = handler(content, map, meta);
    callback(
        null,   // error
        result.content, // 转换后的内容
        result.map, // 转换source-map
        result.meta // 转换后的AST
    )
}

可以看出,该函数对接受到的内容进行转换,然后返回转换后的结果。

2. loader配置

那在应用层面应该如何实施呢?

一切皆模块中说过静态资源的类型是各式各样的,比如静态HTML/CSS/JS、图片字体音视频等,webpack如何处理这各类资源呢?ok,loader的应用场景来了。

loader,字面意思是装载器,但在webpack中实际用途则是预处理器:webpack本身只认识JavaScript,对于其他类型的资源必须先定义一个或多个loader对其进行转译,输出为webpack能够接收的形式再继续进行,因此loader做的实际上是一个预处理的工作。

2.1 引入

那loader到底应该如何使用呢?举例要在js中引入css文件:

代码语言:javascript
复制
// index.js
import './assets/common/css'
代码语言:javascript
复制
/* common.css */

body{
    width: 100vw;
    height: 100vh;
    text-align: center;
    background: gray;
}

ok,现在我们执行打包操作,build一下,会发现在终端报错:

出现报错

为解决报错,我们需要用到的就是loader了~

可以在上图报错内容除看到,提示我们没找到合适的loader来处理,并且给出css-loader提示,我们按提示安装:

代码语言:javascript
复制
// npm
npm install css-loader

// 或者 yarn   与npm二选一即可
yarn add css-loader

安装完成后,仍需在webpack.config.js中进行loader配置:

代码语言:javascript
复制
const path = require('path')

module.exports = {
    entry: {
        index: './src/index.js',
    },

    output: {
        filename: '[name].js'
    },
    mode: 'development',

    // loader配置
    module: {
        rules: [
            // css
            {
                test: /\.css$/,
                use: ['css-loader']
            }
        ]
    }
}

可以看到,对loader进行配置,配置项都在module对象中的rules模块。rules模块是一个数组,代表了要对模块进行处理的规则。在此处,我们使用到的规则有testuse

  • test:接收一个正则表达式或者一个元素为正则表达式的数组,只有正则匹配上的模块才会使用本条规则;
  • use:接收一个数组,代表该规则所使用的loader。

然后进行打包操作:

代码语言:javascript
复制
// npm
npm run build

// 或者 yarn   与npm二选一即可
yarn build

然后发现,打包错误解决。

但,新的问题出现了:此时我们在浏览器打开index.html,发现样式并没有生效。原因是css-loader 的作用是处理css的加载语法而不是做style的样式渲染,因此我们需要添加一个 style-loader 来进行样式渲染。

2.2 链式loader

在上面我们说了需要在引入一个 style-loader 来进行样式渲染处理,先安装:

代码语言:javascript
复制
// npm
npm install style-loader

// 或者 yarn   与npm二选一即可
yarn add style-loader

接着搭配之前的webpack配置,做一些修改:

代码语言:javascript
复制
module.exports = {
    ...

    // loader配置
    module: {
        rules: [
            // css style
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader']
            }
        ]
    }
}

可以看到,我们将style-loader写在了use的数组中,并且细心的朋友可能发现写在了css-loader之前,这就是链式loader

那么为什么要区分顺序呢?在前面描述关于loader的公式中我们介绍过:

output = loader(input)

在链式webpack打包中,是按照数组从后往前的顺序将资源交给loader去处理,因此最后生效的应该放在前面。

此时,我们在执行打包操作,然后可以在浏览器中看到index.html页面加载了样式:

样式加载成功

2.3 其他配置

2.3.1 options配置

有些loader会有专门的配置项,形式上可能会有一些不同,如:

代码语言:javascript
复制
module.exports = {
    ...

    // loader配置
    module: {
        rules: [
            // css
            {
                test: /\.css$/,
                use: [
                    'style-loader',
                    {
                        loader: 'css-loader',
                        options: {
                            // css-loader相关配置
                            ...
                        }
                    }
                ]
            }
        ]
    }
}

当然,具体配置项参数和值则需要参考相应loader的文档来进行配置,用时参阅该loader文档即可。

2.3.2 exclude 和 include

从字面意思理解,这两个分别是用来排除或者包含指定目录下模块的。

如:

代码语言:javascript
复制
module.exports = {
    ...

    // loader配置
    module: {
        rules: [
            // css
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader'],
                exclude: /node_modules/
            }
        ]
    }
}

上面置顶了exclude: /node_modules/,则代表着该目录下的所有模块都不会被此条规则限制,也就是说node_modules中的模块不会执行该规则。

同样,include用途与此类似:

代码语言:javascript
复制
module.exports = {
    ...

    // loader配置
    module: {
        rules: [
            // css
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader'],
                include: /src/
            }
        ]
    }
}

可以看到此处使用的是include,代表该规则只对正则匹配到的模块生效,也就是说只对src下的模块生效。

excludeinclude同时存在的情况下,exclude优先级更高!

通常情况下,在使用loader时,需要配置它,以此来加速打包速度,不配置的话打包会将所有模块打包,可能拖慢整体的打包速度。

2.3.3 resource 与 issuer

有时候,我们会在项目中看到关于resourceissuer的相关配置,那么这两个配置是做什么的呢?

其实与excludeinclude类似,都是用于规定模块作用范围的配置。但是区别是excludeinclude对规则的作用范围更加的精确。如:

代码语言:javascript
复制
// index.js
import './src/common.css'

在webpack中,我们认为被加载模块是resource,加载者是issuer,在上述代码中,css作为被加载者,而index作为加载者。

那么具体如何使用呢?

代码语言:javascript
复制
module.exports = {
    ...

    // loader配置
    module: {
        rules: [
            // css
            {
                test: /\.css$/,
                use: ['style-loader', 'css-loader'],
                exclude: /node_modules/,
                issuer: {
                    test: /\.js$/,
                    include: /src/pages/
                }
            }
        ]
    }
}

在上面我们看到配置了issuer对象,限制是让src/pages目录下js可以引用使用规则css-loader

我们看完后会发现一个风格问题:代码可读性较差。可以稍加改善:

代码语言:javascript
复制
module.exports = {
    ...

    // loader配置
    module: {
        rules: [
            // css
            {
                use: ['style-loader', 'css-loader'],
                resource: {
                    test: /\.css$/,
                    exclude: /node_modules/
                },
                issuer: {
                    test: /\.js$/,
                    exclude: /node_modules/
                }
            }
        ]
    }
}

通过添加resource对象来讲外层配置包裹起来,区分resource和issuer的规则,看上去即可一目了然,但实际本质一样。可选择一种风格进行配置。

小结

本篇介绍了loader的作用和意义,以及在项目中实际使用时的一些配置,如引入、使用过程、链式loader、loader的配置等,从各大小方面均能做到对项目有优化或效率提升。下一篇介绍几个项目常用loader以及如何自定义loader。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2020-07-27,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 流眸 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 写在前面
  • 1. 关于 loader
  • 2. loader配置
    • 2.1 引入
      • 2.2 链式loader
        • 2.3 其他配置
          • 2.3.1 options配置
          • 2.3.2 exclude 和 include
          • 2.3.3 resource 与 issuer
      • 小结
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档