css-loader、style-loader和isomorphic-style-loader原理_css loader原理-程序员宅基地

技术标签: css-loader  style-loader  前端  isomorphic-style-loader  原理  

  本文讲解css-loader、style-loader和isomorphic-style-loader的实现原理,而不会讲解它们的具体用法,具体用法请参考其他文档。我是如何知道它们是这么实现的呢?我没有看它们的源代码,而是通过查看webpack打包后生成的代码。为了留下更深刻的印象,就写下了本文。

css-loader原理

  有个很奇怪的事情,在JS文件中竟然能够导入CSS文件(通过import或require)。这是怎么做到的呢?如果JS文件要想正常被执行,那JS文件中只能包括JS语法,这是毫无疑问的。所以可以推导出,CSS文件肯定被转换成JS文件了,这个就是css-loader做的事情了。
  那CSS文件被转换成什么样子了呢?总的来说,原CSS文件的内容被转换成了一个字符串。但这还不够,为撒?一个文件既然能够被导入,那自然需要导出。所以简单推导,css-loader可以将一个css文件转换成如下内容:

module.exports = "原css文件中的样式";

这样CSS文件就成了一个合理的JS文件了,而且可以被其他JS文件引用了。这是css-loader最基本的作用,其他的都是锦上添花,比如压缩、模块化等。
  关于css-loader最后就谈一下其中的模块化。模块化是什么意思呢?我们知道css中的类名、动画名等是不具有唯一性约束的,不同的css文件或库很可能造成类名等的冲突。为了不造成冲突,css-loader可以按照一定的规则将类名等转化成具有全局唯一性的名字。即使2个文件中都有叫root的类名,经css-loader转换后,它们的类名可以完全不同,这就是css的模块化。
  模块化以后,用户完全不知道被转换后的类名,这样就没法使用了。为了让用户知道类名,css-loader就需要对转换后的内容做些改变。css-loader实际转换后的内容等价于如下伪代码:

module.exports = {
	toString: () => “原css文件中的样式(类名被转换了,代码可能也被压缩过)”
	locals: {
		[原文件中写的类名等]: “被转换后的实际类名等”
	}
}

这样通过其中的locals对象,就很容易知道被转换后的类名了。举个例子,假设css原文件中有个类名为home,导入该css文件时用变量s接收,s.locals.home的值就是被转换后的类名了。

style-loader原理

  有了css-loader,style-loader的实现就很简单了。先通过css-loader把css文件转换成一个对象,假设叫content,该对象就是上面css-loader转换css文件后导出的对象。然后简单粗暴的通过DOM操作将content中的样式插入到style标签中。最后将content.locals导出,方便用户使用类名、动画名等。同时经过css-loader和style-loader转换后的内容可以用如下伪代码表示:

var content = 【css-loader转换css文件后的结果】;
addStylesToDom(content.toString());
module.exports = content.locals;

isomorphic-style-loader原理

  我们知道了style-loader的原理,它很简单,但又很粗暴。粗暴的是,直接将样式通过DOM操作进行插入。对于浏览器环境则很好,很方便,不需要用户干预。但是对于node环境,这就没法愉快的玩耍了。node环境需要的是将样式插入到动态生成的html字符串中,而不是进行DOM操作。这时就需要用到isomorphic-style-loader,而不是style-loader。
  isomorphic-style-loader没有像style-loader那样直接进行DOM操作,而是导出了一些辅助方法,让用户依据实际情况来调用不同的方法。同时经过css-loader和isomorphic-style-loader转换后的内容可以用如下伪代码表示:

var content = 【css-loader转换css文件后的结果】;
// 方便用户使用类名等
exports = module.exports = content.locals || {}; 
exports._getContent = () => content;
// 方便用户获取样式
exports._getCss = () => context.toString();	
// 方便用户将样式插入到DOM中
exports._insertCss = 【作用同上面的addStylesToDom】;

从如上伪代码可以看出,isomorphic-style-loader主要是导出了2个函数,_getCss和_insertCss。让用户根据实际环境来调用,而不是像style-loader那样。在浏览器环境中就可以调用_insertCss(_getCss())来将样式插入到DOM中;在node环境中就不能调用_insertCss,但能调用_getCss获取样式字符串,根据实际需求来使用。

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/zhangyanwei12/article/details/101270048

智能推荐

使用@Autowired注解获取对象为null的几种情况_autowired注入的对象为null-程序员宅基地

文章浏览阅读1.9w次,点赞14次,收藏45次。主要原因就是因为该类继承了一个第三方框架,在执行的过程中,它是被人家框架内部创建实例然后去调用的,这就导致了可能在内部new过这个对象了,所以就导致了@Component对这个类根本不起作用。该类继承了一个WebCrawler,其实就是一个第三方框架,在我执行某个功能的时候,这些被重写的方法就会被其内部自动调用。在该类中使用@Autowired注入对象,就会看到注入的对象为null,尽管这些对象已经在Spring容器中存在了。这是我遇到的情况,当一个对象使用过关键new时,它是不能被Spring所管理的。_autowired注入的对象为null

04、ZigBee 开发教程之进阶篇—CC2530驱动WiFi模块ESP8266打印温度信息_cc2530与esp8266串口t-程序员宅基地

文章浏览阅读4.3k次,点赞3次,收藏21次。文章目录1、实验目的2、实验设备3、源码分析4、实验步骤1、实验目的1)通过实验掌握 CC2530 使用AT指令驱动ESP8266的方法2)CC2530 通过串口0将温度数据打印到串口3)ESP8266在AP模式下发送温度数据到手机,手机发送指令开关LED灯2、实验设备硬件:1、PC机一台;2、ZigBee(CC2530)(底板、核心板、仿真器、USB 线)开发板一套;3、ESP8266 01S模块一个;4、DS18B20温度传感器一个软件:Windows 10系统,IAR for 8051 _cc2530与esp8266串口t

matlab中常微分方法,MATLAB解常微分方程组的解法(好东西要共享)-程序员宅基地

文章浏览阅读2.5k次。1:问题常微分方程的初值问题的标准数学表述为:y'=f(t,y),a<=t<=b,y(a)=y(0);我们要求解的任何高阶常微分方程都可以用替换法化为上式所示的一阶形式,其中y为向量,yo为初始值。2:Matlab中解决以上问题的步骤(1):化方程组为标准形式。例如:y'''-3y''-y’y=0,y(0)=0,y'(0)=1,y''(0)=-1.把微分方程的高阶导数写为低阶导数的算式..._如何把高阶微分方程化为一阶微分方程组

pycharm创建mysql项目_python3.7+djiango+mysql+PyCharm搭建web项目-程序员宅基地

文章浏览阅读149次。python3.71.创建项目目录如下web01目录下:-------------------------------------------------------------------------------------------------------------settings.py:项目配置文件ALLOWED_HOSTS = ['*'] # 允许任意主机访问web项目INSTALLE..._class webconfig(appconfig): name = 'web

MATLAB读取二进制格式的三维数据体_matlab 读取 二进制 “头文件 ” 数值-程序员宅基地

文章浏览阅读3.4k次,点赞2次,收藏6次。在地震勘探的科学计算中,我们经常用到三维数据体的读写,在MATLAB下怎么读取三维的数据体呢?其实很简单,代码如下:clc;close all;#定义一个空的三维数组v2_res=zeros(187,801,801);#187:Z方向的点数#801(中间的):y方向的点数#801(尾部的):x方向的点数#读二进制文件fp=fopen('overthrust.bin','rb')..._matlab 读取 二进制 “头文件 ” 数值

Linux日志管理(一)_linux获取5分钟日志方法-程序员宅基地

文章浏览阅读721次。Linux日志管理(一)1. 日志简介   日志对于安全来说,非常重要,他记录了系统每天发生的各种各样的事情,你可以通过他来检查错误发生的原因,或者受到攻击时攻击者留下的痕迹。日志主要的功能有:审计和监测。他还可以实时的监测系统状态,监测和追踪侵入者等等。   在Linux系统中,有三个主要的日志子系统:  连接时间日志--由多个程序执行,把纪录写入到/var/log/wtmp和/_linux获取5分钟日志方法

随便推点

JAVA——JAVA知识点集锦(上)_java 17点对应的24小时15分钟的哪个点-程序员宅基地

文章浏览阅读500次。转自:http://blog.csdn.net/scythe666/article/details/519947701、面向对象的特征有哪些方面?&nbsp;答:面向对象的特征主要有以下几个方面:&nbsp;- 抽象:抽象是将一类对象的共同特征总结出来构造类的过程,包括数据抽象和行为抽象两方面。抽象只关注..._java 17点对应的24小时15分钟的哪个点

Jira入门教程 敏捷开发管理(二)_jira敏捷开发教程-程序员宅基地

文章浏览阅读1.2k次。瀑布流模型开始介绍敏捷开发之前,先介绍一下敏捷开发方式提出之前的开发方式:瀑布流模型。瀑布流模型将软件开发和交付划分为几个相互独立的阶段:需求收集 设计 编码 测试其中每一步都需要等前一步完成之后才能进行,必须从上向下,也因此得名“瀑布”。瀑布流模型的理念有点“人定胜天”的意思,意图在开发之前就确定好一切细节——有经验的开发者都知道这是不可能的。在传统行业如建筑业中,受限于交付..._jira敏捷开发教程

火狐浏览器打开标签页在最后_火狐浏览器新打开的页面会显示到后面去-程序员宅基地

文章浏览阅读1.5k次,点赞5次,收藏4次。地址栏输入:about:config,把browser.tabs.insertAfterCurrent的值改为flase_火狐浏览器新打开的页面会显示到后面去

android 自定义加载动画效果,Android 自定义View修炼-自定义加载进度动画LoadingImageView...-程序员宅基地

文章浏览阅读299次。一、概述本自定义View,是加载进度动画的自定义View,继承于ImageView来实现,主要实现蒙层加载进度的加载进度效果。支持水平左右加载和垂直上下加载四个方向,同时也支持自定义蒙层进度颜色。直接看下面的效果图吧。二、效果图废话不说,先来看看效果图吧~~三、实现原理方案1、自定义View-XCLoadingImageView,继承ImageVIew来实现,这样就不用自己再处理drawable和..._android imageview loading

mysql免安装版配置与使用方法_mysql免安装版怎么用-程序员宅基地

文章浏览阅读568次。以mysql-noinstall-5.1.6(win32)为例1>把压缩文件mysql-noinstall-5.1.6-alpha-win32.zip解压到一个目录下,在环境变量中设置MYSQL_HOME,把%MYSQL_HOME%\bin 加入到 path。2>创建my.ini配置文件,内容如下:[mysqld]#设置basedir指向mysql的安装路径basedir=_mysql免安装版怎么用

[anaconda] frequently used conda commands_conda安装read_feather-程序员宅基地

文章浏览阅读127次。conda create python=3.6 -n your_env_nameconda listconda list some_packageconda install some_packageconda update some_packageconda remove some_packageconda clean -aconda env listconda env remo..._conda安装read_feather

推荐文章

热门文章

相关标签