Skip to content

Commit 268d39d

Browse files
committed
fix: Ship mermaid's own es-module dist instead of re-bundling it
mermaid is a prebuilt, minified package; running another bundler over it produced 'undefined is not a function' at runtime. The build now copies the dist entry and its transitive chunk imports verbatim - the same artifact the CDN used to serve. The import closure is verified complete at build time by construction (every referenced chunk is copied), and the module graph import-checks cleanly under node.
1 parent 4f96281 commit 268d39d

3 files changed

Lines changed: 32 additions & 23 deletions

File tree

ui/build.mjs

Lines changed: 31 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,20 @@
66
// built as a self-contained IIFE in its own vite pass (rollup cannot code-split
77
// iife output, which is exactly what we want here).
88
import { build } from 'vite';
9-
import { copyFileSync, cpSync, createWriteStream, mkdirSync, readdirSync, rmSync } from 'node:fs';
10-
import { resolve, basename } from 'node:path';
9+
import {
10+
copyFileSync,
11+
cpSync,
12+
createWriteStream,
13+
mkdirSync,
14+
readdirSync,
15+
readFileSync,
16+
rmSync
17+
} from 'node:fs';
18+
import { createRequire } from 'node:module';
19+
import { resolve, basename, dirname } from 'node:path';
1120
import { ZipArchive } from 'archiver';
1221

22+
const require = createRequire(import.meta.url);
1323
const root = import.meta.dirname;
1424
const src = resolve(root, 'src');
1525
const staged = resolve(root, 'build/ui');
@@ -98,25 +108,25 @@ await build(
98108
})
99109
);
100110

101-
// mermaid is imported on demand by partials/mermaid-script.hbs and therefore
102-
// has to stay an es module (the classic-script entries above cannot be
103-
// import()ed); its internal chunks lazy-load per diagram type
104-
await build(
105-
config({
106-
build: {
107-
outDir: staged,
108-
emptyOutDir: false,
109-
rollupOptions: {
110-
input: resolve(src, 'js', 'vendor', 'mermaid.module.js'),
111-
output: {
112-
format: 'es',
113-
entryFileNames: 'js/vendor/mermaid.js',
114-
chunkFileNames: 'js/vendor/mermaid-[name]-[hash].js'
115-
}
116-
}
117-
}
118-
})
119-
);
111+
// mermaid is imported on demand by partials/mermaid-script.hbs. It ships its
112+
// own prebuilt es-module dist and breaks at runtime when re-bundled, so the
113+
// entry and its transitive chunk imports are copied verbatim instead.
114+
const mermaidDist = resolve(dirname(require.resolve('mermaid/package.json')), 'dist');
115+
const mermaidOut = resolve(staged, 'js/vendor/mermaid');
116+
mkdirSync(mermaidOut, { recursive: true });
117+
const mermaidQueue = ['mermaid.esm.min.mjs'];
118+
const mermaidSeen = new Set();
119+
while (mermaidQueue.length > 0) {
120+
const file = mermaidQueue.pop();
121+
if (mermaidSeen.has(file)) continue;
122+
mermaidSeen.add(file);
123+
const content = readFileSync(resolve(mermaidDist, file), 'utf8');
124+
copyFileSync(resolve(mermaidDist, file), resolve(mermaidOut, file));
125+
for (const match of content.matchAll(/(?:from\s*|import\s*\(?\s*)"\.\/([^"]+)"/g)) {
126+
mermaidQueue.push(match[1]);
127+
}
128+
}
129+
console.log(`mermaid: copied ${mermaidSeen.size} dist files`);
120130

121131
for (const dir of ['helpers', 'layouts', 'partials', 'img']) {
122132
cpSync(resolve(src, dir), resolve(staged, dir), { recursive: true });

ui/src/js/vendor/mermaid.module.js

Lines changed: 0 additions & 1 deletion
This file was deleted.

ui/src/partials/mermaid-script.hbs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<script type="module">
22
if (document.querySelector('.mermaid')) {
3-
const { default: mermaid } = await import('{{{uiRootPath}}}/js/vendor/mermaid.js')
3+
const { default: mermaid } = await import('{{{uiRootPath}}}/js/vendor/mermaid/mermaid.esm.min.mjs')
44
mermaid.initialize({ startOnLoad: true })
55
}
66
</script>

0 commit comments

Comments
 (0)