8000 feat: add function support for locals (loader) (#985) · opadilla/mini-css-extract-plugin@65519d0 · GitHub
Skip to content

Commit 65519d0

Browse files
authored
feat: add function support for locals (loader) (webpack-contrib#985)
1 parent 418fd09 commit 65519d0

File tree

9 files changed

+177
-6
lines changed

9 files changed

+177
-6
lines changed

src/loader.js

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ const {
88
BASE_URI,
99
SINGLE_DOT_PATH_SEGMENT,
1010
stringifyRequest,
11+
stringifyLocal,
1112
} = require("./utils");
1213
const schema = require("./loader-options.json");
1314

@@ -22,6 +23,7 @@ const MiniCssExtractPlugin = require("./index");
2223
/** @typedef {import("webpack").AssetInfo} AssetInfo */
2324
/** @typedef {import("webpack").NormalModule} NormalModule */
2425
/** @typedef {import("./index.js").LoaderOptions} LoaderOptions */
26+
/** @typedef {{ [key: string]: string | function }} Locals */
2527

2628
/** @typedef {any} TODO */
2729

@@ -38,7 +40,7 @@ const MiniCssExtractPlugin = require("./index");
3840

3941
/**
4042
* @param {string} content
41-
* @param {{ loaderContext: import("webpack").LoaderContext<LoaderOptions>, options: LoaderOptions, locals: {[key: string]: string } | undefined }} context
43+
* @param {{ loaderContext: import("webpack").LoaderContext<LoaderOptions>, options: LoaderOptions, locals: Locals | undefined }} context
4244
* @returns {string}
4345
*/
4446
function hotLoader(content, context) {
@@ -95,7 +97,7 @@ function pitch(request) {
9597
* @returns {void}
9698
*/
9799
const handleExports = (originalExports, compilation, assets, assetsInfo) => {
98-
/** @type {{[key: string]: string } | undefined} */
100+
/** @type {Locals | undefined} */
99101
let locals;
100102
let namedExport;
101103

@@ -170,7 +172,7 @@ function pitch(request) {
170172
locals = {};
171173
}
172174

173-
locals[key] = originalExports[key];
175+
/** @type {Locals} */ (locals)[key] = originalExports[key];
174176
}
175177
});
176178
} else {
@@ -228,9 +230,8 @@ function pitch(request) {
228230
? Object.keys(locals)
229231
.map(
230232
(key) =>
231-
`\nexport var ${key} = ${JSON.stringify(
232-
/** @type {{[key: string]: string }} */
233-
(locals)[key]
233+
`\nexport var ${key} = ${stringifyLocal(
234+
/** @type {Locals} */ (locals)[key]
234235
)};`
235236
)
236237
.join("")

src/utils.js

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -205,6 +205,15 @@ function getUndoPath(filename, outputPath, enforceRelative) {
205205
: append;
206206
}
207207

208+
/**
209+
*
210+
* @param {string | function} value
211+
* @returns {string}
212+
*/
213+
function stringifyLocal(value) {
214+
return typeof value === "function" ? value.toString() : JSON.stringify(value);
215+
}
216+
208217
module.exports = {
209218
trueFn,
210219
findModuleById,
@@ -216,5 +225,6 @@ module.exports = {
216225
BASE_URI,
217226
SINGLE_DOT_PATH_SEGMENT,
218227
stringifyRequest,
228+
stringifyLocal,
219229
getUndoPath,
220230
};
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import { cnA, cnB } from "./style.css";
2+
3+
// eslint-disable-next-line no-console
4+
console.log(cnA(), cnB());
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
export default function loader() {
2+
const callback = this.async();
3+
4+
callback(
5+
null,
6+
`export default [
7+
[module.id, ".class-name-a {background: red;}", ""],
8+
[module.id, ".class-name-b {background: blue;}", ""],
9+
];
10+
11+
export var cnA = () => "class-name-a";
12+
export var cnB = () => "class-name-b";`
13+
);
14+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
.class-name-a {
2+
background: red;
3+
}
4+
5+
.class-name-b {
6+
background: blue;
7+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
.class-name-a {background: red;}
2+
.class-name-b {background: blue;}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
import path from "path";
2+
3+
import Self from "../../../src";
4+
5+
module.exports = {
6+
entry: "./index.js",
7+
context: path.resolve(__dirname, "app"),
8+
module: {
9+
rules: [
10+
{
11+
test: /\.css$/,
12+
use: [Self.loader, "./mockLoader"],
13+
},
14+
],
15+
},
16+
plugins: [
17+
new Self({
18+
filename: "[name].css",
19+
}),
20+
],
21+
};

test/stringifyLocal.test.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import { stringifyLocal } from "../src/utils";
2+
3+
describe("stringifyLocal", () => {
4+
it(`primitive`, async () => {
5+
const testObj = "classA";
6+
7+
expect(stringifyLocal(testObj)).toBe('"classA"');
8+
});
9+
10+
it(`arrow function`, async () => {
11+
const testFn = () => "classA";
12+
13+
expect(stringifyLocal(testFn)).toBe('() => "classA"');
14+
});
15+
16+
it(`function`, async () => {
17+
const testFn = function () {
18+
return "classA";
19+
};
20+
21+
expect(stringifyLocal(testFn)).toBe(
22+
'function () {\n return "classA";\n }'
23+
);
24+
});
25+
});

0 commit comments

Comments
 (0)