重拾 Webpack(中卷)

之前在上卷中,我主要梳理了 webpack 入门知识,在此我将更接近于工程中的知识实际梳理一遍

本文持续更新中…
前置知识:重拾 Webpack(上卷)


预处理器(loader)

loader 概述

  1. 每一个 loader 本质上都是一个函数,在 webpack4 之前,loader 函数的输入输出都必须为字符串,但在 webpack4 之后,loader 也同时支持 抽象语法树(AST) 的传递,以此来减少代码的重复解析
    用公式可以表示为:output = loader(input)
  2. 在此,我们来看一下 loader 的源码结构,以此阐释 loader 是如何工作的:
     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
         };
     };
    从代码中可以看出,loader 本身就是一个函数,将函数中接收到的内容进行转换,然后返回转换后的结果
    (可能包含 sourcr map 和 AST 对象

loader 的配置

  1. webpack 只认识 JavaScript,对于其他类型的资源,比如 CSS、图片等等,必须预先定义一个或多个 loader 来进行转译,经过 loader 输出为 webpack 能够接受的形式再继续进行
    因此,loader 做的实际上是一个预处理的工作
  2. loader 的引入:
    • 假设在我们的目录中,有以下两种文件:
      |-app.js
      |-style.css
    • 我们要做的是将 css 文件引入到 js 文件中使用,那么跟着我开始吧!
    • 安装第三方模块
      • webpack 本身并不含有任何的 loader,而所有的 loader 都是第三方 npm 模块,所以我们必须先安装它
        npm install --save-dev css-loader
    • 引入到工程中
      • webpack.config.js 中配置:
        module.exports = {
          // ...
          module: {
                  rules: [{
                      test: /\.css$/,
                      use: ['css-loader'],
                  }],
              },
        };
    • 配置项的说明:
      • module.rules 代表着模块的处理规则,每条规则都包含着许多配置项,这里我们只用最重要的两项:test 和 use
      • test 接受一个正则表达式或者元素为正则表达式的数组,如果匹配这条正则表达式,那么就会使用与之对应的规则,比如这里的 /\.css$/ 用来匹配所有的 .css 结尾的文件
      • use 接受一个数组,数组中包含着对应 test 会使用到的所有 loader,比如这里的 css 文件会使用到 css-loader ,如果只有一个 loader,那么也可以省略数组,只写成字符串
  3. 链式 loader:
    • 上述的案例是不成功的,因为我们还差一样东西:style-loader
    • 每一个 loader 的功能都是独特而局限的,也就是说,一种类型的模块可以需要多种 loader 共同完成,在处理 css 文件时同样如此,需要 style-loadercss-loader 共同完成
    • 安装
      npm install --save-dev style-loader
    • 添加配置
      // webpack.config.js
      module.exports = {
        // ...
        module: {
                rules: [{
                    test: /\.css$/,
                    use: ['style-loader', 'css-loader'],
                }],
            },
      };
      在 webpack 打包时,是按照数组从后往前的顺序将资源交给 loader 处理的,因此要把最后生效的 style-loader 放在最前面
  4. exclude 与 include
    • 在项目中我们经常会用到 babel-loader 来处理 ES6+ 语言特性,将其编译为 ES5 来适应浏览器,但是对于 node_modules 中的 js 文件来说,很多都是已经编译为 ES5 的,因此没必要再使用 babel-loader 来进行额外的处理
    • exclude 与 include 就是用来排除规则的,他们可接收正则表达式或者字符串(字符串即文件的绝对路径),以及由他们组成的数组,如:
      rules: [{
            test: /\.css$/,
            use: ['style-loader', 'css-loader'],
            exclude: /node_modules/,
      }],
      • 这里的含义是:对于匹配到正则表达式的模块,若在 exclude 指定的目录中(此处为 node_modules 目录),则不会执行该 use 规则
    • 除了 exclude 之外,使用 include 配置也能达到相同的效果,如:
      rules: [{
            test: /\.css$/,
            use: ['style-loader', 'css-loader'],
            include: /src/,
      }],
      • 值得注意的是,include 的逻辑似乎与 exclude 是相反的,对于匹配到正则表达式的模块,若在 include 指定的目录中(此处为 src 目录),才执行该 use 规则
    • exclude 与 include 同时存在时,exclude 的优先级更高,如:
      rules: [{
            test: /\.css$/,
            use: ['style-loader', 'css-loader'],
            exclude: /node_modules/,
            include: /node_modules\/awesome/,
      }]
      • 此时,exclude 使得 node_modules 目录已经被排除了,虽然 include 之后想要让该 use 规则对 node_modules 中的某一个模块生效,也是无济于事的,因为 include 是无法覆盖 exclude 的
      • 要实现原本的需求,我们可以改为:
        rules: [{
              test; /\.css/,
              use: ['style-loader', 'css-loader'],
              // 用 exclude 排除 node_modules 中除了 foo 和 bar 以外的所有模块
              exclude: /node_modules\/(?!(foo|bar)\/).*/,
        }]
        这令人头疼的正则,哎,,Ծ^Ծ,,
      • 另外,由于 exclude 的优先级跟高,所以我们可以对 include 的子目录进行排除,如:
        rules: [{
              test; /\.css/,
              use: ['style-loader', 'css-loader'],
              exclude: /src\/lib/,
              include: /src/,
        }]
        此处的结果就是:该 use 规则只对 src 目录生效,同时排除 src 目录中的 lib 目录
    • 注:exclude 与 include 的配置项往往是必须考虑的,也是常加的,否则可能会拖慢整体的打包速度
  5. resource 与 issuer
    • resource 与 issuer 可以用于更加精确地确定模块规则的作用范围,如:
      // index.js
      import './style.css'
      在 webpack 中,被加载模块是 resource,而加载者是 issuer,在上面的例子中,resource 是 style.css,加载者是 index.js
    • 前面介绍的 test、exclude、include 在本质上就是对 resource 的配置,如果想要对 issuer 增加条件的话,需要额外地写配置,比如,我们只想让 /src/pages 目录下的 js 文件可以引用 css,本质想就是改变加载者的范围,配置如下:
      rules: [{
        test: /\.css$/,
        use: ['style-loader', 'css-loader'],
        exclude: /node_modules/,
        issuer: {
                test: /\.js$/,
                include: /src/pages/,
            },
      }],
      // 只有 /src/pages/ 下面的 js 文件引用 css 文件才能使此 use 规则生效
      • 事实上,上述代码的可读性较差,我们可以改为:
        rules: [{
              use: ['style-loader', 'css-loader'],
              resource: {
                      test: /\.css$/,
                      exclude: /node_modules/,
                  },
              issuer: {
                      test: /\.js$/,
                      exclude: /node_modules/,
                  },
        }],
        注:此风格和上面的代码风格无法并存的,只能选择一种风格配置
  6. enforce
    • webpack 中的 loader 按照执行顺序可分为:pre、inline、normal、post四种,之前我们直接定义的 loader 都属于 normal 类型,官方已不推荐 inline 形式,而 pre 和 post 形式则需我们使用 enforce 指定,如:
      rules: [{
            test: /\.css$/,
            enforce: 'pre',
            use: 'eslint-loader',
            // eslint-loader 的功能是对源代码进行质量检测,这种检测工作往往在其他 loader 之前执行
      }]
      这段代码的解释为:对于所有匹配正则表达式的模块,首先使用的 loader 规则就是 eslint-loader
    • 概述起来就是,enforce 可以强制指定 loader 的执行顺序
      • pre 能强制 loader 首先执行
      • post 能强制 loader 最后执行
  7. 常用 loader 介绍
    • loader 官方文档
    • 模板 loader:
      • html-loader : 将HTML文件导出编译为字符串,可供js识别的其中一个模块
      • pug-loader : 加载pug模板
      • jade-loader : 加载jade模板(是pug的前身,由于商标问题改名为pug)
      • ejs-loader : 加载ejs模板
      • handlebars-loader : 将Handlebars模板转移为HTML
    • 样式 loader:
      • css-loader : 解析css文件中代码
      • style-loader : 将css模块作为样式导出到DOM中
      • less-loader : 加载和转义less文件
      • sass-loader : 加载和转义sass/scss文件
      • postcss-loader : 使用postcss加载和转义css/sss文件
    • 脚本转换编译 loader:
      • script-loader : 在全局上下文中执行一次javascript文件,不需要解析
      • babel-loader : 加载ES6+ 代码后使用Babel转义为ES5后浏览器才能解析
      • typescript-loader : 加载Typescript脚本文件
      • coffee-loader : 加载Coffeescript脚本文件
    • JSON加载 loader:
      • json-loader : 加载json文件(默认包含)
      • json5-loader : 加载和转义JSON5文件
    • Files文件 loader:
      • raw-loader : 加载文件原始内容(utf-8格式)
      • url-loader : 多数用于加载图片资源,超过文件大小显示则返回data URL
      • file-loader : 将文件发送到输出的文件夹并返回URL(相对路径)
      • jshint-loader : 检查代码格式错误
    • 加载框架 loader:
      • vue-loader : 加载和转义vue组件
      • angualr2-template–loader : 加载和转义angular组件
      • react-hot-loader : 动态刷新和转义react组件中修改的部分,基于webpack-dev-server插件需先安装,然后在webpack.config.js中引用react-hot-loader

样式处理

正在更新中…

本作品采用《CC 协议》,转载必须注明作者和本文链接
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!