{test: /\.css$/,use: ['style-loader','css-loader']}
配置项
{loader: 'style-loader',options: {injectTag: 'styleTag'}}
injectTag
- styleTag:自动往 header 添加 style 标签,默认是多个
- singletonStyleTag:往 header 添加 style 标签,只添加一个 style
- autoStyleTag:默认行为是 styleTag,当 IE6 - 9 时,表现为 singletonStyleTag
- lazyStyleTag:懒加载的 styleTag,只有当调用 styles.use 才会加入 style
- lazySingletonStyleTag:懒加载的 singletonStyleTag,调用 use 加入,unuse 取消
- lazyAutoStyleTag:懒加载的 autoStyleTag
- linkTag:需要搭配 file-loader 使用
singletonStyleTag
懒加载的样式结构: ```javascript import styles from ‘css-loader’
styles 结构: { locals: { container: ‘_2Zi7gYtNVL0Ohubm—3hA2’, btn: ‘Z-kqLN1uX0jQAwM63yfq6’ }, unuse: f (), use: f () }
调用 styles.use() 加载 css,unuse 卸载 css
<a name="JMRTt"></a>#### linkTag 配合 file-loader 使用```javascript{test: /\.css$/,use: [{loader: 'style-loader',options: {injectType: 'linkTag'}},'file-loader']}
attributes
{loader: 'style-loader',options: {attributes: { id: 'id' }}}
insert
- 选择器
- 方法 ```javascript // 选择器
- ‘head’ 默认
- ‘body’
- ‘#app’ 等
// 方法
insert: element => {
const parent = document.querySeletor(‘head’);
const lastElementInsertedByStyleLoader = window.lastElementInsertedByStyleLoader;
if (!lastElementInsertedByStyleLoader) {
parent.insertBefore(element, parent.firstChild);
} else if (lastElementInsertedByStyleLoader.nextSibling) {
parent.insertBefore(element, lastElementInsertedByStyleLoader.nextSibling);
} else {
parent.appendChild(element);
}
window.lastElementInsertedByStyleLoader = element;
}
<a name="4xHqK"></a>### styleTagTransformstyleTagTransform 是在浏览器执行的,有两个参数 css 和 style,css 是解析得到的 css 数据,style 是创建的 style 标签```javascriptstyleTagTransform: (css, style) => {style.innerHTML = `${css}\n.modify{ color: #ff0000 }`;document.head.appendChild(style);}
style-loader自研思路
- style-loader 的核心是:拿到其他 loader 处理完成的 css 内容,把它插入页面
- 如何拿到其他 loader 处理完成的 css
- 如何把内容插入页面
- webpack 热更新时如何替换 css
- insert,injectTag,attributes 如何实现?
如何拿到其他 loader 处理完成的 css?
一点思路也没有的话,可以先看 Loader 预备知识。
loader 有两种:1. 前置 loader; 2. 普通 loader
webpack loader 是洋葱模型,先从左往右执行各个 loader 的 pitch,然后从右往左执行 loader。一般会使用 css-loader 做 import,url,模块化相关工作,执行完成之后 source 格式如下:
可以看到 css 被编译成了 js,调用 CSS_LOADER_EXPORT.toString() 可以获得 css 内容// Importsimport ___CSS_LOADER_API_IMPORT___ from "../node_modules/css-loader/dist/runtime/api.js";var ___CSS_LOADER_EXPORT___ = ___CSS_LOADER_API_IMPORT___(function(i){return i[1]});// Module___CSS_LOADER_EXPORT___.push([module.id, "html {\n height: 100%;\n background: #ff0;\n /* background: aquamarine; */\n}", ""]);// Exportsexport default ___CSS_LOADER_EXPORT___;
这样的内容暂时还没有想到办法可以引入,所以普通 loader 就行不通了前置 loader pitch 拦截
使用 pitch 拦截后续 loader 执行,然后使用 require 行内 loader 的方式来调用后续 loader 获得结果,这也是 webpack 所提倡的方法
在 pitch 中 return,就拦截了后续 loader 的执行,调用 require remainingRequest 可以以模块化的方式获得后续 loader 执行结果module.exports.pitch = function (remainingRequest, precedingRequest, data) {return `module.exports = retuire('-!${remainingRequest}')`}
require 内联 loader
webpack 地址看这里:https://www.webpackjs.com/api/loaders/
其实 webpack 文档中提供了除了使用 webpack 配置文件配置 loader 加载资源之外的另一种方法:
在入口文件中直接这么调用,就不需要配置 webpack 配置文件了,但是 css 文件很多的话,每个都这么写就很麻烦require('style-loader!css-loader?modules!./index.css?name=Alex')
内联 loader 研究
内联 loader 有个问题 ```javascript 比如代码中 import ‘style-loader!css-loader!./index.css’ 然后 webpack.config.js 中又配置了 css 的 loader 检测 { test: /.css/, use: [ ‘style-loader’, ‘css-loader’, ] }
那么 index.css 文件会被加载两次。
以我目前理解是,webpack 配置文件配置的属于 preLoader,内联 import 属于 loader,所以导致执行了两次,所以在内联 import 的时候,最好是都加上 -! 以跳过 **普通和前置 loader**1. ! 跳过普通 loaders1. -! 跳过前置和普通 loaders1. !! 禁用所有的 loaders到这里,拿到其他 loader 处理完成的 css 就解决了<a name="gDPfd"></a>## 如何把内容插入页面?上面方法 require 之后可以调用 toString 拿到编译之后的 css,创建 style 标签,放入 css 即可```javascriptmodule.exports.pitch = function (remainingRequest, precedingRequest, data) {return `import cssModule from '${remainingRequest}'cosnt style = document.createElement('style');style.innerHTML = cssModule;document.head.appendChild(style);`}
webpack 热更新时如何替换 css?
要替换 css,那么就需要找到当前 css 内容对应哪个 style,操作 style 就完事了
window.__styleInjectedMappedByRemainingRequest = {}
window.__styleInjectedMappedByRemainingRequest[remainingRequest] = style;
remainingRequest 的结构如下 👇:
/Users/wholee/Desktop/webpack-css-system/node_modules/css-loader/dist/cjs.js!/Users/wholee/Desktop/webpack-css-system/my-style-loader/index2.css
可以看到使用 loader 的绝对路径以及源文件绝对路径都很清楚,所以可以作为查找 style 的键
insert,injectTag,attributes 如何实现?
这些就不细聊了,只是字符串替换的问题。具体插件源码参考如下:
StyleLoader.js
