Skip to content

Commit

Permalink
feat: Lazy load icons
Browse files Browse the repository at this point in the history
Co-authored-by: Alois Klink <alois@aloisklink.com>
  • Loading branch information
sidharthv96 and aloisklink committed Sep 2, 2024
1 parent c68ae30 commit 0edfab1
Show file tree
Hide file tree
Showing 10 changed files with 175 additions and 140 deletions.
9 changes: 7 additions & 2 deletions cypress/platform/architecture-external.html
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,13 @@ <h2>External Icons Demo</h2>
startOnLoad: false,
logLevel: 0,
});
const logos = await fetch('https://unpkg.com/@iconify-json/logos/icons.json');
mermaid.registerIconPacks(await logos.json());
mermaid.registerIconPacks([
{
name: 'logos',
loader: () =>
fetch('https://unpkg.com/@iconify-json/logos/icons.json').then((res) => res.json()),
},
]);
await mermaid.run();
if (window.Cypress) {
window.rendered = true;
Expand Down
22 changes: 15 additions & 7 deletions demos/architecture.html
Original file line number Diff line number Diff line change
Expand Up @@ -232,17 +232,25 @@ <h2>External Icons Demo</h2>
service s3(logos:aws-s3)[Cloud Store]
service ec2(logos:aws-ec2)[Server]
service api(logos:aws-api-gateway)[Api Gateway]
service fa(fa:image)[Font Awesome Icon]
</pre>

<script type="module">
import mermaid from './mermaid.esm.mjs';
mermaid.initialize({
startOnLoad: false,
logLevel: 0,
});
const logos = await fetch('https://unpkg.com/@iconify-json/logos/icons.json');
mermaid.registerIconPacks(await logos.json());
mermaid.init();
mermaid.registerIconPacks([
{
name: 'logos',
loader: () =>
fetch('https://unpkg.com/@iconify-json/logos/icons.json').then((res) => res.json()),
},
{
name: 'fa',
loader: () =>
fetch('https://unpkg.com/@iconify-json/fa6-regular/icons.json').then((res) =>
res.json()
),
},
]);
</script>
</body>
</html>
10 changes: 5 additions & 5 deletions docs/config/setup/interfaces/mermaid.Mermaid.md
Original file line number Diff line number Diff line change
Expand Up @@ -224,17 +224,17 @@ Used to register external diagram types.

### registerIconPacks

**registerIconPacks**: (...`iconPacks`: `IconifyJSON`\[]) => `void`
**registerIconPacks**: (`iconLoaders`: `IconLoader`\[]) => `void`

#### Type declaration

▸ (`...iconPacks`): `void`
▸ (`iconLoaders`): `void`

##### Parameters

| Name | Type |
| :------------- | :--------------- |
| `...iconPacks` | `IconifyJSON`\[] |
| Name | Type |
| :------------ | :-------------- |
| `iconLoaders` | `IconLoader`\[] |

##### Returns

Expand Down
90 changes: 46 additions & 44 deletions docs/syntax/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -197,42 +197,56 @@ By default, architecture diagram supports the following icons: `cloud`, `databas
Users can use any of the 200,000+ icons available in iconify.design, or add their own custom icons, by following the steps below.

The icon packs available can be found at [icones.js.org](https://icones.js.org/).
We use the name defined when registering the icon pack, to override the prefix field of the iconify pack. This allows the user to use shorter names for the icons. It also allows us to load a particular pack only when it is used in a diagram.

Using JSON file directly from CDN:

```js
import mermaid from 'CDN/mermaid.esm.mjs';

// You have to call `initialize` with startOnLoad:false before calling `registerIconPacks`,
// to prevent mermaid from starting before the icons are loaded
mermaid.initialize({
startOnLoad: false,
logLevel: 0,
});
const logos = await fetch('https://unpkg.com/@iconify-json/logos/icons.json');
mermaid.registerIconPacks(await logos.json());
mermaid.init();
mermaid.registerIconPacks([
{
name: 'logos',
loader: () =>
fetch('https://unpkg.com/@iconify-json/logos/icons.json').then((res) => res.json()),
},
]);
```

Using packages and a bundler:

```bash
npm install @iconify-json/logos
```

With lazy loading

```js
import mermaid from 'mermaid';
// npm install @iconify-json/logos
import { icons as logos } from '@iconify-json/logos';

mermaid.initialize({
startOnLoad: false,
logLevel: 0,
});
mermaid.registerIconPacks(logos);
mermaid.init();
mermaid.registerIconPacks([
{
name: 'logos',
loader: () => import('@iconify-json/logos').then((module) => module.icons),
},
]);
```

After the icons are installed, they can be used in the architecture diagram by using the format "prefix:icon-name", where prefix comes from the icon pack you selected.
Without lazy loading

````
```mermaid
```js
import mermaid from 'mermaid';
import { icons } from '@iconify-json/logos';
mermaid.registerIconPacks([
{
name: icons.prefix, // To use the prefix defined in the icon pack
icons,
},
]);
```

After the icons are installed, they can be used in the architecture diagram by using the format "name:icon-name", where name is the value used when registering the icon pack.

```mermaid-example
architecture-beta
group api(logos:aws-lambda)[API]
Expand All @@ -245,29 +259,17 @@ architecture-beta
disk1:T -- B:server
disk2:T -- B:db
```
````

<div id="arch-example">loading...</div>

<script>
const main = async () => {
const logos = await fetch('https://unpkg.com/@iconify-json/logos/icons.json');
mermaid.registerIconPacks(await logos.json());
const svg = await window.render('d'+Date.now().toString(), `architecture-beta
group api(logos:aws-api-gateway)[API]
service db(logos:aws-aurora)[Database] in api
service disk1(logos:aws-glacier)[Storage] in api
service disk2(logos:aws-s3)[Storage] in api
service server(logos:aws-ec2)[Server] in api
```mermaid
architecture-beta
group api(logos:aws-lambda)[API]
db:L -- R:server
disk1:T -- B:server
disk2:T -- B:db`, {});
document.getElementById('arch-example').innerHTML = svg;
};
service db(logos:aws-aurora)[Database] in api
service disk1(logos:aws-glacier)[Storage] in api
service disk2(logos:aws-s3)[Storage] in api
service server(logos:aws-ec2)[Server] in api
if (!import.meta.env.SSR) {
setTimeout(main, 100);
}
</script>
db:L -- R:server
disk1:T -- B:server
disk2:T -- B:db
```
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,12 @@ import {
} from './architectureTypes.js';
import { drawEdges, drawGroups, drawJunctions, drawServices } from './svgDraw.js';

registerIconPacks(architectureIcons);
registerIconPacks([
{
name: architectureIcons.prefix,
icons: architectureIcons,
},
]);
cytoscape.use(fcose);

function addServices(services: ArchitectureService[], cy: cytoscape.Core) {
Expand Down
6 changes: 3 additions & 3 deletions packages/mermaid/src/diagrams/architecture/svgDraw.ts
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ export const drawGroups = async function (groupsEl: D3Element, cy: cytoscape.Cor
if (data.icon) {
const bkgElem = groupLabelContainer.append('g');
bkgElem.html(
`<g>${getIconSVG(data.icon, { height: groupIconSize, width: groupIconSize, fallbackPrefix: architectureIcons.prefix })}</g>`
`<g>${await getIconSVG(data.icon, { height: groupIconSize, width: groupIconSize, fallbackPrefix: architectureIcons.prefix })}</g>`
);
bkgElem.attr(
'transform',
Expand Down Expand Up @@ -297,11 +297,11 @@ export const drawServices = async function (
// throw new Error(`Invalid SVG Icon name: "${service.icon}"`);
// }
bkgElem.html(
`<g>${getIconSVG(service.icon, { height: iconSize, width: iconSize, fallbackPrefix: architectureIcons.prefix })}</g>`
`<g>${await getIconSVG(service.icon, { height: iconSize, width: iconSize, fallbackPrefix: architectureIcons.prefix })}</g>`
);
} else if (service.iconText) {
bkgElem.html(
`<g>${getIconSVG('blank', { height: iconSize, width: iconSize, fallbackPrefix: architectureIcons.prefix })}</g>`
`<g>${await getIconSVG('blank', { height: iconSize, width: iconSize, fallbackPrefix: architectureIcons.prefix })}</g>`
);
const textElemContainer = bkgElem.append('g');
const fo = textElemContainer
Expand Down
2 changes: 2 additions & 0 deletions packages/mermaid/src/docs/.vitepress/theme/Mermaid.vue
Original file line number Diff line number Diff line change
Expand Up @@ -86,9 +86,11 @@ onUnmounted(() => mut.disconnect());
const renderChart = async () => {
console.log('rendering chart' + props.id + code.value);
const hasDarkClass = document.documentElement.classList.contains('dark');
const mermaidConfig = {
securityLevel: 'loose',
startOnLoad: false,
theme: hasDarkClass ? 'dark' : 'default',
};
let svgCode = await render(props.id, code.value, mermaidConfig);
// This is a hack to force v-html to re-render, otherwise the diagram disappears
Expand Down
28 changes: 8 additions & 20 deletions packages/mermaid/src/docs/.vitepress/theme/mermaid.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,29 +2,17 @@ import mermaid, { type MermaidConfig } from 'mermaid';
import zenuml from '../../../../../mermaid-zenuml/dist/mermaid-zenuml.core.mjs';

const init = mermaid.registerExternalDiagrams([zenuml]);
mermaid.registerIconPacks([
{
name: 'logos',
loader: () =>
fetch('https://unpkg.com/@iconify-json/logos/icons.json').then((res) => res.json()),
},
]);

export const render = async (id: string, code: string, config: MermaidConfig): Promise<string> => {
await init;
const hasDarkClass = document.documentElement.classList.contains('dark');
const theme = hasDarkClass ? 'dark' : 'default';
mermaid.initialize({ ...config, theme });
mermaid.initialize(config);
const { svg } = await mermaid.render(id, code);
return svg;
};

declare global {
interface Window {
mermaid: typeof mermaid;
render: typeof render;
}

interface ImportMeta {
env: {
SSR: boolean;
};
}
}
if (!import.meta.env.SSR) {
window.mermaid = mermaid;
window.render = render;
}
82 changes: 35 additions & 47 deletions packages/mermaid/src/docs/syntax/architecture.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,42 +159,56 @@ By default, architecture diagram supports the following icons: `cloud`, `databas
Users can use any of the 200,000+ icons available in iconify.design, or add their own custom icons, by following the steps below.

The icon packs available can be found at [icones.js.org](https://icones.js.org/).
We use the name defined when registering the icon pack, to override the prefix field of the iconify pack. This allows the user to use shorter names for the icons. It also allows us to load a particular pack only when it is used in a diagram.

Using JSON file directly from CDN:

```js
import mermaid from 'CDN/mermaid.esm.mjs';

// You have to call `initialize` with startOnLoad:false before calling `registerIconPacks`,
// to prevent mermaid from starting before the icons are loaded
mermaid.initialize({
startOnLoad: false,
logLevel: 0,
});
const logos = await fetch('https://unpkg.com/@iconify-json/logos/icons.json');
mermaid.registerIconPacks(await logos.json());
mermaid.init();
mermaid.registerIconPacks([
{
name: 'logos',
loader: () =>
fetch('https://unpkg.com/@iconify-json/logos/icons.json').then((res) => res.json()),
},
]);
```

Using packages and a bundler:

```bash
npm install @iconify-json/logos
```

With lazy loading

```js
import mermaid from 'mermaid';
// npm install @iconify-json/logos
import { icons as logos } from '@iconify-json/logos';

mermaid.initialize({
startOnLoad: false,
logLevel: 0,
});
mermaid.registerIconPacks(logos);
mermaid.init();
mermaid.registerIconPacks([
{
name: 'logos',
loader: () => import('@iconify-json/logos').then((module) => module.icons),
},
]);
```

After the icons are installed, they can be used in the architecture diagram by using the format "prefix:icon-name", where prefix comes from the icon pack you selected.
Without lazy loading

```js
import mermaid from 'mermaid';
import { icons } from '@iconify-json/logos';
mermaid.registerIconPacks([
{
name: icons.prefix, // To use the prefix defined in the icon pack
icons,
},
]);
```

````
```mermaid
After the icons are installed, they can be used in the architecture diagram by using the format "name:icon-name", where name is the value used when registering the icon pack.

```mermaid-example
architecture-beta
group api(logos:aws-lambda)[API]
Expand All @@ -207,29 +221,3 @@ architecture-beta
disk1:T -- B:server
disk2:T -- B:db
```
````

<div id="arch-example">loading...</div>

<script>
const main = async () => {
const logos = await fetch('https://unpkg.com/@iconify-json/logos/icons.json');
mermaid.registerIconPacks(await logos.json());
const svg = await window.render('d'+Date.now().toString(), `architecture-beta
group api(logos:aws-api-gateway)[API]
service db(logos:aws-aurora)[Database] in api
service disk1(logos:aws-glacier)[Storage] in api
service disk2(logos:aws-s3)[Storage] in api
service server(logos:aws-ec2)[Server] in api
db:L -- R:server
disk1:T -- B:server
disk2:T -- B:db`, {});
document.getElementById('arch-example').innerHTML = svg;
};

if (!import.meta.env.SSR) {
setTimeout(main, 100);
}
</script>
Loading

0 comments on commit 0edfab1

Please sign in to comment.