Webpack入门,预处理器

一个Web工程通常会包含HTML、JS、CSS、图片、字体等多种类型的静态资源,且这些资源之间都存在着某种联系。对于Webpack来说,所有这些静态资源都是模块,开发者可以像加载一个JS文件一样去加载它们。比如在index.js中加载style.css。

// index.js
import "./style.css"

提示

对于初学者,可能会有这样的疑问:从JS中加载CSS文件具有怎样的意义呢?从结果来看,其实和之前并没有什么差别,这个style.css可以被打包并生成在输出资源目录下,对index.js文件也不会产生实质性的影响。这句引用的实际意义是描述了JS文件与CSS文件之间的依赖关系。

loader概述

loader是Webpack中的一个核心概念,可以理解为一个代码转换的工具。每个loader本质上都是一个函数,可以表示为以下形式:out = loader(input)这里的input可能是工程源文件的字符串,也可能是上一个loader转化后的结果,output则包括了转化后的代码、sourcemap和AST对象。如果这是最后一个loader,结果将直接被送到Webpack进行后续处理,否则将作为下一个loader的输入向后传递。loader可以是链式的,开发者可以对一种资源设置多个loader,第一个loader的输入是文件源码,之后所有loader的输入都为上一个loader的输出。用公式表达则为:output = loaderA(loaderB(loaderC(input)))

在Webpack中,本身只认识Javascript,对于其他类型的资源,开发者必须先定义一个或多个loader对其进行转译,输出为Webpack能够接收的形式再继续进行,因此loader做的实际上是一个预处理的工作。

loader的引入

// app.js
import "./style.css"
// style.css
body {
  text-align: center;
  padding: 100px;
  color: #fff;
  background-color: #09c;
}

此时工程中还没有任何loader,如果直接打包会看到报错提示。这是因为Webpack无法处理CSS语法。

如果想让Webpack能够处理CSS语法,需要在工程中引入css-loader。

提示

loader都是一些第三方npm模块,因此使用loader的第一步就是先从npm安装它。

在工程目录下安装css-loader。

npm install css-loader -D

接下来将loader引入工程中,具体配置如下

// webpack.config.js
module.exports = {
  // ...
  module: {
    rules: [{
      test: /\.css$/,
      use: ['css-loader'],
    }]
  }
}

与loader相关的配置都在module对象中,其中module.rule代表了模块的处理规则。每条队则内部可以包含很多配置项,这里我们只使用了最重要的两项:test和use。

  • test可接收一个正则表达式或者一个元素为正则表达式的数组,只有正则匹配上的模块才会使用这条规则。
  • use可接收一个数组,数组包含该规则所使用的loader。在只有一个loader时可以将其简化为字符串“css-loader”。

此时再进行打包,就不会出现报错的情况了。但是CSS的样式没有在页面上生效。这是因为css-loader的作用仅仅是处理CSS的各种加载语法(@import和url()函数等),如果要使样式起作用需要style-loader来把样式插入页面。css-loader与style-loader通常是配合在一起使用的。

提示

Webpack在打包时是按照数组从后往前的顺序将资源交给loader处理的。所以在使用多个loader时,要把最后生效的放在前面。例如在使用style-loader和css-loader时,要把style-loader加到css-loader前面。

loader更多配置

exclude与include

exclude与include用于排除或包含指定目录下的模块,可接收正则表达式或者字符串(文件绝对路径),或者由它们组成的数组。

// webpack.config.js
module.exports = {
  ...
  module: {
    rules:[{
      test: /\.css$/,
      use: ['style-loader','css-loader'],
      exclude: /node_modules/,
    }]
  }
}

上面exclude的含义是,所有被正则匹配到的模块都排除在该规则之外,也就是说,node_modules中的模块不会执行这条规则。该配置项通常是必加的,否则将拖慢整体的打包速度。

与exclude相反,include的含义是只对正则匹配到的模块生效。

温馨提示

当exclude和include同时存在时,exclude的优先级更高。

resource与issuer

resource与issuer用于更加精准地确定模块规则的作用范围。 resource指的是被加载模块,issuer指的是加载者。

请看下面的例子

// index.js
import "./style.css"

在示例中,被加载模块(resource)是style.css,加载者(issuer)是index.js。

test、exclude、include本质上均属于对resource也就是被加载者的配置,如果想要对issuer加载者也增加条件限制,则要额外写一些配置。比如,只想让/src/pages目录下的JS可以引用CSS。

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

可以看到,添加了issuer配置对象,其形式与之前对resource条件的配置并无太大差异,但只有/src/pages/目录下面的JS文件引用CSS文件,这条规则才会生效。

上面的配置虽然实现了的需求,但是test、exclude、include这些配置项分布于不同的层级上,可读性较差。事实上还可以将它改为另一种等价的形式。

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

上面的配置,分别包裹了resource和issuer中的规则,这样就一目了然了。

enforce

enforce用来指定一个loader的种类,只接收pre或post两种字符串类型的值。

Webpack中的loader按照执行顺序可分为pre、inline、normal、post四种类型。上面的示例中直接定义的loader都属于normal类型,inline形式官方已经不推荐使用,而pre和post则需要使用enforce来指定。

// webpack.config.js
module.exports = {
  ...
  module: {
    rules: [{
      test: /\.js$/,
      enforce: 'pre',
      use: 'eslint-loader',
    }]
  }
}

在上面的配置中,添加了一个eslint-loader来对源码进行质量检测,其enforce的值为pre。表示它将在所有正常loader之前执行,这样可以保证其检测的代码不是被其他loader更改过的。类似地,如果某一个loader需要在所有loader之后执行,可以指定其enforce为post。

温馨提示

事实上,开发者可以不使用enforce而只要保证loader顺序是正确的即可。配置enforce的主要目的是使模块规则更加清晰,可读性更强。在实际工程中,配置文件可能会出现达到上百行的情况,此时开发者很难保证各个loader都按照预想的方式工作,而使用enforce可以强制指定loader的作用顺序。

示例代码仓库

https://gitee.com/zero_79152105/webpack-vblog

原创文章,作者:ZERO,如若转载,请注明出处:https://www.edu24.cn/course/webpack-loader.html

Like (0)
Donate 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
ZEROZERO
Previous 2022年11月18日
Next 2022年11月23日

相关推荐

  • 封装JDBC工具类,连接MySQL数据库

    JDBC是由java编程语言编写的类及接口组成,同时它为程序开发人员提供了一组用于实现对数据库访问的JDBC API,并支持SQL语言。利用JDBC可以将JAVA代码连接到orac…

    2022年3月31日
    764
  • Java自学之多线程编程

    多线程编程是Java语言最为重要的特性之一。利用多线程技术可以提升单位时间内的程序处理性能,也是现代程序开发中高并发的主要设计模式。 进程与线程 进程是一个应用程序。线程是一个进程…

    2020年12月16日
    1.4K
  • Angular 4.x ngModel 双向绑定原理揭秘

    一直以来都没有去深入探究Angular,只是熟练运用。真要被问起来,很多关于angular的理论知识都回答不上来。感觉上学背书的能力已经丧失的差不多了。只能以这样的方式搜集整理出来。

    2019年7月2日
    1.8K
  • 日常开发 26 个常见的 JavaScript 代码优化方案

    1、NULL、Undefined、”【空】检查 我们在创建新变量赋予一个存在的变量值的时候,并不希望赋予null或undefined,我们可以采用以下简洁的赋值方式。 …

    2021年2月22日
    1.2K
  • Angular环境搭建(Windows 10)

    目前前端开发正处于快速发展阶段,接触angular时,Angular 2刚刚发布,现在第五版也已经发布。由于刚开始没有系统的学习,导致工作中,经常捉襟见肘。现在把自己在工作中踩过的…

    2018年9月5日
    3.9K
  • CSS卡片堆栈

    在浏览各种APP及网站,往往会发现很多酷炫的布局及样式。搜集一下,补充自己的技能库,借鉴学习一下。 HTML CSS

    2019年12月31日
    1.9K
  • 如何判断一个对象为数组

    使用 instanceof 操作符 原理 instanceof 的内部机制是通过判断对象的原型链中是不是能找到类型的 prototype。 使用 instanceof 判断一个对象…

    2020年7月3日
    1.0K
  • spring boot练习篇之用户登录系统【接入数据库】

    抛弃JSP,只做纯粹的前后端分离项目。 写在前面 学习基础知识是枯燥无味的,之所以会这样,多数是因为心不静,对于如何运用它,感到茫然。所以建议大家在学习Java基础知识的时候,一定…

    2021年5月28日
    1.1K
  • spring boot练习篇之用户登录系统【接口篇】

    写在前面 抛弃JSP,只做纯粹的前后端分离项目。 作为一个资深前端工作者,想要转JavaWeb开发,无论是书籍,还是网上视频、资料,竟然没有一篇能清楚明白地讲解怎样搭建一个前后端分…

    2021年5月25日
    1.5K
  • 函数防抖与函数节流

    函数防抖 定义 触发高频事件后 n 秒内函数只会执行一次,如果 n 秒内高频事件再次被触发,则重新计算时间;更直白一点就是:一个需要频繁触发的函数,在规定时间内,只让最后一次生效,…

    2020年7月17日
    1.3K