Skip to content

Commit 1b044a2

Browse files
authored
Merge pull request mermaid-js#4734 from mermaid-js/sidv/tinyMermaid
Add `mermaid.tiny.min.js`. 69.7% size reduction.
2 parents 17a1569 + c8daf9a commit 1b044a2

File tree

16 files changed

+171
-35
lines changed

16 files changed

+171
-35
lines changed

.esbuild/build.ts

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { build } from 'esbuild';
2-
import { mkdir, writeFile } from 'node:fs/promises';
2+
import { mkdir, readFile, rename, writeFile } from 'node:fs/promises';
33
import { packageOptions } from '../.build/common.js';
44
import { generateLangium } from '../.build/generateLangium.js';
55
import type { MermaidBuildOptions } from './util.js';
@@ -31,7 +31,15 @@ const buildPackage = async (entryName: keyof typeof packageOptions) => {
3131
// mermaid.js
3232
{ ...iifeOptions },
3333
// mermaid.min.js
34-
{ ...iifeOptions, minify: true, metafile: shouldVisualize }
34+
{ ...iifeOptions, minify: true, metafile: shouldVisualize },
35+
// mermaid.tiny.min.js
36+
{
37+
...iifeOptions,
38+
minify: true,
39+
includeLargeFeatures: false,
40+
metafile: shouldVisualize,
41+
sourcemap: false,
42+
}
3543
);
3644
}
3745
if (entryName === 'mermaid-zenuml') {
@@ -70,6 +78,20 @@ const handler = (e) => {
7078
process.exit(1);
7179
};
7280

81+
const buildTinyMermaid = async () => {
82+
await mkdir('./packages/tiny/dist', { recursive: true });
83+
await rename(
84+
'./packages/mermaid/dist/mermaid.tiny.min.js',
85+
'./packages/tiny/dist/mermaid.tiny.js'
86+
);
87+
// Copy version from mermaid's package.json to tiny's package.json
88+
const mermaidPkg = JSON.parse(await readFile('./packages/mermaid/package.json', 'utf8'));
89+
const tinyPkg = JSON.parse(await readFile('./packages/tiny/package.json', 'utf8'));
90+
tinyPkg.version = mermaidPkg.version;
91+
92+
await writeFile('./packages/tiny/package.json', JSON.stringify(tinyPkg, null, 2) + '\n');
93+
};
94+
7395
const main = async () => {
7496
await generateLangium();
7597
await mkdir('stats', { recursive: true });
@@ -78,6 +100,7 @@ const main = async () => {
78100
for (const pkg of packageNames) {
79101
await buildPackage(pkg).catch(handler);
80102
}
103+
await buildTinyMermaid();
81104
};
82105

83106
void main();

.esbuild/util.ts

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,15 @@ export interface MermaidBuildOptions extends BuildOptions {
1414
metafile: boolean;
1515
format: 'esm' | 'iife';
1616
options: PackageOptions;
17+
includeLargeFeatures: boolean;
1718
}
1819

1920
export const defaultOptions: Omit<MermaidBuildOptions, 'entryName' | 'options'> = {
2021
minify: false,
2122
metafile: false,
2223
core: false,
2324
format: 'esm',
25+
includeLargeFeatures: true,
2426
} as const;
2527

2628
const buildOptions = (override: BuildOptions): BuildOptions => {
@@ -39,12 +41,18 @@ const buildOptions = (override: BuildOptions): BuildOptions => {
3941
};
4042
};
4143

42-
const getFileName = (fileName: string, { core, format, minify }: MermaidBuildOptions) => {
44+
const getFileName = (
45+
fileName: string,
46+
{ core, format, minify, includeLargeFeatures }: MermaidBuildOptions
47+
) => {
4348
if (core) {
4449
fileName += '.core';
4550
} else if (format === 'esm') {
4651
fileName += '.esm';
4752
}
53+
if (!includeLargeFeatures) {
54+
fileName += '.tiny';
55+
}
4856
if (minify) {
4957
fileName += '.min';
5058
}
@@ -54,25 +62,27 @@ const getFileName = (fileName: string, { core, format, minify }: MermaidBuildOpt
5462
export const getBuildConfig = (options: MermaidBuildOptions): BuildOptions => {
5563
const {
5664
core,
57-
metafile,
5865
format,
59-
minify,
6066
options: { name, file, packageName },
6167
globalName = 'mermaid',
68+
includeLargeFeatures,
69+
...rest
6270
} = options;
71+
6372
const external: string[] = ['require', 'fs', 'path'];
6473
const outFileName = getFileName(name, options);
6574
const output: BuildOptions = buildOptions({
75+
...rest,
6676
absWorkingDir: resolve(__dirname, `../packages/${packageName}`),
6777
entryPoints: {
6878
[outFileName]: `src/${file}`,
6979
},
70-
metafile,
71-
minify,
7280
globalName,
7381
logLevel: 'info',
7482
chunkNames: `chunks/${outFileName}/[name]-[hash]`,
7583
define: {
84+
// This needs to be stringified for esbuild
85+
includeLargeFeatures: `${includeLargeFeatures}`,
7686
'import.meta.vitest': 'undefined',
7787
},
7888
});

.vite/build.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,10 @@ export const getBuildConfig = ({ minify, core, watch, entryName }: BuildOptions)
9494
}),
9595
...visualizerOptions(packageName, core),
9696
],
97+
define: {
98+
// Needs to be string
99+
includeLargeFeatures: 'true',
100+
},
97101
};
98102

99103
if (watch && config.build) {

docs/config/usage.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,12 @@ Mermaid can load multiple diagrams, in the same page.
9898
> Try it out, save this code as HTML and load it using any browser.
9999
> (Except Internet Explorer, please don't use Internet Explorer.)
100100
101+
## Tiny Mermaid
102+
103+
We offer a smaller version of Mermaid that's approximately half the size of the full library. This tiny version doesn't support Mindmap Diagrams, Architecture Diagrams, KaTeX rendering, or lazy loading.
104+
105+
If you need a more lightweight version without these features, you can use [Mermaid Tiny](https://github.com/mermaid-js/mermaid/tree/develop/packages/tiny).
106+
101107
## Enabling Click Event and Tags in Nodes
102108

103109
A `securityLevel` configuration has to first be cleared. `securityLevel` sets the level of trust for the parsed diagrams and limits click functionality. This was introduced in version 8.2 as a security improvement, aimed at preventing malicious use.

docs/intro/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -354,6 +354,7 @@ To Deploy Mermaid:
354354

355355
- [Mermaid Live Editor](https://github.com/mermaid-js/mermaid-live-editor)
356356
- [Mermaid CLI](https://github.com/mermaid-js/mermaid-cli)
357+
- [Mermaid Tiny](https://github.com/mermaid-js/mermaid/tree/develop/packages/tiny)
357358
- [Mermaid Webpack Demo](https://github.com/mermaidjs/mermaid-webpack-demo)
358359
- [Mermaid Parcel Demo](https://github.com/mermaidjs/mermaid-parcel-demo)
359360

packages/mermaid/src/diagram-api/diagram-orchestration.ts

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import block from '../diagrams/block/blockDetector.js';
2727
import architecture from '../diagrams/architecture/architectureDetector.js';
2828
import { registerLazyLoadedDiagrams } from './detectType.js';
2929
import { registerDiagram } from './diagramAPI.js';
30+
import '../type.d.ts';
3031

3132
let hasLoadedDiagrams = false;
3233
export const addDiagrams = () => {
@@ -69,6 +70,11 @@ export const addDiagrams = () => {
6970
return text.toLowerCase().trimStart().startsWith('---');
7071
}
7172
);
73+
74+
if (includeLargeFeatures) {
75+
registerLazyLoadedDiagrams(flowchartElk, mindmap, architecture);
76+
}
77+
7278
// Ordering of detectors is important. The first one to return true will be used.
7379
registerLazyLoadedDiagrams(
7480
c4,
@@ -81,10 +87,8 @@ export const addDiagrams = () => {
8187
pie,
8288
requirement,
8389
sequence,
84-
flowchartElk,
8590
flowchartV2,
8691
flowchart,
87-
mindmap,
8892
timeline,
8993
git,
9094
stateV2,
@@ -95,7 +99,6 @@ export const addDiagrams = () => {
9599
packet,
96100
xychart,
97101
block,
98-
architecture,
99102
radar
100103
);
101104
};

packages/mermaid/src/diagrams/common/common.ts

Lines changed: 30 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -341,29 +341,36 @@ export const renderKatex = async (text: string, config: MermaidConfig): Promise<
341341
return text.replace(katexRegex, 'MathML is unsupported in this environment.');
342342
}
343343

344-
const { default: katex } = await import('katex');
345-
const outputMode =
346-
config.forceLegacyMathML || (!isMathMLSupported() && config.legacyMathML)
347-
? 'htmlAndMathml'
348-
: 'mathml';
349-
return text
350-
.split(lineBreakRegex)
351-
.map((line) =>
352-
hasKatex(line)
353-
? `<div style="display: flex; align-items: center; justify-content: center; white-space: nowrap;">${line}</div>`
354-
: `<div>${line}</div>`
355-
)
356-
.join('')
357-
.replace(katexRegex, (_, c) =>
358-
katex
359-
.renderToString(c, {
360-
throwOnError: true,
361-
displayMode: true,
362-
output: outputMode,
363-
})
364-
.replace(/\n/g, ' ')
365-
.replace(/<annotation.*<\/annotation>/g, '')
366-
);
344+
if (includeLargeFeatures) {
345+
const { default: katex } = await import('katex');
346+
const outputMode =
347+
config.forceLegacyMathML || (!isMathMLSupported() && config.legacyMathML)
348+
? 'htmlAndMathml'
349+
: 'mathml';
350+
return text
351+
.split(lineBreakRegex)
352+
.map((line) =>
353+
hasKatex(line)
354+
? `<div style="display: flex; align-items: center; justify-content: center; white-space: nowrap;">${line}</div>`
355+
: `<div>${line}</div>`
356+
)
357+
.join('')
358+
.replace(katexRegex, (_, c) =>
359+
katex
360+
.renderToString(c, {
361+
throwOnError: true,
362+
displayMode: true,
363+
output: outputMode,
364+
})
365+
.replace(/\n/g, ' ')
366+
.replace(/<annotation.*<\/annotation>/g, '')
367+
);
368+
}
369+
370+
return text.replace(
371+
katexRegex,
372+
'Katex is not supported in @mermaid-js/tiny. Please use the full mermaid library.'
373+
);
367374
};
368375

369376
export default {

packages/mermaid/src/diagrams/info/infoDb.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
import type { InfoFields, InfoDB } from './infoTypes.js';
22
import packageJson from '../../../package.json' assert { type: 'json' };
33

4-
export const DEFAULT_INFO_DB: InfoFields = { version: packageJson.version } as const;
4+
export const DEFAULT_INFO_DB: InfoFields = {
5+
version: packageJson.version + (includeLargeFeatures ? '' : '-tiny'),
6+
} as const;
57

68
export const getVersion = (): string => DEFAULT_INFO_DB.version;
79

packages/mermaid/src/docs/config/usage.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,12 @@ Mermaid can load multiple diagrams, in the same page.
9292
> Try it out, save this code as HTML and load it using any browser.
9393
> (Except Internet Explorer, please don't use Internet Explorer.)
9494
95+
## Tiny Mermaid
96+
97+
We offer a smaller version of Mermaid that's approximately half the size of the full library. This tiny version doesn't support Mindmap Diagrams, Architecture Diagrams, KaTeX rendering, or lazy loading.
98+
99+
If you need a more lightweight version without these features, you can use [Mermaid Tiny](https://github.com/mermaid-js/mermaid/tree/develop/packages/tiny).
100+
95101
## Enabling Click Event and Tags in Nodes
96102

97103
A `securityLevel` configuration has to first be cleared. `securityLevel` sets the level of trust for the parsed diagrams and limits click functionality. This was introduced in version 8.2 as a security improvement, aimed at preventing malicious use.

packages/mermaid/src/docs/intro/index.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ To Deploy Mermaid:
109109

110110
- [Mermaid Live Editor](https://github.com/mermaid-js/mermaid-live-editor)
111111
- [Mermaid CLI](https://github.com/mermaid-js/mermaid-cli)
112+
- [Mermaid Tiny](https://github.com/mermaid-js/mermaid/tree/develop/packages/tiny)
112113
- [Mermaid Webpack Demo](https://github.com/mermaidjs/mermaid-webpack-demo)
113114
- [Mermaid Parcel Demo](https://github.com/mermaidjs/mermaid-parcel-demo)
114115

0 commit comments

Comments
 (0)