mirror of
https://github.com/discourse/discourse.git
synced 2026-08-04 10:39:43 +08:00
DEV: Keep styleguide samples synchronized with source Styleguide code samples were hand-written strings that could silently drift from the markup they described. This caused the char counter sample to advertise a nonexistent `CharCounter` module while rendering `DCharCounter`. Add a `discourse-source-imports` bundler plugin that imports another module's untranspiled source as a string. `?source=file` returns the complete file, while `?source=template` extracts the contents of the module's single `<template>` block. Imports use normal module resolution and pass the result to `StyleguideExample` through its `@code` argument. Move the spinner and char counter examples into `components/examples/` and source their displayed code through the new plugin. Register the plugin with both the core Rolldown build and the asset processor. Each pipeline injects its own `readSource(id)` implementation: the asset processor reads from its in-memory module map, while core reads from disk and rejects paths outside the project root. --------- Co-authored-by: David Taylor <david@taylorhq.com>
191 lines
6 KiB
JavaScript
Vendored
191 lines
6 KiB
JavaScript
Vendored
import BabelTransformTypescript from "@babel/plugin-transform-typescript";
|
|
import BabelPresetEnv from "@babel/preset-env";
|
|
import { rollup } from "@rollup/browser";
|
|
import { babel, getBabelOutputPlugin } from "@rollup/plugin-babel";
|
|
import HTMLBarsInlinePrecompile from "babel-plugin-ember-template-compilation";
|
|
import DecoratorTransforms from "decorator-transforms";
|
|
import colocatedBabelPlugin from "ember-cli-htmlbars/lib/colocated-babel-plugin";
|
|
import { precompile } from "ember-source/ember-template-compiler/index.js";
|
|
import EmberThisFallback from "ember-this-fallback";
|
|
import StripTestSelectorsPlugin from "strip-test-selectors/src/strip-test-selectors";
|
|
import { browsers } from "../discourse/config/targets";
|
|
import babelTransformModuleRenames from "../discourse/lib/babel-transform-module-renames";
|
|
import discourseSourceImports from "../discourse/lib/discourse-source-imports.mjs";
|
|
import AddThemeGlobals from "./add-theme-globals";
|
|
import BabelResolveCoreImports from "./babel-resolve-core-imports";
|
|
import BabelResolvePluginImports from "./babel-resolve-plugin-imports";
|
|
import discourseColocation from "./rollup-plugins/discourse-colocation";
|
|
import discourseExternalLoader from "./rollup-plugins/discourse-external-loader";
|
|
import discourseFileSearch from "./rollup-plugins/discourse-file-search";
|
|
import discourseGjs from "./rollup-plugins/discourse-gjs";
|
|
import discourseHbs from "./rollup-plugins/discourse-hbs";
|
|
import discourseTerser from "./rollup-plugins/discourse-terser";
|
|
import discourseVirtualLoader from "./rollup-plugins/discourse-virtual-loader";
|
|
import buildEmberTemplateManipulatorPlugin from "./theme-hbs-ast-transforms";
|
|
import transformActionSyntax from "./transform-action-syntax";
|
|
import createVirtualFs from "./virtual-fs";
|
|
|
|
let lastRollupResult;
|
|
let lastRollupError;
|
|
|
|
let caches = new Map();
|
|
|
|
async function performRollup(modules, opts) {
|
|
let basePath = opts.pluginName
|
|
? `discourse/plugins/${opts.pluginName}/`
|
|
: `theme-${opts.themeId}/`;
|
|
|
|
const inputConfig = {};
|
|
|
|
for (const key of Object.keys(opts.entrypoints)) {
|
|
inputConfig[key] = `virtual:entrypoint:${key}`;
|
|
}
|
|
|
|
const fs = createVirtualFs(modules, basePath);
|
|
|
|
const cache = opts.pluginName ? caches.get(opts.pluginName) : false;
|
|
|
|
const result = await rollup({
|
|
input: inputConfig,
|
|
logLevel: "info",
|
|
fs,
|
|
cache,
|
|
onLog(level, message) {
|
|
if (String(message).startsWith("Circular dependency")) {
|
|
return;
|
|
}
|
|
// eslint-disable-next-line no-console
|
|
console.info(level, message);
|
|
},
|
|
plugins: [
|
|
discourseSourceImports({ fs }),
|
|
discourseFileSearch(),
|
|
discourseVirtualLoader({
|
|
isTheme: !!opts.themeId,
|
|
basePath,
|
|
entrypoints: opts.entrypoints,
|
|
opts,
|
|
}),
|
|
discourseExternalLoader({ basePath }),
|
|
discourseColocation({ basePath }),
|
|
getBabelOutputPlugin({
|
|
plugins: [BabelResolveCoreImports, BabelResolvePluginImports],
|
|
compact: false,
|
|
}),
|
|
babel({
|
|
extensions: [".js", ".gjs", ".ts", ".gts", ".hbs"],
|
|
babelHelpers: "bundled",
|
|
compact: false,
|
|
// Support `import ... with { ... }` for cross-plugin imports
|
|
parserOpts: { plugins: ["importAttributes"] },
|
|
overrides: [
|
|
{
|
|
test: /\.(gts|ts|mts|cts)$/,
|
|
plugins: [[BabelTransformTypescript, { allowDeclareFields: true }]],
|
|
},
|
|
],
|
|
plugins: [
|
|
[DecoratorTransforms, { runEarly: true }],
|
|
opts.themeId ? AddThemeGlobals : null,
|
|
babelTransformModuleRenames,
|
|
colocatedBabelPlugin,
|
|
[
|
|
HTMLBarsInlinePrecompile,
|
|
{
|
|
compiler: { precompile },
|
|
enableLegacyModules: [
|
|
"ember-cli-htmlbars",
|
|
"ember-cli-htmlbars-inline-precompile",
|
|
"htmlbars-inline-precompile",
|
|
],
|
|
transforms: [
|
|
EmberThisFallback._buildPlugin({
|
|
enableLogging: false,
|
|
isTheme: true,
|
|
}).plugin,
|
|
buildEmberTemplateManipulatorPlugin(opts.themeId),
|
|
transformActionSyntax,
|
|
...(opts.minify ? [StripTestSelectorsPlugin] : []),
|
|
],
|
|
},
|
|
],
|
|
].filter(Boolean),
|
|
presets: [
|
|
[
|
|
BabelPresetEnv,
|
|
{
|
|
modules: false,
|
|
targets: { browsers },
|
|
},
|
|
],
|
|
],
|
|
}),
|
|
discourseHbs(),
|
|
discourseGjs(),
|
|
discourseTerser({ opts }),
|
|
],
|
|
});
|
|
|
|
const bundle = await result.generate({
|
|
format: "es",
|
|
sourcemap: "hidden",
|
|
importAttributesKey: "with",
|
|
entryFileNames: `${opts.filenamePrefix ?? ""}[name].[hash:6]${opts.filenameSuffix ?? ""}.js`,
|
|
chunkFileNames: `${opts.filenamePrefix ?? ""}chunk.[hash:6]${opts.filenameSuffix ?? ""}.js`,
|
|
});
|
|
|
|
if (opts.pluginName) {
|
|
caches.set(opts.pluginName, result.cache);
|
|
}
|
|
|
|
const externalPluginImports = [
|
|
...new Set(
|
|
bundle.output
|
|
.flatMap((c) => c.imports ?? [])
|
|
.filter((i) => i.startsWith("discourse/plugins/"))
|
|
.map((i) => i.split("/")[2])
|
|
),
|
|
];
|
|
|
|
const chunks = Object.fromEntries(
|
|
bundle.output
|
|
.filter((c) => c.code)
|
|
.map((chunk) => {
|
|
return [
|
|
chunk.fileName,
|
|
{
|
|
code: chunk.code,
|
|
map: JSON.stringify(chunk.map),
|
|
name: chunk.name,
|
|
isEntry: chunk.isEntry,
|
|
imports: chunk.imports.filter((i) =>
|
|
bundle.output.find((c) => c.fileName === i)
|
|
),
|
|
externalPluginImports,
|
|
},
|
|
];
|
|
})
|
|
);
|
|
|
|
return chunks;
|
|
}
|
|
|
|
globalThis.rollup = async function (modules, opts) {
|
|
try {
|
|
lastRollupResult = await performRollup(modules, opts);
|
|
} catch (error) {
|
|
lastRollupError = error;
|
|
}
|
|
};
|
|
|
|
globalThis.getRollupResult = function () {
|
|
const error = lastRollupError;
|
|
const result = lastRollupResult;
|
|
|
|
lastRollupError = lastRollupResult = null;
|
|
|
|
if (error) {
|
|
throw error;
|
|
}
|
|
return result;
|
|
};
|