窥探css-loader与style-loader的作用

前言 大家伙都清楚在使用webpack构建前端项目时都会使用到sass-loader、less-loader、postcss-loader、css-loader、style-loader,但这些loader在其中起到什么作用呢?本篇主要阐述css-loaderstyle-loader的作用和实现,加深对loader的理解。
css-loader css-loader 会对 @importurl() 进行处理,就像 js 解析 import/require() 一样,默认生成一个数组存放存放处理后的样式字符串,并将其导出。
假如有三个样式文件:a.module.scssb.module.scssc.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 xxx,hello world!!!}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 会将 DefinePluginprocess.env.NODE_ENV 的值设置为 development。为模块和 chunk 启用有效的名,也就是将模块id替换成模块名称。
窥探css-loader与style-loader的作用
文章图片


窥探css-loader与style-loader的作用
文章图片
production 会将 DefinePluginprocess.env.NODE_ENV 的值设置为 production
为模块和 chunk 启用确定性的混淆名称,FlagDependencyUsagePlugin
FlagIncludedChunksPluginModuleConcatenationPlugin
NoEmitOnErrorsPluginTerserPlugin
窥探css-loader与style-loader的作用
文章图片
none 不使用任何默认优化选项
执行yarn build:dev构建,分析生成的文件
(1)a.module.scss使用@import引入了b.module.scss,被处理放入同一个模块的数组___CSS_LOADER_EXPORT___中并导出
窥探css-loader与style-loader的作用
文章图片

(2)b.module.scss使用@import url()引入了c.module.scss,但c.module.scss被单独处理放入另一个模块的数组___CSS_LOADER_EXPORT___中并导出
窥探css-loader与style-loader的作用
文章图片

(3)a.module.scssb.module.scss被处理放入一个模块数组,c.module.scss被单独处理放入另一个模块的数组,但是b.module.scssc.module.scss是由引入关系的,这个在构建后怎么关联依赖的呢?
a.module.scssb.module.scss被处理放入模块id12的数组,c.module.scss被处理放入模块id15的数组,模块id12的模块中导入了模块id15中的样式数组,并将其追加到模块id12的数组中,最后统一以数组__WEBPACK_DEFAULT_EXPORT__导出,css-loader处理到这一步就结束了。
另外 css-loader还提供其他的功能,比如 css modules,想要了解可以参照例子开启 css modules构建,窥其原理,此处不作介绍
窥探css-loader与style-loader的作用
文章图片

窥探css-loader与style-loader的作用
文章图片

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:通过使用多个 自动把 styles 插入到 DOM 中。该方式是默认行为
  • singletonStyleTag:通过使用一个 来自动把 styles 插入到 DOM
  • autoStyleTag:与 styleTag 相同,但是当代码在 IE6-9 中运行时,请打开 singletonStyleTag 模式
  • lazyStyleTag:在需要时使用多个 styles 插入到 DOM 中。推荐 lazy style 遵循使用 .lazy.css 作为后缀的命名约定,style-loader 基本用法是使用 .css 作为文件后缀(其他文件也一样,比如:.lazy.less.less)。当使用 lazyStyleTag 时,style-loader 将惰性插入 styles,在需要使用 styles 时可以通过 style.use() / style.unuse() 使 style 可用。
  • lazySingletonStyleTag:通过使用一个 来自动把 styles 插入到 DOM 中,如上提供惰性支持
  • lazyAutoStyleTag:与 lazyStyleTag 相同,但是当代码在 IE6-9 中运行时,请打开lazySingletonStyleTag 模式
  • linkTag:使用多个 将 styles 插入到 DOM 中。此 loader 会在运行时使用 JavaScript 动态地插入。要静态插入 时请使用MiniCssExtractPlugin
我们以styleTag插入方式进行分析:
上面说到所有的样式都追加到模块id12的模块数组中,下面先获取模块id12的模块数组,然后生成style标签将其样式插入DOM
窥探css-loader与style-loader的作用
文章图片

【窥探css-loader与style-loader的作用】上图中_node_modules_style_loader_dist_runtime_injectStylesIntoStyleTag_js__WEBPACK_IMPORTED_MODULE_0___default()得到的就是下图模块返回的update方法,该方法调用了其他很多方法将样式通过style标签插入DOM
窥探css-loader与style-loader的作用
文章图片

参考:
css-loader
style-loader

    推荐阅读