feat: load vditor dep from local (#4190)

* feat: load vditor dep from local

* fix: plugin-field-markdown-vditor build config

* Revert "fix: plugin-field-markdown-vditor build config"

This reverts commit 60d344d3402e0da916c918f65c81b1cd734fa3ce.

* feat: plugin-field-markdown-vditor: use NODE_ENV

* fix: plugin-field-markdown-vdtor dep preload

* fix: plugin-field-markdown-vdtor dep preload

* fix: plugin-field-markdown-vdtor dep preload

* feat: plugin-field-markdown-vditor set default valut for edit

* fix: cdn

* fix: set vditor editor value after create

* fix: cdn

---------

Co-authored-by: chenos <chenlinxh@gmail.com>
This commit is contained in:
Sun668 2024-04-28 11:23:14 +08:00 committed by GitHub
parent 132f626fa3
commit 0d9b43206c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 83 additions and 15 deletions

View File

@ -0,0 +1,15 @@
import { defineConfig } from '@nocobase/build';
import fs from 'fs/promises';
import path from 'path';
const vditor = path.dirname(require.resolve('vditor'));
export default defineConfig({
afterBuild: async (log) => {
log('coping vditor dist');
await fs.cp(vditor, path.resolve(__dirname, 'dist/client/vditor/dist'), {
recursive: true,
force: true,
});
},
});

View File

@ -21,7 +21,7 @@
"@formily/react": "2.x", "@formily/react": "2.x",
"@formily/shared": "2.x", "@formily/shared": "2.x",
"antd": "5.x", "antd": "5.x",
"katex": "^0.16.10", "koa-send": "^5.0.1",
"vditor": "^3.10.3" "vditor": "^3.10.3"
}, },
"keywords": [ "keywords": [

View File

@ -1,8 +1,10 @@
import { Field } from '@formily/core'; import { Field } from '@formily/core';
import { useField } from '@formily/react'; import { useField } from '@formily/react';
import { withDynamicSchemaProps } from '@nocobase/client';
import { Popover } from 'antd'; import { Popover } from 'antd';
import React, { CSSProperties, useCallback, useEffect, useRef, useState } from 'react'; import React, { CSSProperties, useCallback, useEffect, useRef, useState } from 'react';
import Vditor from 'vditor'; import Vditor from 'vditor';
import { useCDN } from './const';
import useStyle from './style'; import useStyle from './style';
function convertToText(markdownText: string) { function convertToText(markdownText: string) {
@ -26,10 +28,14 @@ const getContentWidth = (element) => {
function DisplayInner(props: { value: string; style?: CSSProperties }) { function DisplayInner(props: { value: string; style?: CSSProperties }) {
const containerRef = useRef<HTMLDivElement>(); const containerRef = useRef<HTMLDivElement>();
const { wrapSSR, componentCls, hashId } = useStyle(); const { wrapSSR, componentCls, hashId } = useStyle();
const cdn = useCDN();
useEffect(() => { useEffect(() => {
if (!props.value) return; if (!props.value) return;
Vditor.preview(containerRef.current, props.value, { mode: 'light' }); Vditor.preview(containerRef.current, props.value, {
mode: 'light',
cdn,
});
}, [props.value]); }, [props.value]);
return wrapSSR( return wrapSSR(
@ -39,9 +45,10 @@ function DisplayInner(props: { value: string; style?: CSSProperties }) {
); );
} }
export const Display = (props) => { export const Display = withDynamicSchemaProps((props) => {
const field = useField<Field>(); const field = useField<Field>();
const value = props.value ?? field.value; const value = props.value ?? field.value;
const cdn = useCDN();
const containerRef = useRef<HTMLDivElement>(); const containerRef = useRef<HTMLDivElement>();
@ -55,7 +62,10 @@ export const Display = (props) => {
useEffect(() => { useEffect(() => {
if (!props.value || !field.value) return; if (!props.value || !field.value) return;
if (props.ellipsis) { if (props.ellipsis) {
Vditor.md2html(props.value, { mode: 'light' }) Vditor.md2html(props.value, {
mode: 'light',
cdn,
})
.then((html) => { .then((html) => {
setText(convertToText(html)); setText(convertToText(html));
}) })
@ -63,6 +73,7 @@ export const Display = (props) => {
} else { } else {
Vditor.preview(containerRef.current, props.value ?? field.value, { Vditor.preview(containerRef.current, props.value ?? field.value, {
mode: 'light', mode: 'light',
cdn,
}); });
} }
}, [props.value, props.ellipsis, field.value]); }, [props.value, props.ellipsis, field.value]);
@ -107,4 +118,4 @@ export const Display = (props) => {
} }
return <DisplayInner value={value} />; return <DisplayInner value={value} />;
}; });

View File

@ -1,8 +1,9 @@
import React, { useRef, useEffect, useLayoutEffect } from 'react'; import { useAPIClient, useApp, withDynamicSchemaProps } from '@nocobase/client';
import React, { useEffect, useLayoutEffect, useRef } from 'react';
import Vditor from 'vditor'; import Vditor from 'vditor';
import { useAPIClient, withDynamicSchemaProps, useApp } from '@nocobase/client';
import useStyle from './style';
import { defaultToolbar } from '../interfaces/markdown-vditor'; import { defaultToolbar } from '../interfaces/markdown-vditor';
import { useCDN } from './const';
import useStyle from './style';
export const Edit = withDynamicSchemaProps((props) => { export const Edit = withDynamicSchemaProps((props) => {
const { disabled, onChange, value, fileCollection, toolbar } = props; const { disabled, onChange, value, fileCollection, toolbar } = props;
@ -13,13 +14,14 @@ export const Edit = withDynamicSchemaProps((props) => {
const containerParentRef = useRef<HTMLDivElement>(); const containerParentRef = useRef<HTMLDivElement>();
const app = useApp(); const app = useApp();
const apiClient = useAPIClient(); const apiClient = useAPIClient();
const cdn = useCDN();
const { wrapSSR, hashId, componentCls: containerClassName } = useStyle(); const { wrapSSR, hashId, componentCls: containerClassName } = useStyle();
useEffect(() => { useEffect(() => {
const uploadFileCollection = fileCollection ?? 'attachments'; const uploadFileCollection = fileCollection ?? 'attachments';
const toolbarConfig = toolbar ?? defaultToolbar; const toolbarConfig = toolbar ?? defaultToolbar;
const vditor = new Vditor(containerRef.current, { const vditor = new Vditor(containerRef.current, {
value, value: value ?? '',
lang: apiClient.auth.locale.replaceAll('-', '_') as any, lang: apiClient.auth.locale.replaceAll('-', '_') as any,
cache: { cache: {
enable: false, enable: false,
@ -34,9 +36,11 @@ export const Edit = withDynamicSchemaProps((props) => {
fullscreen: { fullscreen: {
index: 1200, index: 1200,
}, },
cdn,
minHeight: 200, minHeight: 200,
after: () => { after: () => {
vdRef.current = vditor; vdRef.current = vditor;
vditor.setValue(value ?? '');
if (disabled) { if (disabled) {
vditor.disabled(); vditor.disabled();
} else { } else {
@ -71,7 +75,7 @@ export const Edit = withDynamicSchemaProps((props) => {
vdRef.current?.destroy(); vdRef.current?.destroy();
vdRef.current = undefined; vdRef.current = undefined;
}; };
}, [fileCollection, toolbar]); }, [fileCollection, toolbar?.join(',')]);
useEffect(() => { useEffect(() => {
if (value === vdRef?.current?.getValue()) { if (value === vdRef?.current?.getValue()) {

View File

@ -0,0 +1,7 @@
import { usePlugin } from '@nocobase/client';
import { PluginFieldMarkdownVditorClient } from '../';
export const useCDN = () => {
const plugin = usePlugin(PluginFieldMarkdownVditorClient);
return plugin.getCDN();
};

View File

@ -1,8 +1,7 @@
import { Plugin } from '@nocobase/client'; import { Plugin } from '@nocobase/client';
import 'vditor/dist/index.css';
import { MarkdownVditor } from './components'; import { MarkdownVditor } from './components';
import { MarkdownVditorFieldInterface } from './interfaces/markdown-vditor'; import { MarkdownVditorFieldInterface } from './interfaces/markdown-vditor';
import 'vditor/dist/index.css';
import katex from 'katex';
export class PluginFieldMarkdownVditorClient extends Plugin { export class PluginFieldMarkdownVditorClient extends Plugin {
async afterAdd() {} async afterAdd() {}
@ -10,12 +9,44 @@ export class PluginFieldMarkdownVditorClient extends Plugin {
async load() { async load() {
this.app.addComponents({ MarkdownVditor }); this.app.addComponents({ MarkdownVditor });
this.initKatexDependency(); this.initVditorDependency();
this.app.dataSourceManager.addFieldInterfaces([MarkdownVditorFieldInterface]); this.app.dataSourceManager.addFieldInterfaces([MarkdownVditorFieldInterface]);
} }
initKatexDependency() { getCDN() {
window['katex'] = katex; if (process.env.NODE_ENV !== 'production') {
// 开发模式下使用远程 cdn
return 'https://cdn.jsdelivr.net/npm/vditor@3.10.4';
}
// 生产环境,使用本地链接,支持内网
// 需要支持子目录,比如应用部署在 /xxx/ 目录下
return this.app.getPublicPath() + 'static/plugins/@nocobase/plugin-field-markdown-vditor/dist/client/vditor';
}
initVditorDependency() {
const cdn = this.getCDN();
try {
const vditorDepdencePrefix = 'plugin-field-markdown-vditor-dep';
const vditorDepdence = {
[`${vditorDepdencePrefix}.katex`]: `${cdn}/dist/js/katex/katex.min.js?v=0.16.9`,
[`${vditorDepdencePrefix}.ABCJS`]: `${cdn}/dist/js/abcjs/abcjs_basic.min`,
[`${vditorDepdencePrefix}.plantumlEncoder`]: `${cdn}/dist/js/plantuml/plantuml-encoder.min`,
[`${vditorDepdencePrefix}.echarts`]: `${cdn}/dist/js/echarts/echarts.min`,
[`${vditorDepdencePrefix}.flowchart`]: `${cdn}/dist/js/flowchart.js/flowchart.min`,
[`${vditorDepdencePrefix}.Viz`]: `${cdn}/dist/js/graphviz/viz`,
[`${vditorDepdencePrefix}.mermaid`]: `${cdn}/dist/js/mermaid/mermaid.min`,
};
this.app.requirejs.require.config({
paths: vditorDepdence,
});
Object.keys(vditorDepdence).forEach((key) => {
this.app.requirejs.require([key], (m) => {
window[key.split('.')[1]] = m;
});
});
} catch (e) {
console.log('initVditorDependency failed', e);
}
} }
} }