Skip to content

Commit 6313bf6

Browse files
authored
feat: added the beforeTagInsert hook (#1054)
1 parent 8480bce commit 6313bf6

File tree

19 files changed

+186
-8
lines changed

19 files changed

+186
-8
lines changed

.cspell.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,8 @@
3030
"vspace",
3131
"commitlint",
3232
"unreload",
33-
"cnfg"
33+
"cnfg",
34+
"tapable"
3435
],
3536

3637
"ignorePaths": [

README.md

+21
Original file line numberDiff line numberDiff line change
@@ -1194,6 +1194,27 @@ If you'd like to extract the media queries from the extracted CSS (so mobile use
11941194
- [Media Query Plugin](https://github.com/SassNinja/media-query-plugin)
11951195
- [Media Query Splitting Plugin](https://github.com/mike-diamond/media-query-splitting-plugin)
11961196

1197+
## Hooks
1198+
1199+
The mini-css-extract-plugin provides hooks to extend it to your needs.
1200+
1201+
### beforeTagInsert
1202+
1203+
`SyncWaterfallHook`
1204+
1205+
Called before inject the insert code for link tag. Should return a string
1206+
1207+
```javascript
1208+
MiniCssExtractPlugin.getCompilationHooks(compilation).beforeTagInsert.tap(
1209+
"changeHref",
1210+
(source, varNames) =>
1211+
Template.asString([
1212+
source,
1213+
`${varNames.tag}.setAttribute("href", "https://github.com/webpack-contrib/mini-css-extract-plugin");`,
1214+
])
1215+
);
1216+
```
1217+
11971218
## Contributing
11981219

11991220
Please take a moment to read our contributing guidelines if you haven't yet done so.

package-lock.json

+1-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+2-1
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,8 @@
5252
"webpack": "^5.0.0"
5353
},
5454
"dependencies": {
55-
"schema-utils": "^4.0.0"
55+
"schema-utils": "^4.0.0",
56+
"tapable": "^2.2.1"
5657
},
5758
"devDependencies": {
5859
"@babel/cli": "^7.21.0",

src/hooks.js

+35
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
const { SyncWaterfallHook } = require("tapable");
2+
3+
/** @typedef {import("webpack").Compilation} Compilation */
4+
/**
5+
* @typedef {Object} VarNames
6+
* @property {string} tag
7+
* @property {string} chunkId
8+
* @property {string} href
9+
* @property {string} resolve
10+
* @property {string} reject
11+
*/
12+
13+
/**
14+
* @typedef {Object} MiniCssExtractPluginCompilationHooks
15+
* @property {import("tapable").SyncWaterfallHook<[string, VarNames], string>} beforeTagInsert
16+
*/
17+
18+
/** @type {WeakMap<Compilation, MiniCssExtractPluginCompilationHooks>} */
19+
const compilationHooksMap = new WeakMap();
20+
21+
/**
22+
*
23+
* @param {Compilation} compilation the compilation
24+
* @returns {MiniCssExtractPluginCompilationHooks} the compilation hooks
25+
*/
26+
exports.getCompilationHooks = function getCompilationHooks(compilation) {
27+
let hooks = compilationHooksMap.get(compilation);
28+
if (!hooks) {
29+
hooks = {
30+
beforeTagInsert: new SyncWaterfallHook(["source", "varNames"], "string"),
31+
};
32+
compilationHooksMap.set(compilation, hooks);
33+
}
34+
return hooks;
35+
};

src/index.js

+18-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ const {
1515
getUndoPath,
1616
BASE_URI,
1717
} = require("./utils");
18+
const { getCompilationHooks } = require("./hooks");
1819

1920
/** @typedef {import("schema-utils/declarations/validate").Schema} Schema */
2021
/** @typedef {import("webpack").Compiler} Compiler */
@@ -513,6 +514,14 @@ class MiniCssExtractPlugin {
513514
return CssDependency;
514515
}
515516

517+
/**
518+
* Returns all hooks for the given compilation
519+
* @param {Compilation} compilation
520+
*/
521+
static getCompilationHooks(compilation) {
522+
return getCompilationHooks(compilation);
523+
}
524+
516525
/**
517526
* @param {PluginOptions} [options]
518527
*/
@@ -843,7 +852,6 @@ class MiniCssExtractPlugin {
843852
if (!withLoading && !withHmr) {
844853
return "";
845854
}
846-
847855
return Template.asString([
848856
'if (typeof document === "undefined") return;',
849857
`var createStylesheet = ${runtimeTemplate.basicFunction(
@@ -902,6 +910,15 @@ class MiniCssExtractPlugin {
902910
"}",
903911
])
904912
: "",
913+
MiniCssExtractPlugin.getCompilationHooks(
914+
compilation
915+
).beforeTagInsert.call("", {
916+
tag: "linkTag",
917+
chunkId: "chunkId",
918+
href: "fullhref",
919+
resolve: "resolve",
920+
reject: "reject",
921+
}) || "",
905922
typeof this.runtimeOptions.insert !== "undefined"
906923
? typeof this.runtimeOptions.insert === "function"
907924
? `(${this.runtimeOptions.insert.toString()})(linkTag)`

test/cases/chunkFilename-fullhash/expected/webpack-5-importModule/main.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ __webpack_require__.r(__webpack_exports__);
7373
/******/
7474
/******/ /* webpack/runtime/getFullHash */
7575
/******/ (() => {
76-
/******/ __webpack_require__.h = () => ("7f0e5fa686a9bb728e64")
76+
/******/ __webpack_require__.h = () => ("04f5273a6b9819ed9e63")
7777
/******/ })();
7878
/******/
7979
/******/ /* webpack/runtime/global */
@@ -201,6 +201,7 @@ __webpack_require__.r(__webpack_exports__);
201201
/******/ linkTag.onerror = linkTag.onload = onLinkComplete;
202202
/******/ linkTag.href = fullhref;
203203
/******/
204+
/******/
204205
/******/ if (oldTag) {
205206
/******/ oldTag.parentNode.insertBefore(linkTag, oldTag.nextSibling);
206207
/******/ } else {

test/cases/chunkFilename-fullhash/expected/webpack-5/main.js

+2-1
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ __webpack_require__.r(__webpack_exports__);
7373
/******/
7474
/******/ /* webpack/runtime/getFullHash */
7575
/******/ (() => {
76-
/******/ __webpack_require__.h = () => ("100253bb7576627988e6")
76+
/******/ __webpack_require__.h = () => ("04f5273a6b9819ed9e63")
7777
/******/ })();
7878
/******/
7979
/******/ /* webpack/runtime/global */
@@ -201,6 +201,7 @@ __webpack_require__.r(__webpack_exports__);
201201
/******/ linkTag.onerror = linkTag.onload = onLinkComplete;
202202
/******/ linkTag.href = fullhref;
203203
/******/
204+
/******/
204205
/******/ if (oldTag) {
205206
/******/ oldTag.parentNode.insertBefore(linkTag, oldTag.nextSibling);
206207
/******/ } else {

test/cases/hmr/expected/main.js

+1
Original file line numberDiff line numberDiff line change
@@ -964,6 +964,7 @@ __webpack_require__.r(__webpack_exports__);
964964
/******/ linkTag.onerror = linkTag.onload = onLinkComplete;
965965
/******/ linkTag.href = fullhref;
966966
/******/
967+
/******/
967968
/******/ if (oldTag) {
968969
/******/ oldTag.parentNode.insertBefore(linkTag, oldTag.nextSibling);
969970
/******/ } else {

test/cases/insert-function/expected/main.js

+1
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@
185185
/******/ linkTag.onerror = linkTag.onload = onLinkComplete;
186186
/******/ linkTag.href = fullhref;
187187
/******/
188+
/******/
188189
/******/ (function (linkTag) {
189190
/******/ const reference = document.querySelector(".hot-reload");
190191
/******/ if (reference) {

test/cases/insert-string/expected/main.js

+1
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@
185185
/******/ linkTag.onerror = linkTag.onload = onLinkComplete;
186186
/******/ linkTag.href = fullhref;
187187
/******/
188+
/******/
188189
/******/ var target = document.querySelector("script[src='1.js']");
189190
/******/ target.parentNode.insertBefore(linkTag, target.nextSibling);
190191
/******/ return linkTag;

test/cases/insert-undefined/expected/main.js

+1
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,7 @@
185185
/******/ linkTag.onerror = linkTag.onload = onLinkComplete;
186186
/******/ linkTag.href = fullhref;
187187
/******/
188+
/******/
188189
/******/ if (oldTag) {
189190
/******/ oldTag.parentNode.insertBefore(linkTag, oldTag.nextSibling);
190191
/******/ } else {

test/hooks.test.js

+74
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
/* eslint-env browser */
2+
import path from "path";
3+
4+
import { Template } from "webpack";
5+
6+
import MiniCssExtractPlugin from "../src";
7+
8+
import { runInJsDom, compile, getCompiler } from "./helpers/index";
9+
10+
describe("hooks", () => {
11+
it(`beforeTagInsert`, async () => {
12+
const webpackCompiler = getCompiler(
13+
"insert.js",
14+
{},
15+
{
16+
mode: "none",
17+
output: {
18+
publicPath: "",
19+
path: path.resolve(__dirname, "../outputs"),
20+
filename: "[name].bundle.js",
21+
},
22+
plugins: [
23+
new MiniCssExtractPlugin({
24+
filename: "[name].css",
25+
}),
26+
{
27+
/**
28+
*
29+
* @param {import('webpack').Compiler} compiler
30+
*/
31+
apply: (compiler) => {
32+
compiler.hooks.compilation.tap("sri", (compilation) => {
33+
MiniCssExtractPlugin.getCompilationHooks(
34+
compilation
35+
).beforeTagInsert.tap("sri", (source, varNames) =>
36+
Template.asString([
37+
source,
38+
`${varNames.tag}.setAttribute("integrity", "sriHashes[${varNames.chunkId}]");`,
39+
])
40+
);
41+
});
42+
},
43+
},
44+
{
45+
/**
46+
*
47+
* @param {import('webpack').Compiler} compiler
48+
*/
49+
apply: (compiler) => {
50+
compiler.hooks.compilation.tap("href", (compilation) => {
51+
MiniCssExtractPlugin.getCompilationHooks(
52+
compilation
53+
).beforeTagInsert.tap("changeHref", (source, varNames) =>
54+
Template.asString([
55+
source,
56+
`${varNames.tag}.setAttribute("href", "https://github.com/webpack-contrib/mini-css-extract-plugin");`,
57+
])
58+
);
59+
});
60+
},
61+
},
62+
],
63+
}
64+
);
65+
const stats = await compile(webpackCompiler);
66+
runInJsDom("main.bundle.js", webpackCompiler, stats, (dom) => {
67+
const [tag] = dom.window.document.head.getElementsByTagName("link");
68+
expect(tag.getAttribute("integrity")).toBe("sriHashes[chunkId]");
69+
expect(tag.getAttribute("href")).toBe(
70+
"https://github.com/webpack-contrib/mini-css-extract-plugin"
71+
);
72+
});
73+
});
74+
});

types/hooks.d.ts

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
export function getCompilationHooks(
2+
compilation: Compilation
3+
): MiniCssExtractPluginCompilationHooks;
4+
export type Compilation = import("webpack").Compilation;
5+
export type VarNames = {
6+
tag: string;
7+
chunkId: string;
8+
href: string;
9+
resolve: string;
10+
reject: string;
11+
};
12+
export type MiniCssExtractPluginCompilationHooks = {
13+
beforeTagInsert: import("tapable").SyncWaterfallHook<
14+
[string, VarNames],
15+
string
16+
>;
17+
};

types/index.d.ts

+8-1
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,13 @@ declare class MiniCssExtractPlugin {
1212
static getCssDependency(
1313
webpack: Compiler["webpack"]
1414
): CssDependencyConstructor;
15+
/**
16+
* Returns all hooks for the given compilation
17+
* @param {Compilation} compilation
18+
*/
19+
static getCompilationHooks(
20+
compilation: Compilation
21+
): import("./hooks").MiniCssExtractPluginCompilationHooks;
1522
/**
1623
* @param {PluginOptions} [options]
1724
*/
@@ -103,6 +110,7 @@ type CssDependencyConstructor = new (
103110
context: string | null,
104111
identifierIndex: number
105112
) => CssDependency;
113+
type Compilation = import("webpack").Compilation;
106114
type PluginOptions = {
107115
filename?: Required<Configuration>["output"]["filename"];
108116
chunkFilename?: Required<Configuration>["output"]["chunkFilename"];
@@ -166,7 +174,6 @@ declare const pluginName: "mini-css-extract-plugin";
166174
declare const pluginSymbol: unique symbol;
167175
declare var loader: string;
168176
type Schema = import("schema-utils/declarations/validate").Schema;
169-
type Compilation = import("webpack").Compilation;
170177
type ChunkGraph = import("webpack").ChunkGraph;
171178
type Chunk = import("webpack").Chunk;
172179
type ChunkGroup = Parameters<import("webpack").Chunk["isInGroup"]>[0];

0 commit comments

Comments
 (0)