Skip to content

Commit

Permalink
feat: support systemjs
Browse files Browse the repository at this point in the history
  • Loading branch information
JLHwung committed Sep 22, 2020
1 parent d14e481 commit 425637a
Show file tree
Hide file tree
Showing 12 changed files with 147 additions and 19 deletions.
Expand Up @@ -16,6 +16,7 @@
"@babel/helper-hoist-variables": "workspace:^7.10.4",
"@babel/helper-module-transforms": "workspace:^7.10.5",
"@babel/helper-plugin-utils": "workspace:^7.10.4",
"@babel/helper-validator-identifier": "workspace:^7.10.4",
"babel-plugin-dynamic-import-node": "^2.3.3"
},
"keywords": [
Expand Down
88 changes: 69 additions & 19 deletions packages/babel-plugin-transform-modules-systemjs/src/index.js
Expand Up @@ -3,6 +3,7 @@ import hoistVariables from "@babel/helper-hoist-variables";
import { template, types as t } from "@babel/core";
import { getImportSource } from "babel-plugin-dynamic-import-node/utils";
import { rewriteThis, getModuleName } from "@babel/helper-module-transforms";
import { isIdentifierName } from "@babel/helper-validator-identifier";

const buildTemplate = template(`
SYSTEM_REGISTER(MODULE_NAME, SOURCES, function (EXPORT_IDENTIFIER, CONTEXT_IDENTIFIER) {
Expand All @@ -29,12 +30,50 @@ WARNING: Dynamic import() transformation must be enabled using the
no longer transform import() without using that plugin.
`;

//todo: use getExportSpecifierName in `helper-module-transforms` when this library is refactored to NodePath usage.

export function getExportSpecifierName(
node: Node,
stringSpecifiers: Set<string>,
): string {
if (node.type === "Identifier") {
return node.name;
} else if (node.type === "StringLiteral") {
const stringValue = node.value;
// add specifier value to `stringSpecifiers` only when it can not be converted to an identifier name
// i.e In `import { "foo" as bar }`
// we do not consider `"foo"` to be a `stringSpecifier` because we can treat it as
// `import { foo as bar }`
// This helps minimize the size of `stringSpecifiers` and reduce overhead of checking valid identifier names
// when building transpiled code from metadata
if (!isIdentifierName(stringValue)) {
stringSpecifiers.add(stringValue);
}
return stringValue;
} else {
throw new Error(
`Expected export specifier to be either Identifier or StringLiteral, got ${node.type}`,
);
}
}

type PluginState = {|
contextIdent: string,

// List of names that should only be printed as string literals.
// i.e. `import { "any unicode" as foo } from "some-module"`
// `stringSpecifiers` is Set(1) ["any unicode"]
// In most cases `stringSpecifiers` is an empty Set
stringSpecifiers: Set<string>,
|};

function constructExportCall(
path,
exportIdent,
exportNames,
exportValues,
exportStarTarget,
stringSpecifiers: Set<string>,
) {
const statements = [];
if (exportNames.length === 1) {
Expand All @@ -52,7 +91,12 @@ function constructExportCall(
const exportName = exportNames[i];
const exportValue = exportValues[i];
objectProperties.push(
t.objectProperty(t.identifier(exportName), exportValue),
t.objectProperty(
stringSpecifiers.has(exportName)
? t.stringLiteral(exportName)
: t.identifier(exportName),
exportValue,
),
);
}
statements.push(
Expand Down Expand Up @@ -179,7 +223,7 @@ export default declare((api, options) => {
},

visitor: {
CallExpression(path, state) {
CallExpression(path, state: PluginState) {
if (t.isImport(path.node.callee)) {
if (!this.file.has("@babel/plugin-proposal-dynamic-import")) {
console.warn(MISSING_PLUGIN_WARNING);
Expand All @@ -197,7 +241,7 @@ export default declare((api, options) => {
}
},

MetaProperty(path, state) {
MetaProperty(path, state: PluginState) {
if (
path.node.meta.name === "import" &&
path.node.property.name === "meta"
Expand Down Expand Up @@ -228,14 +272,15 @@ export default declare((api, options) => {
Program: {
enter(path, state) {
state.contextIdent = path.scope.generateUid("context");
state.stringSpecifiers = new Set();
if (!allowTopLevelThis) {
rewriteThis(path);
}
},
exit(path, state) {
exit(path, state: PluginState) {
const scope = path.scope;
const exportIdent = scope.generateUid("export");
const contextIdent = state.contextIdent;
const { contextIdent, stringSpecifiers } = state;

const exportMap = Object.create(null);
const modules = [];
Expand Down Expand Up @@ -389,28 +434,25 @@ export default declare((api, options) => {
const nodes = [];

for (const specifier of specifiers) {
const binding = scope.getBinding(specifier.local.name);
const { local, exported } = specifier;
const binding = scope.getBinding(local.name);
const exportedName = getExportSpecifierName(
exported,
stringSpecifiers,
);
// hoisted function export
if (
binding &&
t.isFunctionDeclaration(binding.path.node)
) {
exportNames.push(specifier.exported.name);
exportValues.push(t.cloneNode(specifier.local));
exportNames.push(exportedName);
exportValues.push(t.cloneNode(local));
}
// only globals also exported this way
else if (!binding) {
nodes.push(
buildExportCall(
specifier.exported.name,
specifier.local,
),
);
nodes.push(buildExportCall(exportedName, local));
}
addExportName(
specifier.local.name,
specifier.exported.name,
);
addExportName(local.name, exportedName);
}

path.replaceWithMultiple(nodes);
Expand Down Expand Up @@ -445,6 +487,7 @@ export default declare((api, options) => {
}

if (t.isImportSpecifier(specifier)) {
const { imported } = specifier;
setterBody.push(
t.expressionStatement(
t.assignmentExpression(
Expand All @@ -453,6 +496,7 @@ export default declare((api, options) => {
t.memberExpression(
t.identifier(target),
specifier.imported,
/* computed */ imported.type === "StringLiteral",
),
),
),
Expand All @@ -469,7 +513,11 @@ export default declare((api, options) => {
if (t.isExportAllDeclaration(node)) {
hasExportStar = true;
} else if (t.isExportSpecifier(node)) {
exportNames.push(node.exported.name);
const exportedName = getExportSpecifierName(
node.exported,
stringSpecifiers,
);
exportNames.push(exportedName);
exportValues.push(
t.memberExpression(t.identifier(target), node.local),
);
Expand All @@ -485,6 +533,7 @@ export default declare((api, options) => {
exportNames,
exportValues,
hasExportStar ? t.identifier(target) : null,
stringSpecifiers,
),
);
}
Expand Down Expand Up @@ -531,6 +580,7 @@ export default declare((api, options) => {
exportNames,
exportValues,
null,
stringSpecifiers,
),
);
}
Expand Down
@@ -0,0 +1 @@
export { foo as "some exports" } from "foo";
@@ -0,0 +1,10 @@
System.register(["foo"], function (_export, _context) {
"use strict";

return {
setters: [function (_foo) {
_export("some exports", _foo.foo);
}],
execute: function () {}
};
});
@@ -0,0 +1,2 @@
var foo, bar;
export {foo as "defaultExports", bar};
@@ -0,0 +1,15 @@
System.register([], function (_export, _context) {
"use strict";

var foo, bar;

_export({
foo: void 0,
bar: void 0
});

return {
setters: [],
execute: function () {}
};
});
@@ -0,0 +1,2 @@
var foo, bar;
export {foo as "default exports", bar};
@@ -0,0 +1,15 @@
System.register([], function (_export, _context) {
"use strict";

var foo, bar;

_export({
foo: void 0,
bar: void 0
});

return {
setters: [],
execute: function () {}
};
});
@@ -0,0 +1,3 @@
import { "defaultImports" as bar} from "foo";

bar;
@@ -0,0 +1,13 @@
System.register(["foo"], function (_export, _context) {
"use strict";

var bar;
return {
setters: [function (_foo) {
bar = _foo["defaultImports"];
}],
execute: function () {
bar;
}
};
});
@@ -0,0 +1,3 @@
import {"default imports" as bar} from "foo";

bar;
@@ -0,0 +1,13 @@
System.register(["foo"], function (_export, _context) {
"use strict";

var bar;
return {
setters: [function (_foo) {
bar = _foo["default imports"];
}],
execute: function () {
bar;
}
};
});

0 comments on commit 425637a

Please sign in to comment.