Skip to content

Commit b86ed75

Browse files
committed
feat: add beforeTagInsert hook
1 parent d5e540b commit b86ed75

File tree

9 files changed

+157
-8
lines changed

9 files changed

+157
-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": [

package-lock.json

+3-4
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

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/** @typedef {import("webpack").Compiler} WebpackCompiler */
2+
/**
3+
* @typedef {Object} MiniCssExtractHooks
4+
* @property {import("tapable").SyncBailHook<{ varNames: { tag: string, chunkId: string } }, string>} [beforeTagInsert]
5+
*/
6+
7+
const { SyncBailHook } = require("tapable");
8+
9+
/**
10+
* @type {WeakMap<WebpackCompiler, MiniCssExtractHooks>}}
11+
*/
12+
const miniCssExtractHooksMap = new WeakMap();
13+
14+
/**
15+
* @param {WebpackCompiler} complier
16+
*/
17+
function getHooks(complier) {
18+
let hooks = miniCssExtractHooksMap.get(complier);
19+
// Setup the hooks only once
20+
if (!hooks) {
21+
hooks = createHooks();
22+
miniCssExtractHooksMap.set(complier, hooks);
23+
}
24+
return hooks;
25+
}
26+
27+
/**
28+
* @returns {MiniCssExtractHooks}
29+
*/
30+
function createHooks() {
31+
return {
32+
beforeTagInsert: new SyncBailHook(["vars"]),
33+
};
34+
}
35+
36+
module.exports = {
37+
getHooks,
38+
};

src/index.js

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

1920
/** @typedef {import("schema-utils/declarations/validate").Schema} Schema */
2021
/** @typedef {import("webpack").Compiler} Compiler */
@@ -511,6 +512,14 @@ class MiniCssExtractPlugin {
511512
return CssDependency;
512513
}
513514

515+
/**
516+
* Returns all hooks for the given compiler
517+
* @param {Compiler} compiler
518+
*/
519+
static getHooks(compiler) {
520+
return getHooks(compiler);
521+
}
522+
514523
/**
515524
* @param {PluginOptions} [options]
516525
*/
@@ -838,7 +847,6 @@ class MiniCssExtractPlugin {
838847
if (!withLoading && !withHmr) {
839848
return "";
840849
}
841-
842850
return Template.asString([
843851
'if (typeof document === "undefined") return;',
844852
`var createStylesheet = ${runtimeTemplate.basicFunction(
@@ -895,6 +903,12 @@ class MiniCssExtractPlugin {
895903
"}",
896904
])
897905
: "",
906+
MiniCssExtractPlugin.getHooks(compiler).beforeTagInsert?.call({
907+
varNames: {
908+
chunkId: "chunkId",
909+
tag: "linkTag",
910+
},
911+
}),
898912
typeof this.runtimeOptions.insert !== "undefined"
899913
? typeof this.runtimeOptions.insert === "function"
900914
? `(${this.runtimeOptions.insert.toString()})(linkTag)`
@@ -912,7 +926,7 @@ class MiniCssExtractPlugin {
912926
"}",
913927
]),
914928
"return linkTag;",
915-
]
929+
].filter((statement) => statement !== undefined)
916930
)};`,
917931
`var findStylesheet = ${runtimeTemplate.basicFunction(
918932
"href, fullhref",

test/api.test.js

+27
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
1+
import path from "path";
2+
13
import webpack from "webpack";
24

35
import MiniCssExtractPlugin from "../src";
46

7+
import { getCompiler } from "./helpers/index";
8+
59
describe("API", () => {
610
it("should return the same CssModule when same webpack instance provided", () => {
711
expect(MiniCssExtractPlugin.getCssModule(webpack)).toEqual(
@@ -14,4 +18,27 @@ describe("API", () => {
1418
MiniCssExtractPlugin.getCssDependency(webpack)
1519
);
1620
});
21+
22+
it("should return the same Hooks when same webpack instance provided", () => {
23+
const compiler = getCompiler(
24+
"insert.js",
25+
{},
26+
{
27+
mode: "none",
28+
output: {
29+
publicPath: "",
30+
path: path.resolve(__dirname, "../outputs"),
31+
filename: "[name].bundle.js",
32+
},
33+
plugins: [
34+
new MiniCssExtractPlugin({
35+
filename: "[name].css",
36+
}),
37+
],
38+
}
39+
);
40+
expect(MiniCssExtractPlugin.getHooks(compiler)).toEqual(
41+
MiniCssExtractPlugin.getHooks(compiler)
42+
);
43+
});
1744
});

test/hooks.test.js

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
/* eslint-env browser */
2+
import path from "path";
3+
4+
import MiniCssExtractPlugin from "../src";
5+
6+
import { runInJsDom, compile, getCompiler } from "./helpers/index";
7+
8+
describe("hooks", () => {
9+
it(`beforeTagInsert`, async () => {
10+
const webpackCompiler = getCompiler(
11+
"insert.js",
12+
{},
13+
{
14+
mode: "none",
15+
output: {
16+
publicPath: "",
17+
path: path.resolve(__dirname, "../outputs"),
18+
filename: "[name].bundle.js",
19+
},
20+
plugins: [
21+
new MiniCssExtractPlugin({
22+
filename: "[name].css",
23+
}),
24+
{
25+
apply: (compiler) => {
26+
MiniCssExtractPlugin.getHooks(compiler).beforeTagInsert.tap(
27+
"beforeTagInsertHook",
28+
(options) =>
29+
`${options.varNames.tag}.setAttribute("integrity", "sriHashes")`
30+
);
31+
},
32+
},
33+
],
34+
}
35+
);
36+
const stats = await compile(webpackCompiler);
37+
runInJsDom("main.bundle.js", webpackCompiler, stats, (dom) => {
38+
const integrity = dom.window.document.head
39+
.getElementsByTagName("link")[0]
40+
.getAttribute("integrity");
41+
expect(integrity).toBe("sriHashes");
42+
});
43+
});
44+
});

types/hooks.d.ts

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
export type WebpackCompiler = import("webpack").Compiler;
2+
export type MiniCssExtractHooks = {
3+
beforeTagInsert?:
4+
| SyncBailHook<
5+
{
6+
varNames: {
7+
tag: string;
8+
chunkId: string;
9+
};
10+
},
11+
string,
12+
import("tapable").UnsetAdditionalOptions
13+
>
14+
| undefined;
15+
};
16+
/**
17+
* @param {WebpackCompiler} complier
18+
*/
19+
export function getHooks(complier: WebpackCompiler): MiniCssExtractHooks;
20+
import { SyncBailHook } from "tapable";

types/index.d.ts

+5
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,11 @@ declare class MiniCssExtractPlugin {
1212
static getCssDependency(
1313
webpack: Compiler["webpack"]
1414
): CssDependencyConstructor;
15+
/**
16+
* Returns all hooks for the given compiler
17+
* @param {Compiler} compiler
18+
*/
19+
static getHooks(compiler: Compiler): import("./hooks").MiniCssExtractHooks;
1520
/**
1621
* @param {PluginOptions} [options]
1722
*/

0 commit comments

Comments
 (0)