执行debugger;
const loaderAPI = () => {};
loaderAPI.pitch = function loader(request) {
debugger;
const options = this.getOptions(_options.default);
const injectType = options.injectType || "styleTag";
const esModule = typeof options.esModule !== "undefined" ? options.esModule : true;
const runtimeOptions = {};
....`
style-loader是通过loader.pitch函数往源代码中插入dom操作来执行的,webpack执行loader的顺序是从右往左,但是执行pitch函数是从左到右执行 然后就是执行一些绑定参数的操作 最后通过return 返回一段代码字符串:
" import API from "!../../../node_modules/style-loader/dist/runtime/injectStylesIntoStyleTag.js";
import domAPI from "!../../../node_modules/style-loader/dist/runtime/styleDomAPI.js";
import insertFn from "!../../../node_modules/style-loader/dist/runtime/insertBySelector.js";
import setAttributes from "!../../../node_modules/style-loader/dist/runtime/setAttributesWithoutAttributes.js";
import insertStyleElement from "!../../../node_modules/style-loader/dist/runtime/insertStyleElement.js";
import styleTagTransformFn from "!../../../node_modules/style-loader/dist/runtime/styleTagTransform.js";
import content, * as namedExport from "!!../../../node_modules/css-loader/dist/cjs.js!./a.css";
var options = {};
options.styleTagTransform = styleTagTransformFn; options.setAttributes = setAttributes;
options.insert = insertFn.bind(null, "head");
options.domAPI = domAPI;
options.insertStyleElement = insertStyleElement;
var update = API(content, options);
export * from "!!../../../node_modules/css-loader/dist/cjs.js!./a.css"; export default content && content.locals ? content.locals : undefined; "
重点在于这段:
import content, * as namedExport from "!!../../../node_modules/css-loader/dist/cjs.js!./a.css";
pitch函数返回值的时候是会阻断后面loader的执行的,但这时候通过inline-loader写法再次引入css-loader来解析css文件,使得css-loader能再次运行,这里的!!会忽略前置、后置、普通loader的执行,也就是阻止style-loader第二次执行;此时loader执行完成,往源码中插入了dom操作,此时我们来看var update = API(content, options);打断点
module.exports = function injectStylesIntoStyleTag(list, options) {
debugger;
options = options || {};
list = list || [];
var lastIdentifiers = modulesToDom(list, options);
return function update(newList) {
...
function modulesToDom(list, options) {
var idCountMap = {};
var identifiers = [];
for (var i = 0; i < list.length; i++) {
var item = list[i];
var id = options.base ? item[0] + options.base : item[0];
var count = idCountMap[id] || 0;
var identifier = "".concat(id, " ").concat(count);
idCountMap[id] = count + 1;
var indexByIdentifier = getIndexByIdentifier(identifier);
var obj = {
css: item[1],
media: item[2],
sourceMap: item[3],
supports: item[4],
layer: item[5]
};
if (indexByIdentifier !== -1) {
stylesInDOM[indexByIdentifier].references++;
stylesInDOM[indexByIdentifier].updater(obj);
} else {
var updater = addElementStyle(obj, options);
options.byIndex = i;
stylesInDOM.splice(i, 0, {
identifier: identifier,
updater: updater,
references: 1
});
}
identifiers.push(identifier);
}
return identifiers;
}
function addElementStyle(obj, options) {
var api = options.domAPI(options);
api.update(obj);
var updater = function updater(newObj) {
if (newObj) {
if (newObj.css === obj.css && newObj.media === obj.media && newObj.sourceMap === obj.sourceMap && newObj.supports === obj.supports && newObj.layer === obj.layer) {
return;
}
api.update(obj = newObj);
} else {
api.remove();
}
};
return updater;
}
function domAPI(options) {
var styleElement = options.insertStyleElement(options);
return {
update: function update(obj) {
apply(styleElement, options, obj);
},
remove: function remove() {
removeStyleElement(styleElement);
}
};
}
function insertStyleElement(options) {
var element = document.createElement("style");
options.setAttributes(element, options.attributes);
options.insert(element, options.options);
return element;
}
function insertBySelector(insert, style) {
var target = getTarget(insert);
if (!target) {
throw new Error("Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid.");
}
target.appendChild(style);
}
function styleTagTransform(css, styleElement) {
if (styleElement.styleSheet) {
styleElement.styleSheet.cssText = css;
} else {
while (styleElement.firstChild) {
styleElement.removeChild(styleElement.firstChild);
}
styleElement.appendChild(document.createTextNode(css));
}
}
然后就是常见的往head插入style元素的操作