

窥探css-loader与style-loader的作用
source link: https://segmentfault.com/a/1190000040918194
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

大家伙都清楚在使用webpack
构建前端项目时都会使用到sass-loader、less-loader、postcss-loader、css-loader、style-loader
,但这些loader
在其中起到什么作用呢?本篇主要阐述css-loader
与style-loader
的作用和实现,加深对loader
的理解。
css-loader
css-loader
会对 @import
和 url()
进行处理,就像 js
解析 import/require()
一样,默认生成一个数组存放存放处理后的样式字符串,并将其导出。
假如有三个样式文件:a.module.scss
,b.module.scss
,c.module.scss
,它们之间的依赖关系是这样的:
// a.module.scss @import './b.module.scss'; .container { width: 200px; height: 200px; background-color: antiquewhite; } // b.module.scss @import url('./c.module.scss'); .text { font-size: 16px; color: #da2227; font-weight: bold; } // c.module.scss .name { font-size: 16px;; color: #da7777; font-weight: bold; }
在index.jsx
文件中引入它们
// index.jsx import React from 'react'; import styles from './a.module.scss'; const Index = () => { return <div className={styles.container}> <span className={styles.text}><span className={styles.name}>xxx,</span>hello world!!!</span> </div> } export default Index;
webpack.config.js
构建脚本
// webpack.config.js const path = require('path'); const { CleanWebpackPlugin } = require('clean-webpack-plugin'); const webpack = require('webpack'); module.exports = { entry: { index: './src/index.jsx' }, output: { filename: 'js/[name].js', path: path.resolve(__dirname, './dist'), library: 'MyComponent', libraryTarget: 'umd', }, resolve: { extensions: ['.js', '.jsx', '.tsx'], }, module: { rules: [ { test: /\.(js|jsx)$/, exclude: /node_modules/, loader: "babel-loader" }, { test: /\.(sa|sc|c)ss$/, use: [ 'style-loader', { loader: 'css-loader', options: { modules: false, // 禁止css modules } }, 'sass-loader' ] }, { test: /\.(jpg|jpeg|png|gif)$/, use: ['url-loader'] } ] }, plugins: [ new webpack.ProgressPlugin(), new CleanWebpackPlugin({ cleanOnceBeforeBuildPatterns: ['dist'] }), ], }
.babelrc
配置
// .babelrc { "presets": [ "@babel/preset-env", "@babel/preset-react" ], "plugins": [ "@babel/plugin-proposal-class-properties" ] }
在package.json
配置构建命令"build:dev": "webpack --mode none"
。为了方便分析构建之后的代码,这里将mode
设置为none
。
三种mode
方式:
development
会将 DefinePlugin
中 process.env.NODE_ENV
的值设置为 development
。为模块和 chunk 启用有效的名,也就是将模块id替换成模块名称。production
会将 DefinePlugin
中 process.env.NODE_ENV
的值设置为 production
。为模块和 chunk 启用确定性的混淆名称,
FlagDependencyUsagePlugin
,FlagIncludedChunksPlugin
,ModuleConcatenationPlugin
,NoEmitOnErrorsPlugin
和 TerserPlugin
。none
不使用任何默认优化选项执行yarn build:dev
构建,分析生成的文件
(1)a.module.scss
使用@import
引入了b.module.scss
,被处理放入同一个模块的数组___CSS_LOADER_EXPORT___
中并导出
(2)b.module.scss
使用@import url()
引入了c.module.scss
,但c.module.scss
被单独处理放入另一个模块的数组___CSS_LOADER_EXPORT___
中并导出
(3)a.module.scss
与b.module.scss
被处理放入一个模块数组,c.module.scss
被单独处理放入另一个模块的数组,但是b.module.scss
与c.module.scss
是由引入关系的,这个在构建后怎么关联依赖的呢?
a.module.scss
与b.module.scss
被处理放入模块id
为12
的数组,c.module.scss
被处理放入模块id
为15
的数组,模块id
为12
的模块中导入了模块id
为15
中的样式数组,并将其追加到模块id
为12
的数组中,最后统一以数组__WEBPACK_DEFAULT_EXPORT__
导出,css-loader
处理到这一步就结束了。
另外
css-loader
还提供其他的功能,比如css modules
,想要了解可以参照例子开启css modules
构建,窥其原理,此处不作介绍
css-loader
导出方式
上面说到引入的样式都被转化成样式字符串放入模块数组中,这是默认的处理方式,其实还有另外两种。
配置项exportType
允许导出样式为'array'
、'string'
或者 'css-style-sheet'
可构造样式(即 CSSStyleSheet
), 默认值:'array'
CSSStyleSheet
接口代表一个 CSS 样式表,并允许检查和编辑样式表中的规则列表。它从父类型 StyleSheet
继承属性和方法。
一个 CSS
样式表包含了一组表示规则的 CSSRule
对象。每条 CSS
规则可以通过与之相关联的对象进行操作,这些规则被包含在 CSSRuleList
内,可以通过样式表的 cssRules
(en-US) 属性获取。
例如,CSSStyleRule
对象中的一条规则可能包含这样的样式:
h1, h2 { font-size: 16pt; }
style-loader
style-loader
的作用是把 CSS
插入到 DOM
中,就是处理css-loader
导出的模块数组,然后将样式通过style
标签或者其他形式插入到DOM
中。
配置项injectType
可配置把 styles
插入到 DOM
中的方式,主要有:
styleTag
:通过使用多个<style></style>
自动把styles
插入到DOM
中。该方式是默认行为singletonStyleTag
:通过使用一个<style></style>
来自动把styles
插入到DOM
中autoStyleTag
:与styleTag
相同,但是当代码在IE6-9
中运行时,请打开singletonStyleTag
模式lazyStyleTag
:在需要时使用多个<style></style>
把styles
插入到DOM
中。推荐lazy style
遵循使用.lazy.css
作为后缀的命名约定,style-loader
基本用法是使用.css
作为文件后缀(其他文件也一样,比如:.lazy.less
和.less
)。当使用lazyStyleTag
时,style-loader
将惰性插入styles
,在需要使用styles
时可以通过style.use()
/style.unuse()
使style
可用。lazySingletonStyleTag
:通过使用一个<style></style>
来自动把styles
插入到DOM
中,如上提供惰性支持lazyAutoStyleTag
:与lazyStyleTag
相同,但是当代码在IE6-9
中运行时,请打开lazySingletonStyleTag
模式linkTag
:使用多个<link rel="stylesheet" href="path/to/file.css">
将 styles 插入到 DOM 中。此loader
会在运行时使用JavaScript
动态地插入<link href="path/to/file.css" rel="stylesheet">
。要静态插入<link href="path/to/file.css" rel="stylesheet">
时请使用MiniCssExtractPlugin。
我们以styleTag
插入方式进行分析:
上面说到所有的样式都追加到模块id
为12
的模块数组中,下面先获取模块id
为12
的模块数组,然后生成style
标签将其样式插入DOM
中
上图中_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()
得到的就是下图模块返回的update
方法,该方法调用了其他很多方法将样式通过style
标签插入DOM
Recommend
-
9
We want our products to leave a good impression on first-time users. So whenever we build something, we make it possible first, then ask if it can be a little unique. And the glowing loader is one of those attempts. Here is Hieu's ori...
-
5
关于样式编译因为webpack编译的思想是万无皆可JS,意旨所有web项目关联的资源文件,都可以通过js关联起来。然而又由于图片,样式这些本来和js八竿子打不到一起的,所以就有了各种loader来解决他们的关联性问题;说到webpack的样式编译,总有几...
-
8
-
11
-
7
Spinners collection A general situation that we all might face while going through websites/apps is to wait for some progress or something to get loaded. A most simple solution in such scenarios is to use a l...
-
5
CSS only Blob loader 0 unsaved changes xxxxxxxxxx<div class="loader"></div>...
-
7
style-loader与iframe的问题 通常情况下其实遇不到style-loader与iframe纠缠的情况,不过由于自己所做项目的特殊性,所以不得不经常与iframe打些交道,并且往往遇到问题能参考的资料也非常有限。
-
1
When we are writing web applications, the time for loading resources becomes longer and longer as the code grows. It's a good idea to show a loading spinner while the website resources are loading. This post will show you how to show a CSS lo...
-
9
File-Loader.js
-
4
本文翻译自 How to create a CSS-only loader with one element,作者: Temani Afif, 略有删改。
About Joyk
Aggregate valuable and interesting links.
Joyk means Joy of geeK