webpack版本为5.74.0
module: {
rules: [
{
test: /\.css$/i,
use: [path.resolve(__dirname, './loader1.js'), path.resolve(__dirname, './loader2.js')],
}
],
},
loader1.js
module.exports = function () {
console.log('========loader1=========');
return ''
}
module.exports.pitch = function loader() {
console.log('========pitch1=========');
return `
import a from "!!../loader2.js!./index.css"
export default a
`
}
loader2.js
module.exports = function (content) {
console.log('========loader2=========', content);
return `import {a} from "../test.loader.files.js"
export default a
`
}
test.loader.files.js
export const a = () => {
console.log(12345);
}
export const b = () => {
console.log(12345);
}
index.css
div{
background-color: red;
}
控制台显示如下:
========pitch1=========
========loader2========= div{
background-color: red;
}
pitch的执行顺序
在有pitch方法的前提下会先从上至下执行pitch方法,再从下至上执行loader函数,如果pitch方法有返回值那么只会从当前pitch方法对应的loader的前一个loader开始执行。
但是我们从控制台可以看到首先执行的就是loader1的pitch方法,再执行loader2函数。这里有人就有疑问了,不是说pitch方法有返回值只会从当前pitch方法对应的loader的前一个loader开始执行吗,那就是执行loader1前面的loader开始执行。loader1前面是没有loader的,所以loader1不会执行,更不会执行loader2。但是loader2为什么执行了呢?主要是因为pitch1返回的值的原因,注意看!!../loader2.js!./index.css,!!表示不执行pre、post、normal等等loader,而且再次导入了index.css文件。由于是inline-loader,会从右至左执行loader,此时有个loader2.js,会执行该loader,这个loader前面有!!,所以只会执行loader2。我们再来看看打包文件:
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ "./src/index.css":
/*!***********************!*\
!*** ./src/index.css ***!
\***********************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _loader2_js_index_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! !!../loader2.js!./index.css */ \"./loader2.js!./src/index.css\");\n\n \n /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_loader2_js_index_css__WEBPACK_IMPORTED_MODULE_0__[\"default\"]);\n \n\n//# sourceURL=webpack://test-webpack/./src/index.css?");
/***/ }),
/***/ "./loader2.js!./src/index.css":
/*!************************************!*\
!*** ./loader2.js!./src/index.css ***!
\************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"default\": () => (__WEBPACK_DEFAULT_EXPORT__)\n/* harmony export */ });\n/* harmony import */ var _test_loader_files_js__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../test.loader.files.js */ \"./test.loader.files.js\");\n\n \n /* harmony default export */ const __WEBPACK_DEFAULT_EXPORT__ = (_test_loader_files_js__WEBPACK_IMPORTED_MODULE_0__.a);\n \n\n//# sourceURL=webpack://test-webpack/./src/index.css?./loader2.js");
/***/ }),
/***/ "./src/b.js":
/*!******************!*\
!*** ./src/b.js ***!
\******************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"c\": () => (/* binding */ c),\n/* harmony export */ \"d\": () => (/* binding */ d)\n/* harmony export */ });\nconst c = function () {\r\n const node = document.createElement('div')\r\n node.innerText = 888891\r\n node.style.color = 'red'\r\n document.body.appendChild(node)\r\n}\r\n\r\nconst d = function () {\r\n console.log(1141111);\r\n}\r\n\r\n\r\n\r\n\r\n\n\n//# sourceURL=webpack://test-webpack/./src/b.js?");
/***/ }),
/***/ "./src/index.js":
/*!**********************!*\
!*** ./src/index.js ***!
\**********************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _b__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./b */ \"./src/b.js\");\n/* harmony import */ var _index_css__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./index.css */ \"./src/index.css\");\n\r\n\r\nconst add = document.createElement('button')\r\nadd.innerText = '新增'\r\n\r\nconst div = document.createElement('div')\r\ndiv.innerText = Math.random()\r\nadd.addEventListener('click', function () {\r\n const div = document.createElement('div')\r\n div.innerText = Math.random()\r\n document.body.append(div)\r\n})\r\ndocument.body.appendChild(add)\r\nconsole.log(_index_css__WEBPACK_IMPORTED_MODULE_1__[\"default\"]);\r\nif (false) {}\r\n\n\n//# sourceURL=webpack://test-webpack/./src/index.js?");
/***/ }),
/***/ "./test.loader.files.js":
/*!******************************!*\
!*** ./test.loader.files.js ***!
\******************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export */ __webpack_require__.d(__webpack_exports__, {\n/* harmony export */ \"a\": () => (/* binding */ a),\n/* harmony export */ \"b\": () => (/* binding */ b)\n/* harmony export */ });\nconst a = () => {\r\n console.log(12345);\r\n}\r\nconst b = () => {\r\n console.log(12345);\r\n}\n\n//# sourceURL=webpack://test-webpack/./test.loader.files.js?");
/***/ })
/******/ });
可以发现index.css的模块内容就是pitch方法的返回值。引用的模块./loader2.js!./src/index.css和./test.loader.files.js也都被打包进去了。类似的案例就有style-loader和css-loader,style-loader只有pitch方法返回值如下:
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!./index.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!./index.css";
export default content && content.locals ? content.locals : undefined;
和我们讲的类似重新引入了./index.css,并使用css-loader处理,使用!!防止再次进入style-loader。并且导出了css-loader的返回值content:
{
"default": [
[
"./node_modules/css-loader/dist/cjs.js!./src/index.css",
"div{\r\n background-color: red;\r\n}",
""
]
]
}
然后执行style-loader的var update = API(content, options)方法将css样式放到header中。