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

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
ZEROZERO
上一篇 2022年11月18日
下一篇 2022年11月23日

相关推荐

  • 曾被问及的一些关于VUE的面试题

    由于没有系统的专研过VUE,关于VUE的一些理论知识点,没有去挖心思记忆及理解,只是在实际工作中知道怎么去使用。所以曾在面试的过程中被人嫌弃过,这一直是小编的痛点,/(ㄒoㄒ)/~…

    2022年4月2日
    807
  • JavaScript 事件委托详解

    基本概念 事件委托,通俗地来讲,就是把一个元素响应事件(click、keydown……)的函数委托到另一个元素; 一般来讲,会把一个或者一组元素的事件委托到…

    2021年3月8日
    1.1K
  • 封装JDBC工具类,连接MySQL数据库

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

    2022年3月31日
    837
  • 函数防抖与函数节流

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

    2020年7月17日
    1.4K
  • Java自学之多线程编程

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

    2020年12月16日
    1.5K
  • Java自学之抽象类与接口

    面向对象程序设计中,类继承的主要作用的扩充已有类的功能。子类可以根据自己的需要选择是否要覆写父类中的方法,所以一个设计完善的父类是无法对子类做出任何强制性的覆写约定。为了解决这样的…

    2020年12月7日
    1.2K
  • 前端遍历树形数据,返回满足条件的树形数据

    在一次做手机端小程序项目中,有一个机构表单项,需要在页面展示是树形层级结构,但是后端开发人员返回的数据却是一维数组,而且还要在前端做过滤筛选功能。但是在使用的手机端组件库中,却没有…

    2022年11月8日
    403
  • Webpack入门,模块打包原理分析

    面对工程中成百上千个模块,Webpack究竟是如何将它们有序地组织在一起,并按照开发者预想的顺序运行在浏览器上的呢?本篇文章将通过一个简单的示例。分析一下Webpack模块打包的原…

    2022年11月14日
    715
  • vue3.0项目如何配置路径别名

    vue更新到3.0以后,在项目中已经深度集成了webpack,使用vue create命令新建项目之后,已经没有webpack配置文件了,这对于像小编这样没有系统学习过前端的同学来…

    2020年8月22日
    4.0K
  • JavaScript基础知识八问

    JavaScript是前端开发中非常重要的一门语言,浏览器是他主要运行的地方。JavaScript是一个非常有意思的语言,但是他有很多一些概念,大家经常都会忽略。比如说,原型,闭包…

    2020年12月30日
    969