From 19ac1cb090cb88149ededdd26e9e1f563f5d2ce9 Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Tue, 11 Jun 2024 14:47:36 +0200 Subject: [PATCH 1/2] perf: Make emoji related packages a custom chunk Signed-off-by: Ferdinand Thiessen --- vite.config.ts | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/vite.config.ts b/vite.config.ts index 70fd856c4d4..686861a2f1f 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -2,8 +2,8 @@ // SPDX-License-Identifier: AGPL-3.0-or-later import { createAppConfig } from '@nextcloud/vite-config' +import { webpackStats } from 'rollup-plugin-webpack-stats' import path from 'path' -import { webpackStats } from 'rollup-plugin-webpack-stats'; const ENTRIES_TO_INCLUDE_CSS = ['text', 'public', 'viewer', 'editors'] @@ -29,6 +29,18 @@ const config = createAppConfig({ plugins: [ webpackStats(), ], + build: { + rollupOptions: { + output: { + manualChunks: (id) => { + // Make the emoji related dependencies a custom chunk to reduce the size of the RichText chunk + if (id.includes('emoji-mart-vue') || id.includes('emoji-datasource')) { + return 'emoji-picker' + } + }, + }, + }, + }, }, }) From f1acd48089053d1b9c4379b89757848e95fd5f99 Mon Sep 17 00:00:00 2001 From: Ferdinand Thiessen Date: Tue, 11 Jun 2024 14:49:23 +0200 Subject: [PATCH 2/2] perf: Lazy load mermaid JS Mermaid JS and its dependency elkjs is a huge depenency (6MiB and 3MiB compressed), so we only should load it if required. Signed-off-by: Ferdinand Thiessen --- src/nodes/CodeBlockView.vue | 57 +++++++++++++++++++++---------------- 1 file changed, 32 insertions(+), 25 deletions(-) diff --git a/src/nodes/CodeBlockView.vue b/src/nodes/CodeBlockView.vue index 73b144764d7..46029e24577 100644 --- a/src/nodes/CodeBlockView.vue +++ b/src/nodes/CodeBlockView.vue @@ -79,7 +79,6 @@ import debounce from 'debounce' import { NodeViewWrapper, NodeViewContent } from '@tiptap/vue-2' import { NcActions, NcActionButton, NcActionInput, NcActionLink, NcActionSeparator, NcLoadingIcon } from '@nextcloud/vue' -import mermaid from 'mermaid' import { v4 as uuidv4 } from 'uuid' import ViewSplitVertical from 'vue-material-design-icons/ViewSplitVertical.vue' @@ -93,7 +92,6 @@ import Check from 'vue-material-design-icons/Check.vue' import CopyToClipboardMixin from '../mixins/CopyToClipboardMixin.js' export default { - // eslint-disable-next-line vue/match-component-file-name name: 'CodeBlockView', components: { MarkerIcon, @@ -123,6 +121,12 @@ export default { required: true, }, }, + setup() { + return { + /** The lazy loaded mermaid js module */ + mermaid: null, + } + }, data() { return { isEditable: false, @@ -153,10 +157,16 @@ export default { return this.supportPreview() ? 'code' : 'preview' } }, + renderMermaidDebounced() { + return debounce(this.renderMermaid, 250) + }, }, watch: { - 'node.textContent'() { - this.renderMermaid() + 'node.textContent': { + handler() { + this.renderMermaidDebounced() + }, + immediate: true, }, }, beforeMount() { @@ -164,7 +174,17 @@ export default { this.editor.on('update', ({ editor }) => { this.isEditable = editor.isEditable }) - this.renderMermaidDebounced = debounce(async function() { + }, + methods: { + async copyCode() { + await this.copyToClipboard(this.node?.textContent) + }, + updateLanguage(event) { + this.updateAttributes({ + language: event.target.value, + }) + }, + async renderMermaid() { if (!this.supportPreview) { this.viewMode = 'code' return @@ -177,9 +197,14 @@ export default { } try { - await mermaid.parse(textContent) + // lazy load mermaid on first real usage + if (this.mermaid === null) { + this.mermaid = (await import('mermaid')).default + this.mermaid.initialize({ startOnLoad: false }) + } + await this.mermaid.parse(textContent) - const { svg } = await mermaid.render(this.targetId, textContent) + const { svg } = await this.mermaid.render(this.targetId, textContent) const targetElement = document.getElementById(this.targetId) if (targetElement) { targetElement.style.display = 'none' @@ -191,24 +216,6 @@ export default { this.viewMode = this.isEditable ? 'side-by-side' : 'code' } } - }, 250) - - mermaid.initialize({ startOnLoad: false }) - this.$nextTick(() => { - this.renderMermaid() - }) - }, - methods: { - async copyCode() { - await this.copyToClipboard(this.node?.textContent) - }, - updateLanguage(event) { - this.updateAttributes({ - language: event.target.value, - }) - }, - renderMermaid() { - this.renderMermaidDebounced() }, }, }