Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: amis 渲染器支持异步,并且全部调整为异步 #10917

Merged
merged 2 commits into from
Sep 18, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 5 additions & 9 deletions examples/embed.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,11 @@ import copy from 'copy-to-clipboard';
import {normalizeLink, supportsMjs} from 'amis-core';

import qs from 'qs';
import {
toast,
alert,
confirm,
ToastComponent,
AlertComponent,
render as renderAmis,
makeTranslator
} from 'amis';
import {alert, confirm} from 'amis-ui/lib/components/Alert';
import {toast, default as ToastComponent} from 'amis-ui/lib/components/Toast';
import AlertComponent from 'amis-ui/lib/components/Alert';
import {render as renderAmis, makeTranslator} from 'amis-core';
import 'amis/lib/minimal';

import 'amis-ui/lib/locale/en-US';
import 'history';
Expand Down
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,7 @@
"\\.(svg)$": "<rootDir>/__mocks__/svgMock.js",
"\\.svg\\.js$": "<rootDir>/__mocks__/svgJsMock.js",
"^amis\\-ui$": "<rootDir>/packages/amis-ui/src/index.tsx",
"^amis\\-ui/lib/(.*)$": "<rootDir>/packages/amis-ui/src/$1",
"^amis\\-core$": "<rootDir>/packages/amis-core/src/index.tsx",
"^amis\\-formula$": "<rootDir>/packages/amis-formula/src/index.ts",
"^office\\-viewer$": "<rootDir>/packages/office-viewer/src/index.ts",
Expand Down
13 changes: 9 additions & 4 deletions packages/amis-core/__tests__/jest.setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,23 +6,26 @@ const originalDebug = console.warn.bind(console.debug);
const originalError = console.error.bind(console.error);
require('@testing-library/jest-dom');
require('moment-timezone');
const loadAllAsyncRenderers = require('amis-core').loadAllAsyncRenderers;
const moment = require('moment');
moment.tz.setDefault('Asia/Shanghai');
const cleanup = require('@testing-library/react').cleanup;

// https://github.com/nrwl/nx/issues/1178
// 解决jest 运行的时候报:
// ReferenceError: DragEvent is not defined
Object.defineProperty(window, 'DragEvent', {
value: class DragEvent {}
});
if (!window.DragEvent) {
Object.defineProperty(window, 'DragEvent', {
value: class DragEvent {}
});
}

// Mock ResizeObserver in jest env
global.ResizeObserver = require('resize-observer-polyfill');

global.__buildVersion = '';

global.beforeAll(() => {
global.beforeAll(async () => {
console.warn =
console.groupCollapsed =
console.group =
Expand All @@ -40,6 +43,8 @@ global.beforeAll(() => {
// }
// originalWarn(msg);
};

await loadAllAsyncRenderers();
});
global.afterAll(() => {
console.warn = originalWarn;
Expand Down
3 changes: 2 additions & 1 deletion packages/amis-core/rollup.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,8 @@ function transpileDynamicImportForCJS(options) {

return {
left: 'Promise.resolve().then(function() {return new Promise(function(fullfill) {require([',
right: '], function(mod) {fullfill(tslib.__importStar(mod))})})})'
right:
', "tslib"], function(mod, tslib) {fullfill(tslib.__importStar(mod))})})})'
};

// return {
Expand Down
25 changes: 24 additions & 1 deletion packages/amis-core/src/RootRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,16 @@ import type {RootProps} from './Root';
import {IScopedContext, ScopedContext, filterTarget} from './Scoped';
import {IRootStore, RootStore} from './store/root';
import {ActionObject} from './types';
import {bulkBindFunctions, guid, isVisible} from './utils/helper';
import {bulkBindFunctions, guid, isVisible, JSONTraverse} from './utils/helper';
import {filter} from './utils/tpl';
import qs from 'qs';
import pick from 'lodash/pick';
import mapValues from 'lodash/mapValues';
import {saveAs} from 'file-saver';
import {normalizeApi} from './utils/api';
import {findDOMNode} from 'react-dom';
import LazyComponent from './components/LazyComponent';
import {hasAsyncRenderers, loadAsyncRenderersByType} from './factory';

export interface RootRendererProps extends RootProps {
location?: any;
Expand Down Expand Up @@ -46,6 +48,25 @@ export class RootRenderer extends React.Component<RootRendererProps> {
'handleDrawerClose',
'handlePageVisibilityChange'
]);

this.store.init(() => {
if (!hasAsyncRenderers()) {
return;
}
const schema = props.schema;
const types: Array<string> = ['tpl', 'dialog', 'drawer'];
JSONTraverse(schema, (value: any, key: string) => {
if (key === 'type') {
types.push(value);

// form 依赖 panel
if (value === 'form') {
types.push('panel');
}
}
});
return loadAsyncRenderersByType(types);
});
}

componentDidMount() {
Expand Down Expand Up @@ -499,6 +520,8 @@ export class RootRenderer extends React.Component<RootRendererProps> {

if (store.runtimeError) {
return this.renderRuntimeError();
} else if (!store.ready) {
return <LazyComponent className="RootLoader" />;
}

return (
Expand Down
32 changes: 20 additions & 12 deletions packages/amis-core/src/SchemaRenderer.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@ import {isValidElementType} from 'react-is';
import LazyComponent from './components/LazyComponent';
import {
filterSchema,
loadRenderer,
loadRendererError,
loadAsyncRenderer,
registerRenderer,
RendererConfig,
RendererEnv,
RendererProps,
Expand Down Expand Up @@ -268,7 +270,7 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
const omitList = RENDERER_TRANSMISSION_OMIT_PROPS.concat();
if (this.renderer) {
const Component = this.renderer.component;
Component.propsList &&
Component?.propsList &&
omitList.push.apply(omitList, Component.propsList as Array<string>);
}

Expand Down Expand Up @@ -402,8 +404,7 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
} else if (!this.renderer) {
return rest.invisible ? null : (
<LazyComponent
{...rest}
{...exprProps}
defaultVisible={true}
getComponent={async () => {
const result = await rest.env.loadRenderer(
schema,
Expand All @@ -417,14 +418,20 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
}

this.reRender();
return () => loadRenderer(schema, $path);
return () => loadRendererError(schema, $path);
}}
/>
);
} else if (this.renderer.getComponent && !this.renderer.component) {
// 处理异步渲染器
return rest.invisible ? null : (
<LazyComponent
defaultVisible={true}
getComponent={async () => {
await loadAsyncRenderer(this.renderer as RendererConfig);
this.reRender();
return () => null;
}}
$path={$path}
$schema={schema}
retry={this.reRender}
rootStore={rootStore}
statusStore={statusStore}
dispatchEvent={this.dispatchEvent}
/>
);
}
Expand All @@ -437,7 +444,7 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
activeKey: defaultActiveKey,
...restSchema
} = schema;
const Component = renderer.component;
const Component = renderer.component!;

// 原来表单项的 visible: false 和 hidden: true 表单项的值和验证是有效的
// 而 visibleOn 和 hiddenOn 是无效的,
Expand All @@ -463,6 +470,7 @@ export class SchemaRenderer extends React.Component<SchemaRendererProps, any> {
Component.prototype?.isReactComponent ||
(Component as any).$$typeof === Symbol.for('react.forward_ref');
let props: any = {
...renderer.defaultProps?.(schema.type, schema),
...theme.getRendererConfig(renderer.name),
...restSchema,
...chainEvents(rest, restSchema),
Expand Down
19 changes: 14 additions & 5 deletions packages/amis-core/src/components/LazyComponent.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,16 @@

import React from 'react';
import {InView} from 'react-intersection-observer';
import {themeable, ThemeProps} from '../theme';

export interface LazyComponentProps {
export interface LazyComponentProps extends ThemeProps {
component?: React.ElementType;
getComponent?: () => Promise<React.ElementType>;
placeholder?: React.ReactNode;
unMountOnHidden?: boolean;
childProps?: object;
defaultVisible?: boolean;
className?: string;
[propName: string]: any;
}

Expand All @@ -21,7 +24,7 @@ export interface LazyComponentState {
component?: React.ElementType;
}

export default class LazyComponent extends React.Component<
export class LazyComponent extends React.Component<
LazyComponentProps,
LazyComponentState
> {
Expand All @@ -39,14 +42,14 @@ export default class LazyComponent extends React.Component<
this.mounted = true;

this.state = {
visible: false,
visible: props.defaultVisible ?? false,
component: props.component as React.ElementType
};
}

componentDidMount() {
// jest 里面有点异常,先手动让它总是可见
if (typeof jest !== 'undefined') {
if (typeof jest !== 'undefined' || this.state.visible) {
this.handleVisibleChange(true);
}
}
Expand Down Expand Up @@ -92,8 +95,10 @@ export default class LazyComponent extends React.Component<
childProps,
partialVisibility,
children,
className,
...rest
} = this.props;
const cx = this.props.classnames;

const {visible, component: Component} = this.state;

Expand Down Expand Up @@ -144,6 +149,10 @@ export default class LazyComponent extends React.Component<
return children;
}

return <div>{placeholder}</div>;
return <div className={cx('LazyComponent', className)}>{placeholder}</div>;
}
}

const themedLazyComponent = themeable(LazyComponent);
(themedLazyComponent as any).defaultProps = LazyComponent.defaultProps;
export default themedLazyComponent;
Loading
Loading