From 5f0972908136eb69187e33c64fa68e6e13b97851 Mon Sep 17 00:00:00 2001 From: Marcel Laverdet Date: Tue, 24 Oct 2023 14:00:05 -0400 Subject: [PATCH] feat: support named exports with any characters A proposed change to `css-loader` will allow named exports to be any string, regardless of whether or not it is a valid identifier. The code generation in this project assumes that all exports will be a valid identifier, so the generation stage has been updated to take this into account. --- src/loader.js | 46 +++++++++++++------ .../expected/main.js | 10 ++-- .../expected/main.js | 20 +++++--- .../expected/main.mjs | 14 +++--- test/cases/es-named-export/expected/main.js | 14 +++--- .../expected/main.js | 14 +++--- 6 files changed, 74 insertions(+), 44 deletions(-) diff --git a/src/loader.js b/src/loader.js index 36b54386..0d2b701b 100644 --- a/src/loader.js +++ b/src/loader.js @@ -242,23 +242,39 @@ function pitch(request) { return; } - const result = locals - ? namedExport - ? Object.keys(locals) + const result = (function makeResult() { + // nb: `locals` is reassigned to const to improve TypeScript narrowing. + const scopeLocals = locals; + if (scopeLocals) { + if (namedExport) { + const identifiers = Array.from( + (function* generateIdentifiers() { + let identifierId = 0; + for (const key of Object.keys(scopeLocals)) { + identifierId += 1; + yield [`_${identifierId.toString(16)}`, key]; + } + })() + ); + const localsString = identifiers .map( - (key) => - `\nexport var ${key} = ${stringifyLocal( - /** @type {Locals} */ (locals)[key] - )};` + ([id, key]) => + `\nvar ${id} = ${stringifyLocal(scopeLocals[key])};` ) - .join("") - : `\n${ - esModule ? "export default" : "module.exports =" - } ${JSON.stringify(locals)};` - : esModule - ? `\nexport {};` - : ""; - + .join(""); + const exportsString = `export { ${identifiers + .map(([id, key]) => `${id} as ${JSON.stringify(key)}`) + .join(", ")} }`; + return `${localsString};\n${exportsString};\n`; + } + return `\n${ + esModule ? "export default" : "module.exports = " + } ${JSON.stringify(locals)};`; + } else if (esModule) { + return "\nexport {};"; + } + return ""; + })(); let resultSource = `// extracted by ${MiniCssExtractPlugin.pluginName}`; // only attempt hotreloading if the css is actually used for something other than hash values diff --git a/test/cases/custom-loader-with-functional-exports/expected/main.js b/test/cases/custom-loader-with-functional-exports/expected/main.js index a25ef24d..ee77a246 100644 --- a/test/cases/custom-loader-with-functional-exports/expected/main.js +++ b/test/cases/custom-loader-with-functional-exports/expected/main.js @@ -7,12 +7,14 @@ __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ cnA: () => (/* binding */ cnA), -/* harmony export */ cnB: () => (/* binding */ cnB) +/* harmony export */ cnA: () => (/* binding */ _1), +/* harmony export */ cnB: () => (/* binding */ _2) /* harmony export */ }); // extracted by mini-css-extract-plugin -var cnA = () => "class-name-a"; -var cnB = () => "class-name-b"; +var _1 = () => "class-name-a"; +var _2 = () => "class-name-b";; + + /***/ }) /******/ ]); diff --git a/test/cases/es-module-concatenation-modules/expected/main.js b/test/cases/es-module-concatenation-modules/expected/main.js index 71f38e53..8439fae1 100644 --- a/test/cases/es-module-concatenation-modules/expected/main.js +++ b/test/cases/es-module-concatenation-modules/expected/main.js @@ -41,21 +41,21 @@ __webpack_require__.r(__webpack_exports__); __webpack_require__.d(__webpack_exports__, { a: () => (/* reexport */ a_namespaceObject), b: () => (/* reexport */ b_namespaceObject), - c: () => (/* reexport */ c) + c: () => (/* reexport */ c_1) }); // NAMESPACE OBJECT: ./a.css var a_namespaceObject = {}; __webpack_require__.r(a_namespaceObject); __webpack_require__.d(a_namespaceObject, { - a: () => (a) + a: () => (_1) }); // NAMESPACE OBJECT: ./b.css var b_namespaceObject = {}; __webpack_require__.r(b_namespaceObject); __webpack_require__.d(b_namespaceObject, { - b: () => (b) + b: () => (b_1) }); // NAMESPACE OBJECT: ./index.js @@ -64,18 +64,24 @@ __webpack_require__.r(index_namespaceObject); __webpack_require__.d(index_namespaceObject, { a: () => (a_namespaceObject), b: () => (b_namespaceObject), - c: () => (c) + c: () => (c_1) }); ;// CONCATENATED MODULE: ./a.css // extracted by mini-css-extract-plugin -var a = "foo__a"; +var _1 = "foo__a";; + + ;// CONCATENATED MODULE: ./b.css // extracted by mini-css-extract-plugin -var b = "foo__b"; +var b_1 = "foo__b";; + + ;// CONCATENATED MODULE: ./c.css // extracted by mini-css-extract-plugin -var c = "foo__c"; +var c_1 = "foo__c";; + + ;// CONCATENATED MODULE: ./index.js /* eslint-disable import/no-namespace */ diff --git a/test/cases/es-named-export-output-module/expected/main.mjs b/test/cases/es-named-export-output-module/expected/main.mjs index 1f78824d..f3a8121b 100644 --- a/test/cases/es-named-export-output-module/expected/main.mjs +++ b/test/cases/es-named-export-output-module/expected/main.mjs @@ -5,14 +5,16 @@ __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ aClass: () => (/* binding */ aClass), -/* harmony export */ bClass: () => (/* binding */ bClass), -/* harmony export */ cClass: () => (/* binding */ cClass) +/* harmony export */ aClass: () => (/* binding */ _1), +/* harmony export */ bClass: () => (/* binding */ _2), +/* harmony export */ cClass: () => (/* binding */ _3) /* harmony export */ }); // extracted by mini-css-extract-plugin -var aClass = "foo__style__a-class"; -var bClass = "foo__style__b__class"; -var cClass = "foo__style__cClass"; +var _1 = "foo__style__a-class"; +var _2 = "foo__style__b__class"; +var _3 = "foo__style__cClass";; + + /***/ }) /******/ ]); diff --git a/test/cases/es-named-export/expected/main.js b/test/cases/es-named-export/expected/main.js index a5118432..9a65b177 100644 --- a/test/cases/es-named-export/expected/main.js +++ b/test/cases/es-named-export/expected/main.js @@ -7,14 +7,16 @@ __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ aClass: () => (/* binding */ aClass), -/* harmony export */ bClass: () => (/* binding */ bClass), -/* harmony export */ cClass: () => (/* binding */ cClass) +/* harmony export */ aClass: () => (/* binding */ _1), +/* harmony export */ bClass: () => (/* binding */ _2), +/* harmony export */ cClass: () => (/* binding */ _3) /* harmony export */ }); // extracted by mini-css-extract-plugin -var aClass = "foo__style__a-class"; -var bClass = "foo__style__b__class"; -var cClass = "foo__style__cClass"; +var _1 = "foo__style__a-class"; +var _2 = "foo__style__b__class"; +var _3 = "foo__style__cClass";; + + /***/ }) /******/ ]); diff --git a/test/cases/export-only-locals-and-es-named-export/expected/main.js b/test/cases/export-only-locals-and-es-named-export/expected/main.js index 15e05d5f..93a87ae2 100644 --- a/test/cases/export-only-locals-and-es-named-export/expected/main.js +++ b/test/cases/export-only-locals-and-es-named-export/expected/main.js @@ -7,14 +7,16 @@ __webpack_require__.r(__webpack_exports__); /* harmony export */ __webpack_require__.d(__webpack_exports__, { -/* harmony export */ aClass: () => (/* binding */ aClass), -/* harmony export */ bClass: () => (/* binding */ bClass), -/* harmony export */ cClass: () => (/* binding */ cClass) +/* harmony export */ aClass: () => (/* binding */ _1), +/* harmony export */ bClass: () => (/* binding */ _2), +/* harmony export */ cClass: () => (/* binding */ _3) /* harmony export */ }); // extracted by mini-css-extract-plugin -var aClass = "foo__style__a-class"; -var bClass = "foo__style__b__class"; -var cClass = "foo__style__cClass"; +var _1 = "foo__style__a-class"; +var _2 = "foo__style__b__class"; +var _3 = "foo__style__cClass";; + + /***/ }) /******/ ]);