跳到主要内容

style-loader

2024年04月06日
柏拉文
越努力,越幸运

一、认识


style-loader 核心逻辑是在 loader.patch 阶段执行, loader 函数本身是一个空函数。在 pitch 中, 核心处理逻辑如下:

  1. 获得对应样式文件: 通过 import style from "!!remainingRequest" 获取对应样式, remainingRequest 表示use: ['style-loader'] 位于 style-loader 之后的 loader 路径, !!remainingRequest 表示仅本次引入的 inline-loader 生效, 避免造成死循环。webpack 遇到 import style from "!!remainingRequest" 会递归编译 import 语句中的路径模块, 编译结果为:

    import style from "!!remainingRequest"

    // 编译为:
    /* harmony import */ var _Users_zhangwenqiang_bolawen_blog_docusaurus_webpack_test_webpack_bolawen01_node_modules_pnpm_css_loader_6_8_1_webpack_5_89_0_node_modules_css_loader_dist_cjs_js_Users_zhangwenqiang_bolawen_blog_docusaurus_webpack_test_webpack_bolawen01_loaders_style_loader_example_index_css__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! !!./node_modules/.pnpm/css-loader@6.8.1_webpack@5.89.0/node_modules/css-loader/dist/cjs.js!./loaders/style-loader/example/index.css */ "./node_modules/.pnpm/css-loader@6.8.1_webpack@5.89.0/node_modules/css-loader/dist/cjs.js!./loaders/style-loader/example/index.css");
  2. 在页面创建style节点, 将样式内容赋给style节点然后将节点加入head标签即可

设计理念:

  1. style-loader 处理逻辑放入 loader 中, css-loader 返回的是一段 js 脚本, 我们需要处理脚本中的 import/require 逻辑并执行这一段脚本, 获得样式内容

  2. style-loader 处理逻辑放入 pitch 中, 通过 import style from "!!remainingRequest" 语句, 并返回非 undefined 发生熔断。这样, 在 style-loader.pitch 之后 webpack 不会在去执行 use 中配置的后续 loader , 对 import style from "!!remainingRequest" 编译执行, 然后获得样式内容。

也就是是说: 通过pitch loaderimport someThing from !!${remainingRequest}剩余loader,从而实现上一个loader的返回值是js脚本,将脚本交给webpack去编译执行。

二、实现


function styleLoader(sourceCode) {}

styleLoader.pitch = function (remainingRequest, previousRequest, data) {
const script = `
import style from "!!${remainingRequest}";

const styleEl = document.createElement('style');
styleEl.innerHTML = style;
document.head.appendChild(styleEl);
`;
return script;
};

module.exports = styleLoader;

三、测试


3.1 test/webpack/bolawen01/loaders/style-loader/example/webpack.config.js

const path = require('path');
const HtmlWebpackPlugin = require('html-webpack-plugin');

module.exports = {
entry: path.resolve(__dirname, './index.js'),
devtool: false,
mode: 'development',
output: {
path: path.resolve(__dirname, 'dist'),
filename: '[name].js'
},
module: {
rules: [
{
test: /\.css$/,
use: [path.resolve(__dirname, '../core/index.js'), 'css-loader']
}
]
},
plugins: [new HtmlWebpackPlugin()]
};

3.2 test/webpack/bolawen01/loaders/style-loader/example/index.js

require("./index.css");

3.3 test/webpack/bolawen01/loaders/style-loader/example/index.css

div{
color: red;
}

3.4 test/webpack/bolawen01/package.json

"style-loader": "webpack --config ./loaders/style-loader/example/webpack.config.js"

参考资料


你不知道的「pitch loader」应用场景