style-loader为什么要使用pitch方法原理解析

目录
  • loader
  • pitch
  • 总结

loader

loader是一个函数,loader模块要默认导出该函数,同时这个函数上可以有pitch方法,webpack会执行这个pitch方法,pitch方法会影响webpack后续行为。

loader的作用是将源文件转化为可以执行的js模块,webpack会检查loader返回的这个模块是否是正确的,符合js模块化规范,如果有错误会终止打包。例如我定义了一个test.js模块,其默认导出一个函数:

test.js

module.exports = function (a, b) {
    return a+b;
}

然后定义一个test-loader,让其只会匹配test.js

module.exports = function (content) {
    return `var a = {name: 'wjl'}; module.exports = a;`
}

test-loader返回了一段新的代码,默认导出一个对象,在index.js中我们导入test.js模块,尝试输出对象上的name属性,然后通过webpack打包:

const a = require('./test.js')
console.log(a.name)

打包结果为main.js,运行main.js可以正确得到输出。这说明webpack执行了var a = {name: 'wjl'}; module.exports = a;test.js模块最终导出的内容为a

当把test-loader的导出语句删除,改为以下内容时,能够正确通过webpack检查,但是index.js中不能访问导出对象了:

test-loader.js

module.exports = function (content) {
    // return `var a = {name: 'wjl'}; console.log(123); module.exports = a;`
    return `var a = {name: 'wjl'}; console.log(123);`
}

index.js

const a = require('./test.js')
console.log(a, a.name)

运行导出文件main.js得到

这是由于这个模块没有导出内容(对象上没有属性),test.js的模块代码会在运行时执行(输出123,cjs的模块需要执行完模块内容才能得到导出对象)。

(如果loader导出的内容中含有importrequire等语句,webpack会再次进行相关内容的导入,这方面的知识目前暂时不分析)

loader总结loader的作用是将准备导入的模块里面的内容转换成可以正常执行的js模块代码,转换后的内容会在运行时执行,以得到模块的导出内容或执行其他副作用代码。

pitch

为什么需要使用pitch?我们以css-loaderstyle-loader作为分析。

在只使用css-loader的情况下,假设我们有两个文件:index.cssindex.jsindex.css定义了一些样式,index.js导入了index.css

index.css

body  {
    font-size: 16px;
    color: red;
}

index.js

const style = require('./index.css')
console.log(style);

运行结果为:

css-loader将目标样式文件转换成一个js对象并导出了该对象,默认属性上有index.css文件的信息。

需要注意的是,这个对象是执行完css-loader转换的模块内容后得到的!我们先定义一个普通的my-style-loader根据调用顺序拿到css-loader的返回值:

my-style-loader:

module.exports = function (source) {
  console.log('*******************');
  console.log(source);
  console.log('*******************');
  return source;
}

css-loaderindex.css模块转换为以下内容:

// Imports
import ___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___ from "./node_modules/.pnpm/registry.npmmirror.com+css-loader@6.7.3_webpack@5.75.0/node_modules/css-loader/dist/runtime/noSourceMaps.js";
import ___CSS_LOADER_API_IMPORT___ from "./node_modules/.pnpm/registry.npmmirror.com+css-loader@6.7.3_webpack@5.75.0/node_modules/css-loader/dist/runtime/api.js";
var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(___CSS_LOADER_API_NO_SOURCEMAP_IMPORT___);
// Module
___CSS_LOADER_EXPORT___.push([module.id, "body  {\r\n    font-size: 16px;\r\n    color: red;\r\n}", ""]);
// Exports
export default ___CSS_LOADER_EXPORT___;
​

也就是说,index.css里面的内容,还是要执行完index.css模块才能得到

使用style-loader的目的是往document中插入style标签,如果style-loader是一个普通loader的话,它需要执行css-loader返回的模块才能得到css样式,当然可以解析css-loader返回的模块内容,然后得到样式,然后返回创建style标签的相关语句,但是这样工作量太大了。而返回的模块中有import相关的语句时,webpack还会加载那些import的内容,但是例如./node_modules/.pnpm/registry.npmmirror.com+css-loader@6.7.3_webpack@5.75.0/node_modules/css-loader/dist/runtime/api.js是会被webpack最终打包生成的模块,在nodejs环境中是无法得到的。

打包产物:

一个模块加载(import '!!xxxx-loader!./index.css')被webpack打包之后会添加到module map里面,键就是请求路径。

style-loader的思路就是,得到css-loader的模块内容,然后再将模块内容插入到style标签中,再将style标签插入文档中。

为了得到css-loader处理后的内容(需要能被执行),style-loader构造了一个新的require语句,即:

require(`${loaderUtils.stringifyRequest(this, '!!' + remainingRequest)}`)
// !!./node_modules/.pnpm/registry.npmmirror.com+css-loader@6.7.3_webpack@5.75.0/node_modules/css-loader/dist/cjs.js!./index.css

webpack发现返回的内容中有模块导入,然后使用路径中的loader去加载这个模块,并将其保存在内存中(多个文件引用同一个模块,目标模块只会被处理一次)。

总结

loaderpicher本质上都是改变目标文件的内容,让它变成符合js语法的代码,如果返回的内容有不存在的导入,则会再次执行导入。

webpack每个loader处理的结果都会生成单独的模块,但是在loader函数中,它无法之前使用了哪些loader,也无法知道已生成模块的名字,因此style-loader无法在loader函数中导入已经生成的模块。

pitch阶段可以获取到之后的loader顺序,实现起来也更加方便。

以上就是style-loader为什么要使用pitch方法原理解析的详细内容,更多关于style-loader使用pitch方法的资料请关注我们其它相关文章!

(0)

相关推荐

  • webpack的pitching loader详解

    webpack中关于pitching loader的文档比较不清楚: The loaders are called from right to left. But in some cases loaders do not care about the results of the previous loader or the resource. They only care for metadata. The pitch method on the loaders is called from

  • vue安装node-sass和sass-loader报错问题的解决办法

    目录 可行版本(针对 node 16+ 版本) 问题描述 解决方法 补充知识:解决启动VUE项目时报node-sass不能运行问题 总结 可行版本(针对 node 16+ 版本) 不想浪费时间看的,可直接去尝试 npm install node-sass@6.0.1 -D npm install sass-loader@10.2.0 -D 问题描述 问题描述:在进行一个vue项目练习时需要导入node-sass.sass-loader这两个依赖,书本提供代码是npm install sass-l

  • 一文详解webpack中loader与plugin的区别

    目录 一.Loader 1.loader的作用: 2.loader的工作原理: 3. Loader 执行顺序 4.如何开发一个loader 二.Plugin 1.plugin解决其他的更多的自动化打包工作 2.自定义插件 常见的Loader和Plugin loader: plugin: 一.Loader 1.loader的作用: webpack 只能直接处理 javascript 格式的代码.任何非 js 文件都必须被预先处理转换为 js 代码,才可以参与打包.loader(加载器)就是这样一个

  • 使用webpack配置react-hot-loader热加载局部更新

    目录 webpack配置react-hot-loader热加载局部更新 步骤1 步骤2 步骤3 步骤4 步骤5 步骤6 react-hot-loader热加载不生效的可能问题 总结 webpack配置react-hot-loader热加载局部更新 有人会问 webpack-dev-server 已经是热加载了,能做到只要代码修改了页面也自动更新了,为什么在 react 项目还要安装 react-hot-loader 呢? 其实这两者的更新是有区别的,webpack-dev-server 的热加载

  • vue2.0安装style/css loader的方法

    项目需要引用额外的ui组件库,就需要安装style-loader和css-loader 安装style-loader  (css-loader默认有) npm install style-loader -D 然后,打开模板build--webpack.base.conf.js( 根据初始化模板不同也可能是 build 下面的webpack.base.conf.js ),新增一个json,注意style!css顺序不能颠倒(!表示连接) 补充: 2.0 以后应该写成 style-loader!cs

  • style-loader为什么要使用pitch方法原理解析

    目录 loader pitch 总结 loader loader是一个函数,loader模块要默认导出该函数,同时这个函数上可以有pitch方法,webpack会执行这个pitch方法,pitch方法会影响webpack后续行为. loader的作用是将源文件转化为可以执行的js模块,webpack会检查loader返回的这个模块是否是正确的,符合js模块化规范,如果有错误会终止打包.例如我定义了一个test.js模块,其默认导出一个函数: test.js module.exports = fu

  • python @propert装饰器使用方法原理解析

    这篇文章主要介绍了python @propert装饰器使用方法原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 首先,@propert的作用是把类中的方法『变成』了属性,方便通过实例访问.propert可以有两种用法:可以把一个方法变成只读属性:可以对一些属性进行过滤. 想象这样一个场景,在实例化一个类之后,需要对类的一个属性进行赋值,这时候是没有对属性属性被赋予的值进行判断的,如果属性被赋予了一个不合适的值,那么代码在后面执行的时候就会

  • python线程join方法原理解析

    这篇文章主要介绍了python线程join方法原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 几个事实 1 python 默认参数创建线程后,不管主线程是否执行完毕,都会等待子线程执行完毕才一起退出,有无join结果一样 2 如果创建线程,并且设置了daemon为true,即thread.setDaemon(True), 则主线程执行完毕后自动退出,不会等待子线程的执行结果.而且随着主线程退出,子线程也消亡. 3 join方法的作用是阻

  • Java多线程start()方法原理解析

    1.为什么启动线程不用run()方法而是使用start()方法 run()方法只是一个类中的普通方法,调用run方法跟调用普通方法一样 而start()是创建线程等一系列工作,然后自己调用run里面的任务内容. 验证代码: /** * @data 2019/11/8 - 下午10:29 * 描述:run()和start() */ public class StartAndRunMethod { public static void main(String[] args) { Runnable r

  • Java Object toString方法原理解析

    在Java中,所有的对象都是继承自Object,自然继承了toString方法,在当使用System,out.println()里面为一个对象的引用时,自动调用toString方法将对象打印出来.如果重写了tostring方法则调用重写的toString 方法. 先看下面一段代码 public class ToStringTest { static int i = 1; public static void main(String[] args) { System.out.println("lo

  • SpringMVC注解@RequestParam方法原理解析

    一.作用 作用在方法传递的参数前,用于接收所传参数 例如:http://localhost:8081/selectStudentById?id=01 接收问号后面的参数值(允许多个参数) 二.注解内部的四个属性 1.name 指定传入的参数名称,其后面跟的参数名称一定要与前端传入的参数名称一致 2.value 指定传入的参数名称,其后面跟的参数名称一定要与前端传入的参数名称一致 3.requred 指定参数是否是必传参数,如果不指定,默认为true 4.defaultValue 指定参数的默认值

  • Python startswith()和endswith() 方法原理解析

    startswith()方法 Python startswith() 方法用于检查字符串是否是以指定子字符串开头 如果是则返回 True,否则返回 False.如果参数 beg 和 end 指定值,则在指定范围内检查. str.startswith(str, beg=0,end=len(string)); 参数 str --检测的字符串. strbeg --可选参数用于设置字符串检测的起始位置. strend --可选参数用于设置字符串检测的结束位置. 返回值 如果检测到字符串则返回True,否

  • JAVA判断空值方法原理解析

    Java空字符串与null的区别: 1.类型 null表示的是一个对象的值,而并不是一个字符串.例如声明一个对象的引用,String a = null ; ""表示的是一个空字符串,也就是说它的长度为0.例如声明一个字符串String str = "" ; 2.内存分配 String str = null ; 表示声明一个字符串对象的引用,但指向为null,也就是说还没有指向任何的内存空间: String str = ""; 表示声明一个字符串类

  • Java lastIndexOf类使用方法原理解析

    lastIndexOf 在字符串中根据搜索条件来返回其在字符串中的位置,空格也计数,如果字符串中没有这样的字符,返回-1. 其方法主要有4个: lastIndexOf(int ch) ,返回指定字符在此字符串中最后一次出现处的索引. lastIndexOf(int ch , int fromIndex) ,返回指定字符在此字符串中最后一次出现处的索引,从指定的索引处开始进行反向搜索. lastIndexOf(String str),返回指定子字符串在此字符串中最右边出现处的索引. lastInd

  • Java Method类及invoke方法原理解析

    在说Method和invoke的使用之前我们来看一个小例子, 如果看懂了那就ok了 public class MethodInvoke { class Animal { public void print() { System.out.println("Animal.print()"); } } class Cat extends Animal { @Override public void print() { System.out.println("Cat.print()&

随机推荐