transform non-default imports and exports using babel

since they are not supported by njs.

polyfill also added
This commit is contained in:
Miao Wang 2024-04-15 12:40:36 +08:00
parent d2f1d2d75b
commit 88adaa9ba4
5 changed files with 124 additions and 0 deletions

33
_src/babel-njs/hooks.mjs Normal file
View File

@ -0,0 +1,33 @@
const commonJSHooksKey =
"transform-njs-module/customWrapperPlugin";
export function defineCommonJSHook(file, hook) {
let hooks = file.get(commonJSHooksKey);
if (!hooks) file.set(commonJSHooksKey, (hooks = []));
hooks.push(hook);
}
function findMap(arr, cb) {
if (arr) {
for (const el of arr) {
const res = cb(el);
if (res != null) return res;
}
}
}
export function makeInvokers(file){
const hooks = file.get(commonJSHooksKey);
return {
getWrapperPayload(...args) {
return findMap(hooks, hook => hook.getWrapperPayload?.(...args));
},
wrapReference(...args) {
return findMap(hooks, hook => hook.wrapReference?.(...args));
},
buildRequireWrapper(...args) {
return findMap(hooks, hook => hook.buildRequireWrapper?.(...args));
},
};
}

88
_src/babel-njs/index.mjs Normal file
View File

@ -0,0 +1,88 @@
import { declare } from "@babel/helper-plugin-utils";
import {
isModule,
rewriteModuleStatementsAndPrepareHeader,
isSideEffectImport,
buildNamespaceInitStatements,
ensureStatementsHoisted,
wrapInterop,
getModuleName,
} from "@babel/helper-module-transforms";
import { template, types as t } from "@babel/core";
import { makeInvokers } from "./hooks.mjs";
export default declare((api) => {
return {
name: "transform-njs-module",
visitor: {
Program: {
exit(path, state) {
if (!isModule(path)) return;
// Rename the bindings auto-injected into the scope so there is no
// risk of conflict between the bindings.
path.scope.rename("exports");
let moduleName = getModuleName(this.file.opts, {});
// @ts-expect-error todo(flow->ts): do not reuse variables
if (moduleName) moduleName = t.stringLiteral(moduleName);
const hooks = makeInvokers(this.file);
const { meta, headers } = rewriteModuleStatementsAndPrepareHeader(
path,
{
exportName: "exports",
constantReexports: true,
enumerableModuleMeta: true,
strict: true,
strictMode: true,
allowTopLevelThis: true,
importInterop: "none",
wrapReference: hooks.wrapReference,
getWrapperPayload: hooks.getWrapperPayload,
esNamespaceOnly: true,
filename: this.file.opts.filename,
},
);
headers.unshift(...template.statements.ast(`
const exports = {};
export default exports;
`));
for (const [source, metadata] of meta.source) {
let header;
if (isSideEffectImport(metadata)) {
header = t.importDeclaration([], t.stringLiteral(source));
} else {
header = t.importDeclaration([t.importDefaultSpecifier(t.identifier(metadata.name))], t.stringLiteral(source));
}
header.loc = metadata.loc;
headers.push(header);
headers.push(
...buildNamespaceInitStatements(
meta,
metadata,
hooks.wrapReference,
),
);
}
ensureStatementsHoisted(headers);
path.unshiftContainer("body", headers);
path.get("body").forEach(path => {
if (headers.indexOf(path.node) === -1) return;
if (path.isVariableDeclaration()) {
path.scope.registerDeclaration(path);
}
});
},
},
},
};
});

View File

@ -1,3 +1,4 @@
import "../lib/njs-polyfill.js";
import Mark from "markup-js";
import processingHandlers from "../lib/mirrorListDataProcessing";
import { TUNASYNC_JSON_PATH } from "../lib/consts";

1
_src/lib/njs-polyfill.js Normal file
View File

@ -0,0 +1 @@
import "core-js/modules/es.object.from-entries";

View File

@ -182,6 +182,7 @@ export default defineConfig(({ mode }) => ({
"babel-preset-njs",
],
plugins: [
"./_src/babel-njs/index.mjs",
],
configFile: false,
}),