Skip to content

Commit

Permalink
feat: add beforeTagInsert hook
Browse files Browse the repository at this point in the history
  • Loading branch information
msidolphin committed Jan 31, 2024
1 parent 8480bce commit 86cc2be
Show file tree
Hide file tree
Showing 19 changed files with 187 additions and 9 deletions.
3 changes: 2 additions & 1 deletion .cspell.json
Expand Up @@ -30,7 +30,8 @@
"vspace",
"commitlint",
"unreload",
"cnfg"
"cnfg",
"tapable"
],

"ignorePaths": [
Expand Down
23 changes: 22 additions & 1 deletion README.md
Expand Up @@ -101,7 +101,7 @@ module.exports = {
- **[`attributes`](#attributes)**
- **[`linkType`](#linkType)**
- **[`runtime`](#runtime)**
- **[`experimentalUseImportModule`](#experimentalUseImportModule)**
- **[`experimentalUseImportModule`](#experimentalUseImportmodule)**

#### `filename`

Expand Down Expand Up @@ -1194,6 +1194,27 @@ If you'd like to extract the media queries from the extracted CSS (so mobile use
- [Media Query Plugin](https://github.com/SassNinja/media-query-plugin)
- [Media Query Splitting Plugin](https://github.com/mike-diamond/media-query-splitting-plugin)

## Hooks

The mini-css-extract-plugin provides hooks to extend it to your needs.

### beforeTagInsert

`SyncWaterfallHook`

Called before inject the insert code for link tag. Should return a string

```javascript
MiniCssExtractPlugin.getCompilationHooks(compilation).beforeTagInsert.tap(
"changeHref",
(source, varNames) =>
Template.asString([
source,
`${varNames.tag}.setAttribute("href", "https://github.com/webpack-contrib/mini-css-extract-plugin");`,
])
);
```

## Contributing

Please take a moment to read our contributing guidelines if you haven't yet done so.
Expand Down
3 changes: 1 addition & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion package.json
Expand Up @@ -52,7 +52,8 @@
"webpack": "^5.0.0"
},
"dependencies": {
"schema-utils": "^4.0.0"
"schema-utils": "^4.0.0",
"tapable": "^2.2.1"
},
"devDependencies": {
"@babel/cli": "^7.21.0",
Expand Down
35 changes: 35 additions & 0 deletions src/hooks.js
@@ -0,0 +1,35 @@
const { SyncWaterfallHook } = require("tapable");

/** @typedef {import("webpack").Compilation} Compilation */
/**
* @typedef {Object} VarNames
* @property {string} tag
* @property {string} chunkId
* @property {string} href
* @property {string} resolve
* @property {string} reject
*/

/**
* @typedef {Object} MiniCssExtractPluginCompilationHooks
* @property {import("tapable").SyncWaterfallHook<[string, VarNames], string>} beforeTagInsert
*/

/** @type {WeakMap<Compilation, MiniCssExtractPluginCompilationHooks>} */
const compilationHooksMap = new WeakMap();

/**
*
* @param {Compilation} compilation the compilation
* @returns {MiniCssExtractPluginCompilationHooks} the compilation hooks
*/
exports.getCompilationHooks = function getCompilationHooks(compilation) {
let hooks = compilationHooksMap.get(compilation);
if (!hooks) {
hooks = {
beforeTagInsert: new SyncWaterfallHook(["source", "varNames"], "string"),
};
compilationHooksMap.set(compilation, hooks);
}
return hooks;
};
19 changes: 18 additions & 1 deletion src/index.js
Expand Up @@ -15,6 +15,7 @@ const {
getUndoPath,
BASE_URI,
} = require("./utils");
const { getCompilationHooks } = require("./hooks");

/** @typedef {import("schema-utils/declarations/validate").Schema} Schema */
/** @typedef {import("webpack").Compiler} Compiler */
Expand Down Expand Up @@ -513,6 +514,14 @@ class MiniCssExtractPlugin {
return CssDependency;
}

/**
* Returns all hooks for the given compilation
* @param {Compilation} compilation
*/
static getCompilationHooks(compilation) {
return getCompilationHooks(compilation);
}

/**
* @param {PluginOptions} [options]
*/
Expand Down Expand Up @@ -843,7 +852,6 @@ class MiniCssExtractPlugin {
if (!withLoading && !withHmr) {
return "";
}

return Template.asString([
'if (typeof document === "undefined") return;',
`var createStylesheet = ${runtimeTemplate.basicFunction(
Expand Down Expand Up @@ -902,6 +910,15 @@ class MiniCssExtractPlugin {
"}",
])
: "",
MiniCssExtractPlugin.getCompilationHooks(
compilation
).beforeTagInsert.call("", {
tag: "linkTag",
chunkId: "chunkId",
href: "fullhref",
resolve: "resolve",
reject: "reject",
}) || "",
typeof this.runtimeOptions.insert !== "undefined"
? typeof this.runtimeOptions.insert === "function"
? `(${this.runtimeOptions.insert.toString()})(linkTag)`
Expand Down
Expand Up @@ -73,7 +73,7 @@ __webpack_require__.r(__webpack_exports__);
/******/
/******/ /* webpack/runtime/getFullHash */
/******/ (() => {
/******/ __webpack_require__.h = () => ("7f0e5fa686a9bb728e64")
/******/ __webpack_require__.h = () => ("04f5273a6b9819ed9e63")
/******/ })();
/******/
/******/ /* webpack/runtime/global */
Expand Down Expand Up @@ -201,6 +201,7 @@ __webpack_require__.r(__webpack_exports__);
/******/ linkTag.onerror = linkTag.onload = onLinkComplete;
/******/ linkTag.href = fullhref;
/******/
/******/
/******/ if (oldTag) {
/******/ oldTag.parentNode.insertBefore(linkTag, oldTag.nextSibling);
/******/ } else {
Expand Down
3 changes: 2 additions & 1 deletion test/cases/chunkFilename-fullhash/expected/webpack-5/main.js
Expand Up @@ -73,7 +73,7 @@ __webpack_require__.r(__webpack_exports__);
/******/
/******/ /* webpack/runtime/getFullHash */
/******/ (() => {
/******/ __webpack_require__.h = () => ("100253bb7576627988e6")
/******/ __webpack_require__.h = () => ("04f5273a6b9819ed9e63")
/******/ })();
/******/
/******/ /* webpack/runtime/global */
Expand Down Expand Up @@ -201,6 +201,7 @@ __webpack_require__.r(__webpack_exports__);
/******/ linkTag.onerror = linkTag.onload = onLinkComplete;
/******/ linkTag.href = fullhref;
/******/
/******/
/******/ if (oldTag) {
/******/ oldTag.parentNode.insertBefore(linkTag, oldTag.nextSibling);
/******/ } else {
Expand Down
1 change: 1 addition & 0 deletions test/cases/hmr/expected/main.js
Expand Up @@ -964,6 +964,7 @@ __webpack_require__.r(__webpack_exports__);
/******/ linkTag.onerror = linkTag.onload = onLinkComplete;
/******/ linkTag.href = fullhref;
/******/
/******/
/******/ if (oldTag) {
/******/ oldTag.parentNode.insertBefore(linkTag, oldTag.nextSibling);
/******/ } else {
Expand Down
1 change: 1 addition & 0 deletions test/cases/insert-function/expected/main.js
Expand Up @@ -185,6 +185,7 @@
/******/ linkTag.onerror = linkTag.onload = onLinkComplete;
/******/ linkTag.href = fullhref;
/******/
/******/
/******/ (function (linkTag) {
/******/ const reference = document.querySelector(".hot-reload");
/******/ if (reference) {
Expand Down
1 change: 1 addition & 0 deletions test/cases/insert-string/expected/main.js
Expand Up @@ -185,6 +185,7 @@
/******/ linkTag.onerror = linkTag.onload = onLinkComplete;
/******/ linkTag.href = fullhref;
/******/
/******/
/******/ var target = document.querySelector("script[src='1.js']");
/******/ target.parentNode.insertBefore(linkTag, target.nextSibling);
/******/ return linkTag;
Expand Down
1 change: 1 addition & 0 deletions test/cases/insert-undefined/expected/main.js
Expand Up @@ -185,6 +185,7 @@
/******/ linkTag.onerror = linkTag.onload = onLinkComplete;
/******/ linkTag.href = fullhref;
/******/
/******/
/******/ if (oldTag) {
/******/ oldTag.parentNode.insertBefore(linkTag, oldTag.nextSibling);
/******/ } else {
Expand Down
74 changes: 74 additions & 0 deletions test/hooks.test.js
@@ -0,0 +1,74 @@
/* eslint-env browser */
import path from "path";

import { Template } from "webpack";

import MiniCssExtractPlugin from "../src";

import { runInJsDom, compile, getCompiler } from "./helpers/index";

describe("hooks", () => {
it(`beforeTagInsert`, async () => {
const webpackCompiler = getCompiler(
"insert.js",
{},
{
mode: "none",
output: {
publicPath: "",
path: path.resolve(__dirname, "../outputs"),
filename: "[name].bundle.js",
},
plugins: [
new MiniCssExtractPlugin({
filename: "[name].css",
}),
{
/**
*
* @param {import('webpack').Compiler} compiler
*/
apply: (compiler) => {
compiler.hooks.compilation.tap("sri", (compilation) => {
MiniCssExtractPlugin.getCompilationHooks(
compilation
).beforeTagInsert.tap("sri", (source, varNames) =>
Template.asString([
source,
`${varNames.tag}.setAttribute("integrity", "sriHashes[${varNames.chunkId}]");`,
])
);
});
},
},
{
/**
*
* @param {import('webpack').Compiler} compiler
*/
apply: (compiler) => {
compiler.hooks.compilation.tap("href", (compilation) => {
MiniCssExtractPlugin.getCompilationHooks(
compilation
).beforeTagInsert.tap("changeHref", (source, varNames) =>
Template.asString([
source,
`${varNames.tag}.setAttribute("href", "https://github.com/webpack-contrib/mini-css-extract-plugin");`,
])
);
});
},
},
],
}
);
const stats = await compile(webpackCompiler);
runInJsDom("main.bundle.js", webpackCompiler, stats, (dom) => {
const [tag] = dom.window.document.head.getElementsByTagName("link");
expect(tag.getAttribute("integrity")).toBe("sriHashes[chunkId]");
expect(tag.getAttribute("href")).toBe(
"https://github.com/webpack-contrib/mini-css-extract-plugin"
);
});
});
});
17 changes: 17 additions & 0 deletions types/hooks.d.ts
@@ -0,0 +1,17 @@
export function getCompilationHooks(
compilation: Compilation
): MiniCssExtractPluginCompilationHooks;
export type Compilation = import("webpack").Compilation;
export type VarNames = {
tag: string;
chunkId: string;
href: string;
resolve: string;
reject: string;
};
export type MiniCssExtractPluginCompilationHooks = {
beforeTagInsert: import("tapable").SyncWaterfallHook<
[string, VarNames],
string
>;
};
9 changes: 8 additions & 1 deletion types/index.d.ts
Expand Up @@ -12,6 +12,13 @@ declare class MiniCssExtractPlugin {
static getCssDependency(
webpack: Compiler["webpack"]
): CssDependencyConstructor;
/**
* Returns all hooks for the given compilation
* @param {Compilation} compilation
*/
static getCompilationHooks(
compilation: Compilation
): import("./hooks").MiniCssExtractPluginCompilationHooks;
/**
* @param {PluginOptions} [options]
*/
Expand Down Expand Up @@ -103,6 +110,7 @@ type CssDependencyConstructor = new (
context: string | null,
identifierIndex: number
) => CssDependency;
type Compilation = import("webpack").Compilation;
type PluginOptions = {
filename?: Required<Configuration>["output"]["filename"];
chunkFilename?: Required<Configuration>["output"]["chunkFilename"];
Expand Down Expand Up @@ -166,7 +174,6 @@ declare const pluginName: "mini-css-extract-plugin";
declare const pluginSymbol: unique symbol;
declare var loader: string;
type Schema = import("schema-utils/declarations/validate").Schema;
type Compilation = import("webpack").Compilation;
type ChunkGraph = import("webpack").ChunkGraph;
type Chunk = import("webpack").Chunk;
type ChunkGroup = Parameters<import("webpack").Chunk["isInGroup"]>[0];
Expand Down

0 comments on commit 86cc2be

Please sign in to comment.