mirror of
https://github.com/discourse/discourse.git
synced 2026-08-06 01:10:43 +08:00
1. Remove 'federated exports' system, which was named entrypoint exports
for every module inside the plugin. Replace it with a single import of
the target plugin's 'compatModules', and then update call sites to do a
'just in time' lookup of the module and export. This is implemented in a
new `babel-resolve-plugin-imports` plugin
2. Update theme & plugin build systems to produce a list of external
plugins which are imported. For plugins, it's stored in the manifest.
For themes, it's stored in a new column of the javascript_caches table.
3. Refactor theme extra_js loading to use a more structured data model,
and move the HTML generation to the erb template
4. Update core importmap to identify any missing plugin dependencies and
add a fake placeholder module for them. This allows optional imports to
exist without causing a boot error. The imported values will resolve to
'null'.
5. Update core plugins to remove use of `optionalRequire`, and replace
it with regular imports, and a `with { discourseImport: "optional" }`
suffix. This is functionally equivalent to optionalRequire, but without
leaning on the legacy `loader.js` system of core
6. Add support for `with { discourseImport: "optional" }` for
plugins/themes importing core modules. This is useful when a
theme/plugin needs to target multiple versions of Discourse core.
Co-authored-by: Jarek Radosz <jarek@cvx.dev>
76 lines
2.3 KiB
JavaScript
Vendored
76 lines
2.3 KiB
JavaScript
Vendored
import { readDiscourseImportMode } from "./discourse-import-attribute";
|
|
import rollupVirtualImports from "./rollup-virtual-imports";
|
|
|
|
export default function (babel) {
|
|
const { types: t } = babel;
|
|
|
|
const declare = (id, init) =>
|
|
t.variableDeclaration("const", [t.variableDeclarator(id, init)]);
|
|
|
|
return {
|
|
manipulateOptions(_opts, parserOpts) {
|
|
// Allow the `with { discourseImport: ... }` attribute to parse.
|
|
if (!parserOpts.plugins.includes("importAttributes")) {
|
|
parserOpts.plugins.push("importAttributes");
|
|
}
|
|
},
|
|
visitor: {
|
|
ImportDeclaration(path) {
|
|
const moduleName = path.node.source.value;
|
|
if (
|
|
moduleName.startsWith(".") ||
|
|
rollupVirtualImports[moduleName] ||
|
|
moduleName.startsWith("discourse/theme-") ||
|
|
moduleName.startsWith("discourse/plugins/")
|
|
) {
|
|
return;
|
|
}
|
|
|
|
// Core imports are required unless explicitly marked optional.
|
|
const optional = readDiscourseImportMode(path) === "optional";
|
|
|
|
const lookup = () =>
|
|
t.callExpression(
|
|
t.memberExpression(
|
|
t.memberExpression(
|
|
t.identifier("window"),
|
|
t.identifier("moduleBroker")
|
|
),
|
|
t.identifier("lookup")
|
|
),
|
|
optional
|
|
? [t.stringLiteral(moduleName), t.booleanLiteral(true)]
|
|
: [t.stringLiteral(moduleName)]
|
|
);
|
|
|
|
const replacements = [];
|
|
const properties = [];
|
|
|
|
for (const specifier of path.node.specifiers) {
|
|
if (specifier.type === "ImportNamespaceSpecifier") {
|
|
replacements.push(
|
|
declare(t.identifier(specifier.local.name), lookup())
|
|
);
|
|
} else {
|
|
const exportedName =
|
|
specifier.type === "ImportDefaultSpecifier"
|
|
? "default"
|
|
: specifier.imported.name;
|
|
properties.push(
|
|
t.objectProperty(
|
|
t.identifier(exportedName),
|
|
t.identifier(specifier.local.name)
|
|
)
|
|
);
|
|
}
|
|
}
|
|
|
|
if (properties.length) {
|
|
replacements.unshift(declare(t.objectPattern(properties), lookup()));
|
|
}
|
|
|
|
path.replaceWithMultiple(replacements);
|
|
},
|
|
},
|
|
};
|
|
}
|