webpack中的loader

在这里插入图片描述

loader 是什么玩意儿?

loaderwebpack 能够去处理那些非 JavaScript 文件(webpack 自身只理解 JavaScript)。loader 可以将所有类型的文件转换为 webpack 能够处理的有效模块,然后你就可以利用 webpack 的打包能力,对它们进行处理

本质上,webpack loader 将所有类型的文件,转换为应用程序的依赖图(和最终的 bundle)可以直接引用的模块

注意,loader 能够 import 导入任何类型的模块(例如 .css 文件),这是 webpack 特有的功能,其他打包程序或任务执行器的可能并不支持。我们认为这种语言扩展是有很必要的,因为这可以使开发人员创建出更准确的依赖关系图。

在更高层面,在 webpack 的配置中 loader 有两个目标:

  • test 属性,用于标识出应该被对应的 loader 进行转换的某个或某些文件
  • use 属性,表示进行转换时,应该使用哪个 loader
// webpack.config.js
const path = require("path");

const config = {
  output: {
    filename: "my-first-webpack.bundle.js",
  },
  module: {
    rules: [{ test: /\.txt$/, use: "raw-loader" }],
  },
};

module.exports = config;

以上配置中,对一个单独的 module 对象定义了 rules 属性,里面包含两个必须属性:testuse这告诉 webpack 编译器(compiler) 如下信息:

“嘿,webpack 编译器,当你碰到「在 require()/import 语句中被解析为 ‘.txt’ 的路径」时,在你对它打包之前,先使用 raw-loader 转换一下。”

总结: 因为webpack本身只能编译js文件,loader 就是帮助 webpack 将不同类型的文件转换为 webpack 可识别的模块 例如:less sass css png等文件

常用 loader

样式

  • style-loader 将样式模块导出的内容以往 <head> 中注入多个 <style> 的形式,添加到 DOM 中
  • css-loader 加载 CSS 文件并解析 @import 的 CSS 文件,将 url() 处理成 require() 请求,最终返回 CSS 代码
  • less-loader 加载并编译 LESS 文件
  • sass-loader 加载并编译 SASS/SCSS 文件
  • postcss-loader 使用 PostCSS 加载并转换 CSS/SSS 文件
  • stylus-loader 加载并编译 Stylus 文件

语法转换

  • babel-loader 使用 Babel 加载 ES2015+ 代码并将其转换为 ES5
  • ts-loader 像加载 JavaScript 一样加载 TypeScript 2.0+

文件

  • url-loader与 file-loader 类似,但当文件 size 小于设置的 limit 值,会返回 data URL
  • file-loader 将文件保存至输出文件夹中并返回 URL (默认是是绝对路径,可以 outputPath 和 publicPath 通过配置成相对路径)

loader 的执行顺序

1. 分类

  • pre: 前置 loader
  • normal: 普通 loader
  • inline: 内联 loader
  • post: 后置 loader

2. 执行顺序

  • 4 类 loader 的执行优级为:pre > normal > inline > post
  • 相同优先级的 loader 执行顺序为:从右到左,从下到上

例如:

   // 此时loader执行顺序:loader1 - loader2 - loader3
module: {
  rules: [
    {
      enforce: "pre",
      test: /\.js$/,
      loader: "loader1",
    },
    {
      // 没有enforce就是normal
      test: /\.js$/,
      loader: "loader2",
    },
    {
      enforce: "post",
      test: /\.js$/,
      loader: "loader3",
    },
  ],
},

3.使用 loader 的方式

  • 配置方式:在 webpack.config.js 文件中指定 loader。(pre、normal、post loader)
  • 内联方式:在每个 import 语句中显式指定 loader。(inline loader)

4.inline loader

用法:import Styles from 'style-loader!css-loader?modules!./styles.css';

含义:

  • 使用 css-loader 和 style-loader 处理 styles.css 文件
  • 通过 ! 将资源中的 loader 分开

inline loader 可以通过添加不同前缀,跳过其他类型 loader

  • ! 跳过 normal loader

import Styles from '!style-loader!css-loader?modules!./styles.css';

  • -! 跳过 pre 和 normal loader

import Styles from '-!style-loader!css-loader?modules!./styles.css';

  • !!跳过 pre、 normal 和 post loader

import Styles from '!!style-loader!css-loader?modules!./styles.css';

实现一个 loader

1.loader 是一个函数,接收文件内容并返回文件内容出去

定义一个 test-laoder

//test-laoder.js
/*
   laoder就是一个函数
   当webpack解析资源时,会调用相应的loader去处理
   loader接收到文件内容作为参数,返回出去 
   content 文件内容
   map sourceMap
   meta 别的loader传递过来的数据
*/
module.exports = function (content, map, meta) {
  console.log("content", content);
  return content;
};

webpack.config.js中引入定义的 test-loader

//webpack.config.js
const path = require("path");
const HtmlWebpackPlugin = require("html-webpack-plugin");
module.exports = {
  entry: "./src/main.js",
  output: {
    filename: "js/[name].js",
    path: path.resolve(__dirname, "./dist"),
  },
  module: {
    rules: [
      {
        test: /\.js$/, //处理js的loader
        loader: "./loaders/test-loader.js", //调用对应的js
      },
    ],
  },
  plugins: [
    new HtmlWebpackPlugin({
      template: path.resolve(__dirname, "public/index.html"),
    }),
  ],
  mode: "development",
};
// main.js
console.log("hello main");

运行npx webpack 终端会输出 hello main

webpack 打包的时候会通过入口文件找到所有的依赖,对依赖文件一个个进行编译,编译的时候就会加载 loader 的配置,并且将要处理的文件作为参数传到函数中

1.同步 loader

//同步loader
// 写法一
module.exports = function (content) {
  return content;
};

// 写法二
module.exports = function (content, map, meta) {
  /*
      this.callback的参数
      1.err代表是否有错误
      2.content 处理后的内容
      3.source-map 继续传递source-map
      4.meta给下一个loader传递参数
   */
  //   同步loader中不能进行异步操作
  this.callback(null, content, map, meta);
};

2.异步 loader

异步 loader 会等待当前异步任务执行完再执行下一个 laoder

//异步loader
module.exports = function (content, map, meta) {
  //调用async方法返回callback
  const callback = this.async();

  setTimeout(() => {
    console.log("test2");
    //异步任务作为后调用callback
    callback(null, content, map, meta);
  }, 1000);
};

3.raw loader

raw loader 需要在exports对象中添加raw属性为true

//raw loaders接收到的content是Buffer数据
module.exports = function (content, map, meta) {
  console.log("content", content); //<Buffer 63 6f 6e 73 6f 6c 65 2e 6c 6f 67 28 27 68 65 6c 6c 6f 20 6d 61 69 6e 27 29>
  return content;
};
module.exports.raw = true; // 开启 Raw Loader

4.Pitching Loader

webpack 会先从左到右执行 loader 链中的每个 loader 上的 pitch 方法(如果有),然后再从右到左执行 loader 链中的每个 loader 上的普通 loader 方法,在这个过程中如果任何 pitch 有返回值,则 loader 链被阻断。webpack 会跳过后面所有的的 pitchloader,直接进入上一个 loader

module.exports = function (content) {
  return content;
};
module.exports.pitch = function (remainingRequest, precedingRequest, data) {
  console.log("do somethings");
};

loader API

方法名含义用法
this.async异步回调 loader。返回this.callback const callback = this.async()
this.callback可以同步或者异步调用的并返回多个结果的函数this.callback(err, content, sourceMap?, meta?)
this.getOptions(schema)获取 loader 的 optionsthis.getOptions(schema)
this.emitFile产生一个文件this.emitFile(name, content, sourceMap)
this.utils.contextify返回一个相对路径this.utils.contextify(context, request)
this.utils.absolutify返回一个绝对路径this.utils.absolutify(context, request)

更多文档,请查阅webpack 官方 loader api 文档

手写 babel-loader

作用:编译 js 代码,将 ES6+语法编译成 ES5-语法

  • 下载依赖
npm i @babel/core @babel/preset-env -D
  • babel-loader/index.js
const babel = require("@babel/core");
const schema = require("./schema.json");

module.exports = function (content, map, meta) {
  const callback = this.async();
  const options = this.getOptions(schema);

  //使用babel对代码进行装换
  // babel.transform(代码:字符串,选项?:对象,回调:函数)
  // 转换传入的code. 使用生成的代码、源映射和 AST 调用带有对象的回调
  babel.transform(content, options, function (err, result) {
    if (err) callback(err);
    else callback(null, result.code);
  });
};
  • schema.json
{
  "type": "object",
  "properties": {
    "presets": {
      "type": "array"
    }
  },
  "additionalProperties": true
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值