Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

9种loader

1. babel-loader

  • 作用

    • 对代码进行预处理,常用于将 es6 语法 转换为 es5 语法,向下兼容老旧浏览器
  • 安装

    npm i -D babel-loader @babel/core @babel/preset-env @babel/preset-react @babel/preset-typescript
    
    • @babel/core

      • 核心底层依赖包
    • @babel/preset-env

      • 提供了 ES6 转 ES5 的语法规则和垫片
      • 包含了 babel-preset-latest 的功能,并对其进行增强
    • @babel/preset-react

      • 提供了处理 react jsx 模板文件的功能
    • @babel/preset-typescript

      • 提供了处理 typescript 文件的功能,就不需要额外的更慢的ts-loader,要求 babel 版本在 7+,会直接移除 TS 转为 JS,编译速度飞快
      • 这种方法不需要安装 typescript 包,但需要根目录下新建tsconfig.json文件配置
      • 由于没安装 typescript 包,所以这种方法没有类型检查功能,可选如下方案补充
        • 额外安装并配置脚本"type-check": "tsc --watch",手动检查
        • 使用 ESLint,用@typescript-eslint 配置 ESLint 来自动检查
        • 使用 Vscode 带有的自动检查
  • 在 json 中配置

    module: {
      rules: [
        {
          test: /\.(m?js|jsx|ts|tsx)$/,
          exclude: /node_modules/,
          use: {
            loader: "babel-loader",
            options: {
              cacheDirectory: true,
              presets: [
                ["@babel/preset-env", { modules: false }],
                "@babel/preset-react",
                "@babel/preset-typescript",
              ],
            },
          },
        },
      ];
    }
    
    • test 表示只对.js结尾的文件应用
    • exclude 排除对 node_modules 目录下的应用
    • use 可以同时指定 要使用的 loader 和 配置项 options
      • 也可以直接用loader: "babel-loader"替代,这样配置项就要写到单独的根目录.babelrc文件中:
        {
            "presets": [
                "@babel/preset-env",
                "@babel/preset-typescript"
            ]
        }
        
    • 配置项
      • cacheDirectory 可以启用缓存机制,防止对未改变过的模块二次编译
      • 这里@babel/preset-env默认会将 ES6 转为 CommonJS,导致 tree-shaking 失效,所以需要配置modules: false禁用这个模块依赖解析
  • 在 chain 中配置

    config.module
      .rule("babel")
      .test(/\.(m?js|jsx|ts|tsx)$/)
      .exclude.add(/node_modules/)
      .end()
      .use("babel-loader")
      .loader("babel-loader")
      .options({
        presets: [
          "@babel/preset-env",
          "@babel/preset-react",
          "@babel/preset-typescript",
        ],
      });
    

2. css-loader

  • css-loader

    • 作用:
      • 解析 js 内使用的import './style.css'@import './style.css',就像 js 解析 import 和 require 一样
  • style-loader【不建议使用】

    • 作用: 把上面解析好的 css 直接插入到 DOM 中,即在 header 处用<style></style>嵌入式引入
    • 如果想保留独立的 css 文件,就不要用这个 loader,而是换成 mini-css-extract-plugin 去处理,就能生成 link 插入到 DOM 中
  • 安装

    npm i style-loader css-loader -D
    
  • 在 json 中配置

    module: {
        rules: [
            {
                test: /\.css$/,
                use: ["style-loader", "css-loader"]
            },
        ],
    },
    
  • 在 chain 中配置

    config.module
      .rule("css")
      .test(/\.css$/)
      .use("style-loader")
      .loader("style-loader")
      .end()
      .use("css-loader")
      .loader("css-loader")
      .end();
    

CSS modules 支持

  • 可以通过 options 开启 CSS modules 支持,实现作用域隔离

    {
        loader: "css-loader",
        options: {
            modules: true,
            localIdentName: "[name]__[local]__[hash:base64:5]"
        }
    }
    
    • 这里 localIdentName 的作用,就是指定生成的 class 的名字,由文件名、类名、5 位哈希拼成,比如如下用法

      //style.css
      .title {
          color: purple;
      }
      
      //app.js
      import styles from "./style.css";
      document.write(`<h1 class="${styles.title}">Hey</h1>`)
      
      • 会生成如下 class 名字
        .style_title_1CFy6
        

3. postcss-loader

  • 作用

    • 使用 PostCSS 对 css 做处理和优化
  • 安装

    npm i postcss-loader postcss -D
    
    • postcss 最新版本需要 webpack v5,如果是 v4,需要指定 postcss 版本为@4
    • 需要在根目录下新建配置文件postcss.config.js,添加各种工具的配置,比如autoprefixerstylelintpostcss-cssnext
  • 在 json 中配置

    module: {
        rules: [
            {
                test: /\.css$/,
                use: ["style-loader", "css-loader", "postcss-loader"]
            },
        ],
    },
    
  • 在 chain 中配置

    config.module
      .rule("css")
      .test(/\.css$/)
      .use("style-loader")
      .loader("style-loader")
      .end()
      .use("css-loader")
      .loader("css-loader")
      .end()
      .use("postcss-loader")
      .loader("postcss-loader")
      .end();
    

4. less-loader

  • 作用

    • 将 less 编译为 css,需要安装 less 包
  • 安装

    npm i less less-loader -D
    
  • 在 json 中配置

    module: {
        rules: [
            {
                test: /\.less/,
                use: ["style-loader", "css-loader", "less-loader"]
            },
        ],
    },
    
  • 在 chain 中配置

    config.module
      .rule("css")
      .test(/\.css$/)
      .use("style-loader")
      .loader("style-loader")
      .end()
      .use("css-loader")
      .loader("css-loader")
      .end()
      .use("less-loader")
      .loader("less-loader")
      .end();
    

。5 sass-loader

  • 作用

    • 将 Sass/SCSS 编译为 css,需要安装 sass 包
  • 安装

    npm i sass sass-loader -D
    
  • 在 json 中配置

    module: {
        rules: [
            {
                test: /\.s[ac]ss/,
                use: ["style-loader", "css-loader", "sass-loader"]
            },
        ],
    },
    
  • 在 chain 中配置

    config.module
      .rule("css")
      .test(/\.css$/)
      .use("style-loader")
      .loader("style-loader")
      .end()
      .use("css-loader")
      .loader("css-loader")
      .end()
      .use("sass-loader")
      .loader("sass-loader")
      .end();
    

5.file-loader

  • 作用

    • 解析代码中的 url 引入,并将 url 资源(比如图片)拷贝到相应的打包路径
    • 同时在代码内修改为这个路径,使之指向正确的文件
    • 还能生成版本 hash 值到文件名,从而获得更好的缓存
  • 注意

    • 一般来说,只建议对字体文件使用这个 loader
    • webpack 5 内置了另一种解决方案,可以做替换
      {
          test: /(\.(eot|ttf|woff|woff2|otf)|font)$/,
          type: 'asset/resource'
      }
      
    • 而对于图片等资源,有更好的 url-loader 可以使用,且 url-loader 本身就封装了 file-loader 的功能
  • 安装

    npm i file-loader -D
    
  • 在 json 中配置

    module: {
        rules: [
            {
                test: /(\.(eot|ttf|woff|woff2|otf)|font)$/,
                use: [
                    {
                        loader: "file-loader",
                        options: {
                            outputPath: "fonts/"
                        }
                    }
                ]
            },
        ],
    },
    
  • 在 chain 中配置

    config.module
      .rule("font")
      .test(/(\.(eot|ttf|woff|woff2|otf)|font)$/)
      .use("file-loader")
      .loader("file-loader")
      .options({
        outputPath: "fonts/",
      })
      .end();
    

6. url-loader

  • 作用

    • 参考 file-loader,只是多出下面的特性
    • 可以按照 limit 参数来划分
      • 小于 limit 的文件,会转为 DataURL base64 内容 inline 内嵌到代码中,避免请求 http 数过多
      • 大于 limit 的文件,会调用 file-loader 进行处理
  • 注意

    • 不能对字体文件使用这个 loader,因为字体文件转成 base64 后浏览器无法识别
    • webpack 5 内置了小图片的 inline 方案,但不建议做替换
      {
          test: /\.svg$/,
          type: 'asset/inline'
      }
      
  • 安装

    npm i url-loader -D
    
  • 在 json 中配置

    module: {
        rules: [
            {
                test: /\.(png|jpe?g|gif|svg)(\?.*)?$/,
                use: [
                    {
                        loader: "url-loader",
                        options: {
                            limit: 10240,
                            name: utils.assetsPath("img/[name].[hash:8].[ext]")
                        }
                    }
                ]
            },
        ],
    },
    
  • 在 chain 中配置

    config.module
      .rule("url")
      .test(/\.(png|jpe?g|gif|svg)(\?.*)?$/)
      .use("url-loader")
      .loader("url-loader")
      .options({
        limit: 10000,
        name: utils.assetsPath("img/[name].[hash:8].[ext]"),
      })
      .end();
    

7.html-loader

  • 作用

    • 支持导入 html 类型的文件,并生成为字符串
      import html_string from "./xxx.html";
      document.write(html_string);
      
  • 安装

    npm i html-loader -D
    
  • 在 json 中配置

    module: {
        rules: [
            {
                test: /\.html$/,
                use: ["html-loader"]
            },
        ],
    },
    
  • 在 chain 中配置

    config.module
      .rule("html")
      .test(/\.html$/)
      .use("html-loader")
      .loader("html-loader")
      .end();
    

8.js-conditional-compile-loader

  • 作用

    • 支持条件编译
  • 安装

    npm i js-conditional-compile-loader -D
    
  • 在 json 中配置

    module: {
        rules: [
            {
                test: /\.(m?js|jsx|ts|tsx)$/,
                use: [{
                    loader: "js-conditional-compile-loader",
                    options: {
                        isMainland: globalConfig.isMainland,
                        isOversea: !globalConfig.isMainland
                    }
                }]
            },
        ],
    },
    
    • 可以用 isMainland 和 isOversea 作为布尔标志,去决定哪些内容应该被加入到生产编译
  • 在 chain 中配置

    config.module
      .rule("conditional")
      .test(/\.tsx$/)
      .use("js-conditional-compile-loader")
      .loader("js-conditional-compile-loader")
      .options({
        isMainland: globalConfig.isMainland,
        isOversea: !globalConfig.isMainland,
      })
      .end();
    
  • 使用案例

    /* IFTRUE_isMainland const logo = logoMainLand FITRUE_isMainland */
    
    /* IFTRUE_isOversea const logo = overseaLogo  FITRUE_isOversea */
    
    • 如果 isMainland 为 true,那上面那一条会在生产环境被加入
    • 如果 isOversea 为 true,那下面那一条会在生产环境被加入
    • 为了防止开发环境没有 logo 变量的定义,需要加入如下代码
      /* IFDEBUG */
      const logo = globalConfig.isMainland ? logoMainLand : logoOversea;
      /* FIDEBUG */
      
      • 只有在开发环境才会原样使用这个代码,否则就移除

9.自定义 loader

实现一个 loader,在每个 js 文件最开始加上 开启严格模式 的一行代码

  • 创建一个新目录

    touch force-strict-loader && cd force-strict-loader
    
  • 初始化

    npm init -y
    
  • 安装依赖,用来获取外面传入的 options

    npm i loader-utils -D
    
  • 创建 index.js 文件,并填入如下内容

    let loaderUtils = require("loader-utils");
    module.exports = function (content) {
      if (this.cacheable) {
        this.cacheable();
      }
    
      const options = loaderUtils.getOptions(this) || {};
      console.log("options", options);
    
      var useStrictPrefix = "'use strict';\n\n";
      return useStrictPrefix + content;
    };
    
    • cacheable 可以启用缓存,输入没变化时无需重复转换
  • 在工程中安装这个 loader

    npm i <path-to-loader>/force-strict-loader -D
    
    • 会在 node_modules 目录内创建一个软链接
  • 使用

    rules: [
      {
        test: /\.js$/,
        use: "force-strict-loader",
      },
    ];