Skip to content

Commit

Permalink
Merge pull request #25540 from mlazari/next
Browse files Browse the repository at this point in the history
Webpack5: Make export-order-loader compatible with both esm and cjs
(cherry picked from commit dfb08da)
  • Loading branch information
valentinpalkovic authored and JReinhold committed Jan 16, 2024
1 parent abaa634 commit 2f96d0f
Show file tree
Hide file tree
Showing 3 changed files with 287 additions and 72 deletions.
1 change: 1 addition & 0 deletions code/builders/builder-webpack5/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,7 @@
"babel-loader": "^9.0.0",
"browser-assert": "^1.2.1",
"case-sensitive-paths-webpack-plugin": "^2.4.0",
"cjs-module-lexer": "^1.2.3",
"constants-browserify": "^1.0.0",
"css-loader": "^6.7.1",
"es-module-lexer": "^1.4.1",
Expand Down
66 changes: 45 additions & 21 deletions code/builders/builder-webpack5/src/loaders/export-order-loader.ts
Original file line number Diff line number Diff line change
@@ -1,34 +1,58 @@
import { parse } from 'es-module-lexer';
import assert from 'assert';
import { parse as parseCjs, init as initCjsParser } from 'cjs-module-lexer';
import { parse as parseEs } from 'es-module-lexer';
import MagicString from 'magic-string';
import type { LoaderContext } from 'webpack';

export default async function loader(this: LoaderContext<any>, source: string) {
export default async function loader(
this: LoaderContext<any>,
source: string,
map: any,
meta: any
) {
const callback = this.async();

try {
// Do NOT remove await here. The types are wrong! It has to be awaited,
// otherwise it will return a Promise<Promise<...>> when wasm isn't loaded.
const [, exports = []] = await parse(source);
const magicString = new MagicString(source);

// Trying to parse as ES module
try {
// Do NOT remove await here. The types are wrong! It has to be awaited,
// otherwise it will return a Promise<Promise<...>> when wasm isn't loaded.
const parseResult = await parseEs(source);
const namedExportsOrder = (parseResult[1] || [])
.map((e) => source.substring(e.s, e.e))
.filter((e) => e !== 'default');

assert(
namedExportsOrder.length > 0,
'No named exports found. Very likely that this is not a ES module.'
);

const namedExportsOrder = exports.some(
(e) => source.substring(e.s, e.e) === '__namedExportsOrder'
);
magicString.append(
`;export const __namedExportsOrder = ${JSON.stringify(namedExportsOrder)};`
);
// Try to parse as CJS module
} catch {
await initCjsParser();
const namedExportsOrder = (parseCjs(source).exports || []).filter(
(e: string) => e !== 'default' && e !== '__esModule'
);

if (namedExportsOrder) {
return callback(null, source);
assert(
namedExportsOrder.length > 0,
'No named exports found. Very likely that this is not a CJS module.'
);

magicString.append(
`;module.exports.__namedExportsOrder = ${JSON.stringify(namedExportsOrder)};`
);
}

const magicString = new MagicString(source);
const orderedExports = exports.filter((e) => source.substring(e.s, e.e) !== 'default');
magicString.append(
`;export const __namedExportsOrder = ${JSON.stringify(
orderedExports.map((e) => source.substring(e.s, e.e))
)};`
);

const map = magicString.generateMap({ hires: true });
return callback(null, magicString.toString(), map);
const generatedMap = magicString.generateMap({ hires: true });

return callback(null, magicString.toString(), generatedMap, meta);
} catch (err) {
return callback(err as any);
return callback(null, source, map, meta);
}
}
Loading

0 comments on commit 2f96d0f

Please sign in to comment.