{
- let original;
- beforeEach(() => {
- original = HTMLElement.prototype.getBoundingClientRect;
- // @ts-ignore
- HTMLElement.prototype.getBoundingClientRect = () => ({
- width: 500,
- height: 0,
- });
-
- // Reset the extensions loaded state
- molecule.extension.setLoaded(false);
- });
+describe('The create function', () => {
afterEach(() => {
- HTMLElement.prototype.getBoundingClientRect = original;
+ clearInstance();
});
- test('Match The MoleculeProvider snapshot', () => {
- const { asFragment } = render(
-
-
-
- );
- expect(asFragment()).toMatchSnapshot();
+ test('Should create an instance', () => {
+ const instance = create({});
+ expect(instance).toBeInstanceOf(InstanceService);
});
- test('MoleculeProvider should render built-in Workbench extensions', () => {
- render(
-
-
-
- );
- expect(
- select('div[data-id="sidebar.explore.title"]')
- ).toBeInTheDocument();
- expect(
- select('div[data-id="sidebar.search.title"]')
- ).toBeInTheDocument();
- expect(select('.mo-welcome')).toBeInTheDocument();
- expect(
- select('div[id="statusbar.problems.title"]')
- ).toBeInTheDocument();
- });
+ test('Should to be a standalone', () => {
+ const instance = create({});
+ const nextInstance = create({});
- test('MoleculeProvider load the extensions', async () => {
- render(
-
-
-
- );
- await expect(
- select('div[data-id="ActivityBarTestPane"]')
- ).toBeInTheDocument();
+ expect(instance).toBe(nextInstance);
});
- test('MoleculeProvider load the locale language extensions', () => {
- localStorage.removeItem('mo.localeId');
+ test('Should call methods normally', () => {
+ create({});
+ molecule.editor.isOpened(1);
+ });
+});
- render(
-
+describe('The molecule Provider', () => {
+ test('Match the Snapshot', () => {
+ const { asFragment } = render(
+
-
+
);
+ expect(asFragment()).toMatchSnapshot();
});
});
diff --git a/src/provider/create.ts b/src/provider/create.ts
new file mode 100644
index 000000000..beaaf8925
--- /dev/null
+++ b/src/provider/create.ts
@@ -0,0 +1,48 @@
+import { IExtension } from 'mo/model';
+import InstanceService from 'mo/services/instanceService';
+
+export interface IConfigProps {
+ /**
+ * Molecule Extension instances, after the MoleculeProvider
+ * did mount, then handle it.
+ */
+ extensions?: IExtension[];
+ /**
+ * Specify a default locale Id, the Molecule built-in `zh-CN`, `en` two languages, and
+ * default locale Id is `en`.
+ */
+ defaultLocale?: string;
+}
+
+namespace stanalone {
+ let instance: InstanceService | null = null;
+
+ /**
+ * Create an instance
+ */
+ export function create(config: IConfigProps) {
+ if (instance) {
+ return instance;
+ }
+ instance = new InstanceService(config);
+ return instance;
+ }
+
+ /**
+ * Do NOT call it in production, ONLY used for test cases
+ */
+ export function clearInstance() {
+ instance = null;
+ }
+}
+
+export default function create(config: IConfigProps) {
+ return stanalone.create(config);
+}
+
+/**
+ * Do NOT call it in production, ONLY used for test cases
+ */
+export function clearInstance() {
+ stanalone.clearInstance();
+}
diff --git a/src/provider/index.tsx b/src/provider/index.tsx
index 84b9d21ac..1a07838e1 100644
--- a/src/provider/index.tsx
+++ b/src/provider/index.tsx
@@ -1 +1,3 @@
export * from 'mo/provider/molecule';
+
+export { default as create } from './create';
diff --git a/src/provider/molecule.tsx b/src/provider/molecule.tsx
index a2f0c80c6..31dc678a2 100644
--- a/src/provider/molecule.tsx
+++ b/src/provider/molecule.tsx
@@ -1,121 +1,19 @@
-import 'reflect-metadata';
-import { container } from 'tsyringe';
-import React, { createContext, Component } from 'react';
-
-import { defaultExtensions } from 'mo/extensions';
-import { BuiltInId } from 'mo/extensions/locales-defaults';
-import { IExtension } from 'mo/model/extension';
-import {
- ExtensionService,
- IExtensionService,
-} from 'mo/services/extensionService';
-import { LocaleService, ILocaleService } from 'mo/i18n';
-import { STORE_KEY, DEFAULT_LOCALE_ID } from 'mo/i18n/localeService';
-import { IMonacoService, MonacoService } from 'mo/monaco/monacoService';
-import { ILayoutService, LayoutService } from 'mo/services';
-import * as controllers from 'mo/controller';
-import type { Controller } from 'mo/react';
-
-export interface IMoleculeProps {
- /**
- * Molecule Extension instances, after the MoleculeProvider
- * did mount, then handle it.
- */
- extensions?: IExtension[];
- /**
- * Specify a default locale Id, the Molecule built-in `zh-CN`, `en` two languages, and
- * default locale Id is `en`.
- */
- defaultLocale?: string;
-}
-export interface IMoleculeState {}
-
-export const MoleculeCtx = createContext({});
-
-export class MoleculeProvider extends Component
{
- private readonly extensionService!: IExtensionService;
- private readonly monacoService!: IMonacoService;
- private readonly layoutService!: ILayoutService;
- private readonly localeService!: ILocaleService;
-
- constructor(props: IMoleculeProps) {
- super(props);
-
- this.monacoService = container.resolve(MonacoService);
- this.extensionService = container.resolve(ExtensionService);
- this.layoutService = container.resolve(LayoutService);
- this.localeService = container.resolve(LocaleService);
- }
-
- componentDidMount() {
- // The monacoService needs to be initialized each time the MoleculeProvider is loaded to
- // ensure that Keybinding events can be bound to the latest dom.
- this.monacoService.initWorkspace(this.layoutService.container!);
-
- if (!this.extensionService.isLoaded()) {
- this.initialize();
- }
- }
-
- initialize() {
- const { extensions = [] } = this.props;
-
- const [languages, restExts] =
- this.extensionService.splitLanguagesExts(extensions);
-
- // Molecule should load the language extensions first to
- // ensure that the custom language extensions is registered in localeService
- this.initLocaleExts(languages);
-
- // The Workbench depends on the monaco and locale extension
- this.initWorkbenchUI();
-
- // Init the built-in extensions
- this.extensionService.load(defaultExtensions);
-
- // Finally, handle the rest of extensions
- this.extensionService.load(restExts);
-
- // Mark the extensionService as loaded
- this.extensionService.setLoaded();
- }
-
- initLocaleExts(languages: IExtension[]) {
- const { defaultLocale = BuiltInId } = this.props;
-
- this.extensionService.load(languages);
-
- // And Molecule should set the correct locale before loading normal extensions in case of
- // the localize method returns incorrect international text caused by incorrect current locale in the normal extensions
- const currentLocale = localStorage.getItem(STORE_KEY) || defaultLocale;
- const preDefaultLocale = localStorage.getItem(DEFAULT_LOCALE_ID);
- let finalLocale = currentLocale;
-
- if (defaultLocale !== preDefaultLocale) {
- finalLocale = defaultLocale;
- }
-
- this.localeService.setCurrentLocale(finalLocale);
- localStorage.setItem(DEFAULT_LOCALE_ID, defaultLocale);
- }
-
- /**
- * Register all controllers and execute the initView method automatically to inject the default value
- * into the corresponding service
- */
- initWorkbenchUI() {
- Object.keys(controllers).forEach((key) => {
- const module = controllers[key];
- const controller = container.resolve(module);
- controller.initView?.();
+import React, { useLayoutEffect } from 'react';
+import create, { IConfigProps } from './create';
+
+export default function Provider({
+ defaultLocale,
+ extensions,
+ children,
+}: IConfigProps & { children: React.ReactElement }) {
+ useLayoutEffect(() => {
+ const instance = create({
+ defaultLocale,
+ extensions,
});
- }
- public render() {
- return (
-
- {this.props.children}
-
- );
- }
+ instance.render(children);
+ }, []);
+
+ return children;
}
diff --git a/src/services/__tests__/__snapshots__/instanceService.test.tsx.snap b/src/services/__tests__/__snapshots__/instanceService.test.tsx.snap
new file mode 100644
index 000000000..35b9d2ecd
--- /dev/null
+++ b/src/services/__tests__/__snapshots__/instanceService.test.tsx.snap
@@ -0,0 +1,9 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`The InstanceService Should support render workbench 1`] = `
+
+
+ 123
+
+
+`;
diff --git a/src/services/__tests__/instanceService.test.tsx b/src/services/__tests__/instanceService.test.tsx
new file mode 100644
index 000000000..58e443ca0
--- /dev/null
+++ b/src/services/__tests__/instanceService.test.tsx
@@ -0,0 +1,46 @@
+import React from 'react';
+import { defaultExtensions } from 'mo/extensions';
+import InstanceService from '../instanceService';
+import { render } from '@testing-library/react';
+
+describe('The InstanceService', () => {
+ test('Constuctor with default config', () => {
+ const instance = new InstanceService({});
+ const config = instance.getConfig();
+ expect(config.defaultLocale).toBe('en');
+ expect(config.extensions).toEqual(defaultExtensions);
+ });
+
+ test('Should init with params', () => {
+ const instance = new InstanceService({
+ defaultLocale: 'test',
+ extensions: [
+ {
+ id: 1,
+ name: 'test',
+ activate: () => {},
+ dispose: () => {},
+ },
+ ],
+ });
+ const config = instance.getConfig();
+ expect(config.defaultLocale).toBe('test');
+ expect(config.extensions).toHaveLength(defaultExtensions.length + 1);
+ });
+
+ test('Should support render workbench', () => {
+ const instance = new InstanceService({});
+ const { asFragment } = render(instance.render(123
));
+ expect(asFragment()).toMatchSnapshot();
+ });
+
+ test('Should support liftCycle hooks', () => {
+ const instance = new InstanceService({});
+ const mockFn = jest.fn();
+ instance.onBeforeInit(mockFn);
+ instance.onBeforeLoad(mockFn);
+ instance.render(123
);
+
+ expect(mockFn).toBeCalledTimes(2);
+ });
+});
diff --git a/src/services/__tests__/settingsService.test.ts b/src/services/__tests__/settingsService.test.ts
index a61cf99fe..f69054f10 100644
--- a/src/services/__tests__/settingsService.test.ts
+++ b/src/services/__tests__/settingsService.test.ts
@@ -1,4 +1,3 @@
-import { BuiltInDefault } from 'mo/i18n/localization';
import { ISettings, SettingsEvent } from 'mo/model/settings';
import 'reflect-metadata';
import { SettingsService } from '../settingsService';
@@ -25,7 +24,7 @@ describe('Test the SettingsService', () => {
const config = settingsService.getSettings();
expect(config.colorTheme).toEqual(BuiltInColorTheme.id);
expect(config.editor).toEqual({});
- expect(config.locale).toEqual(BuiltInDefault.id);
+ expect(config.locale).toBeUndefined();
});
test('Append a new setting item', () => {
@@ -60,7 +59,7 @@ describe('Test the SettingsService', () => {
settingsService.update(expectedSettings);
const config = settingsService.getSettings() as TestSetting;
expect(config.colorTheme).toEqual(BuiltInColorTheme.id);
- expect(config.locale).toEqual(BuiltInDefault!.id);
+ expect(config.locale).toBeUndefined();
expect(config.editor?.tabSize).toBe(expectedSettings.editor.tabSize);
expect(config.project).toEqual(expectedSettings.project);
});
diff --git a/src/services/instanceService.tsx b/src/services/instanceService.tsx
new file mode 100644
index 000000000..fee90f1a5
--- /dev/null
+++ b/src/services/instanceService.tsx
@@ -0,0 +1,92 @@
+import { ReactElement } from 'react';
+import { ILocale } from 'mo/i18n';
+import { container } from 'tsyringe';
+import * as controllers from 'mo/controller';
+import type { Controller } from 'mo/react';
+import { defaultExtensions } from 'mo/extensions';
+import { GlobalEvent } from 'mo/common/event';
+import { IConfigProps } from 'mo/provider/create';
+import { IExtension } from 'mo/model';
+import { STORE_KEY } from 'mo/i18n/localeService';
+import molecule from 'mo';
+
+interface IInstanceServiceProps {
+ getConfig: () => IConfigProps;
+ render: (dom: ReactElement) => ReactElement;
+ onBeforeInit: (callback: () => void) => void;
+ onBeforeLoad: (callback: () => void) => void;
+}
+
+enum InstanceHookKind {
+ beforeInit = 'before.init',
+ beforeLoad = 'before.load',
+}
+
+export default class InstanceService
+ extends GlobalEvent
+ implements IInstanceServiceProps
+{
+ private _config = {
+ extensions: defaultExtensions.concat(),
+ defaultLocale: 'en',
+ };
+
+ constructor(config: IConfigProps) {
+ super();
+ if (config.defaultLocale) {
+ this._config.defaultLocale = config.defaultLocale;
+ }
+
+ if (Array.isArray(config.extensions)) {
+ this._config.extensions.push(...config.extensions);
+ }
+ }
+
+ private initialLocaleService = (languagesExts: IExtension[]) => {
+ const locales = languagesExts.reduce((pre, cur) => {
+ const languages = cur.contributes?.languages || [];
+ return pre.concat(languages);
+ }, [] as ILocale[]);
+
+ molecule.i18n.initialize(
+ locales,
+ localStorage.getItem(STORE_KEY) || this._config.defaultLocale
+ );
+ };
+
+ public getConfig: () => IConfigProps = () => {
+ return Object.assign({}, this._config);
+ };
+
+ public render = (workbench: ReactElement) => {
+ this.emit(InstanceHookKind.beforeInit);
+
+ // get all locales including builtin and custom locales
+ const [languages, others] = molecule.extension.splitLanguagesExts(
+ this._config.extensions
+ );
+ this.initialLocaleService(languages);
+
+ // resolve all controllers, and call `initView` to inject initial values into services
+ Object.keys(controllers).forEach((key) => {
+ const module = controllers[key];
+ const controller = container.resolve(module);
+ controller.initView?.();
+ });
+
+ this.emit(InstanceHookKind.beforeLoad);
+ molecule.extension.load(others);
+
+ molecule.monacoService.initWorkspace(molecule.layout.container!);
+
+ return workbench;
+ };
+
+ public onBeforeInit = (callback: () => void) => {
+ this.subscribe(InstanceHookKind.beforeInit, callback);
+ };
+
+ public onBeforeLoad = (callback: () => void) => {
+ this.subscribe(InstanceHookKind.beforeLoad, callback);
+ };
+}
diff --git a/src/services/settingsService.ts b/src/services/settingsService.ts
index b4dab821f..513489682 100644
--- a/src/services/settingsService.ts
+++ b/src/services/settingsService.ts
@@ -107,7 +107,7 @@ export class SettingsService extends GlobalEvent implements ISettingsService {
const editorOptions = this.editorService.getState().editorOptions;
const theme = this.colorThemeService.getColorTheme();
const locale = this.localeService.getCurrentLocale();
- return new SettingsModel(theme.id, editorOptions!, locale!.id);
+ return new SettingsModel(theme.id, editorOptions!, locale?.id);
}
public getDefaultSettingsTab(): BuiltInSettingsTabType {
diff --git a/src/workbench/notification/__tests__/localeNotification.test.tsx b/src/workbench/notification/__tests__/localeNotification.test.tsx
index f0c361240..5ef4ddaa8 100644
--- a/src/workbench/notification/__tests__/localeNotification.test.tsx
+++ b/src/workbench/notification/__tests__/localeNotification.test.tsx
@@ -1,10 +1,18 @@
+import 'reflect-metadata';
import React from 'react';
-import { fireEvent, render } from '@testing-library/react';
import { create } from 'react-test-renderer';
+import { container } from 'tsyringe';
+import { LocaleService } from 'mo/i18n';
+import { ExtendsLocales } from 'mo/extensions/locales-defaults';
+import { fireEvent, render } from '@testing-library/react';
import LocaleNotification from '../notificationPane/localeNotification';
import '@testing-library/jest-dom';
describe('The LocaleNotification Component', () => {
+ // initial locales
+ const localeService = container.resolve(LocaleService);
+ localeService.initialize(ExtendsLocales.contributes!.languages!, 'en');
+
test('Match Snapshot', () => {
const component = create();
expect(component.toJSON()).toMatchSnapshot();
diff --git a/src/workbench/notification/__tests__/notificationPane.test.tsx b/src/workbench/notification/__tests__/notificationPane.test.tsx
index 8c346d8e7..b00985092 100644
--- a/src/workbench/notification/__tests__/notificationPane.test.tsx
+++ b/src/workbench/notification/__tests__/notificationPane.test.tsx
@@ -1,3 +1,4 @@
+import 'reflect-metadata';
import React from 'react';
import { fireEvent, render } from '@testing-library/react';
import renderer from 'react-test-renderer';
@@ -9,8 +10,15 @@ import {
} from '../notificationPane';
import { select } from 'mo/common/dom';
import { expectFnCalled } from '@test/utils';
+import { container } from 'tsyringe';
+import { ExtendsLocales } from 'mo/extensions/locales-defaults';
+import { LocaleService } from 'mo/i18n';
describe('Test NotificationPane Component', () => {
+ // initial locales
+ const localeService = container.resolve(LocaleService);
+ localeService.initialize(ExtendsLocales.contributes!.languages!, 'en');
+
test('Match The NotificationPane snapshot', () => {
const component = renderer.create(
diff --git a/src/workbench/panel/__tests__/panel.test.tsx b/src/workbench/panel/__tests__/panel.test.tsx
index cd5207829..d12692987 100644
--- a/src/workbench/panel/__tests__/panel.test.tsx
+++ b/src/workbench/panel/__tests__/panel.test.tsx
@@ -1,3 +1,4 @@
+import 'reflect-metadata';
import React from 'react';
import { render } from '@testing-library/react';
import renderer from 'react-test-renderer';
@@ -10,6 +11,9 @@ import { select } from 'mo/common/dom';
import { modules } from 'mo/services/builtinService/const';
import { cloneDeep } from 'lodash';
import Output from '../output';
+import { container } from 'tsyringe';
+import { ExtendsLocales } from 'mo/extensions/locales-defaults';
+import { LocaleService } from 'mo/i18n';
function panelMockModel(): PanelModel {
const output = modules.builtInOutputPanel();
@@ -32,6 +36,10 @@ function panelMockModel(): PanelModel {
}
describe('Test Panel Component', () => {
+ // initial locales
+ const localeService = container.resolve(LocaleService);
+ localeService.initialize(ExtendsLocales.contributes!.languages!, 'en');
+
test('Match the PanelView snapshot', () => {
const component = renderer.create();
expect(component.toJSON()).toMatchSnapshot();
diff --git a/src/workbench/sidebar/__tests__/editorTree.test.tsx b/src/workbench/sidebar/__tests__/editorTree.test.tsx
index 764a32baf..59e58a067 100644
--- a/src/workbench/sidebar/__tests__/editorTree.test.tsx
+++ b/src/workbench/sidebar/__tests__/editorTree.test.tsx
@@ -1,3 +1,4 @@
+import 'reflect-metadata';
import React from 'react';
import renderer from 'react-test-renderer';
import { cleanup, fireEvent, render } from '@testing-library/react';
@@ -10,6 +11,9 @@ import {
editorTreeGroupClassName,
} from '../explore/base';
import { constants } from 'mo/services/builtinService/const';
+import { container } from 'tsyringe';
+import { LocaleService } from 'mo/i18n';
+import { ExtendsLocales } from 'mo/extensions/locales-defaults';
const PaneEditorTree = (props: Omit) => {
return ;
@@ -73,6 +77,10 @@ jest.mock('react', () => {
});
describe('The EditorTree Component', () => {
+ // initial locales
+ const localeService = container.resolve(LocaleService);
+ localeService.initialize(ExtendsLocales.contributes!.languages!, 'en');
+
afterEach(cleanup);
test('Match Snapshot', () => {
diff --git a/stories/workbench/0-Workbench.stories.tsx b/stories/workbench/0-Workbench.stories.tsx
index d1bf41059..ecb9519e2 100644
--- a/stories/workbench/0-Workbench.stories.tsx
+++ b/stories/workbench/0-Workbench.stories.tsx
@@ -1,19 +1,28 @@
import React from 'react';
-import { MoleculeProvider, Workbench } from 'mo';
+import molecule, { create, Workbench } from 'mo';
import 'mo/style/mo.scss';
import { customExtensions } from '../extensions';
import '../demo.scss';
-export const IDEDemo = () => (
-
-
-
-);
+const moInstance = create({
+ extensions: customExtensions,
+ defaultLocale: 'japanese',
+});
+
+moInstance.onBeforeInit(() => {
+ molecule.builtin.inactiveModule('activityBarData');
+});
+
+export const IDEDemo = () => moInstance.render();
IDEDemo.story = {
name: 'Workbench',
};
+if (module.hot) {
+ module.hot.accept();
+}
+
export default {
title: 'Workbench',
component: IDEDemo,
diff --git a/website/docs/guides/builtin.md b/website/docs/guides/builtin.md
new file mode 100644
index 000000000..a2588b79d
--- /dev/null
+++ b/website/docs/guides/builtin.md
@@ -0,0 +1,66 @@
+---
+title: Builtin
+sidebar_label: Builtin
+---
+
+For convenience, molecule has some built-in data to initialize the layout UI. But sometimes, you don't need some default data. For example now, we want to initialize an application without the default activity bar.
+
+In `src/App.js`, we get this code:
+
+```js title="src/App.js"
+import React from 'react';
+import { create, Workbench } from '@dtinsight/molecule';
+import '@dtinsight/molecule/esm/style/mo.css';
+
+const moInstance = create({
+ extensions: [],
+});
+
+const App = () => moInstance.render();
+
+export default App;
+```
+
+And we have a service named `builtinService` to manage the built-in data. So if we want to **disable** the default activity bar, we could call `molecule.builtin.inactiveModule` method to set module inactive.
+
+But here is a question where should I call this method?
+
+It's not working that you call `inactiveModule` method in extensions, because when molecule loads extensions, the layout UI already initialized with built-in data. It's obviously not working if you inactive a module after actived.
+
+## hooks
+
+For solving the timing problems, there are some hooks you can call from moInstance.
+
+### onBeforeInit
+
+The `onBeforeInit` is called before initializing. At this time, the layout UI isn't initialized yet. And the extensions are not loaded too.
+
+You can disable some built-in data at this hook.
+
+### onBeforeLoad
+
+The `onBeforeLoad` is called before loading extensions. At this time, the layout UI is initialized. But the extensions are not loaded.
+
+You can't disable some built-in data at this hook. But You can inactive some extensions at this hook.
+
+## Example
+
+```js title="src/App.js"
+import React from 'react';
+import { create, Workbench } from '@dtinsight/molecule';
+import '@dtinsight/molecule/esm/style/mo.css';
+
+const moInstance = create({
+ extensions: [],
+});
+
+moInstance.onBeforeInit(() => {
+ molecule.builtin.inactiveModule('activityBarData');
+});
+
+const App = () => moInstance.render();
+
+export default App;
+```
+
+The module you can refer to [constants](https://github.com/DTStack/molecule/blob/main/src/services/builtinService/const.ts#L96)
diff --git a/website/docs/guides/extend-color-theme.md b/website/docs/guides/extend-color-theme.md
index c0bd335e9..c30e68d16 100644
--- a/website/docs/guides/extend-color-theme.md
+++ b/website/docs/guides/extend-color-theme.md
@@ -93,13 +93,9 @@ Finally, we add the extension package in `App.js`
```js title="src/App.js"
import { OneDarkPro } from './extensions/OneDark-Pro';
-function App() {
- return (
-
-
-
- );
-}
+const moInstance = create({
+ extensions: [OneDarkPro],
+});
```
We can use the shortcut key `Command/Ctrl + K` to quickly access the **Color Theme Panel**.
@@ -215,19 +211,15 @@ export { MyTheme };
### Apply color theme extension
-Similarly, custom theme extensions are also need to be introduced in the [MoleculeProvider](../api/classes/MoleculeProvider) component in `App.js`:
+Similarly, custom theme extensions are also need to be introduced in the params of [create](../api#create) component in `App.js`:
```js title="src/App.js"
import { OneDarkPro } from './extensions/OneDark-Pro';
import { MyTheme } from './extensions/MyTheme';
-function App() {
- return (
-
-
-
- );
-}
+const moInstance = create({
+ extensions: [OneDarkPro, MyTheme],
+});
```
Open **the color theme quick access panel**, we should be able to see the theme of `My Theme`. After selecting this theme, the **background color** of the [StatusBar](extend-workbench#statusbar) at the bottom changes to red.
diff --git a/website/docs/guides/extension.md b/website/docs/guides/extension.md
index 8e3d7fba7..23feeb1ba 100644
--- a/website/docs/guides/extension.md
+++ b/website/docs/guides/extension.md
@@ -66,33 +66,30 @@ In some cases, you may want to **disable** some built-in extensions in Molecule.
```ts
import React from 'react';
-import molecule from '@dtinsight/molecule';
-import { MoleculeProvider, Workbench } from '@dtinsight/molecule';
+import molecule, { create, Workbench } from '@dtinsight/molecule';
import '@dtinsight/molecule/esm/style/mo.css';
// All Extension instances
import extensions from './extensions';
-molecule.extension.inactive((extension: IExtension) => {
- // Inactive the Extension which id is ExampleExt
- if (extension.id === 'ExampleExt') {
- return true;
- }
+const moInstance = create({
+ extensions,
});
-function App() {
- return (
-
-
-
- );
-}
+moInstance.onBeforeLoad(() => {
+ molecule.extension.inactive((ext) => {
+ // Inactive the Extension which id is ExampleExt
+ return extension.id === 'ExampleExt';
+ });
+});
+
+const App = () => moInstance.render();
export default App;
```
:::caution
-It should be noted that the [inactive][inactive-url] method needs to be declared before [MoleculeProvider](../api/classes/MoleculeProvider).
+It should be noted that the [inactive][inactive-url] method needs to be declared after [create](../api#create).
:::
[inactive-url]: ../api/interfaces/molecule.IExtensionService#inactive
diff --git a/website/docs/introduction.md b/website/docs/introduction.md
index b15b8ecf6..014161d3f 100644
--- a/website/docs/introduction.md
+++ b/website/docs/introduction.md
@@ -52,14 +52,14 @@ yarn add @dtinsight/molecule
```javascript
import React from 'react';
import ReactDOM from 'react-dom';
-import { MoleculeProvider, Workbench } from '@dtinsight/molecule';
+import { create, Workbench } from '@dtinsight/molecule';
import '@dtinsight/molecule/esm/style/mo.css';
-const App = () => (
-
-
-
-);
+const moInstance = create({
+ extensions: [],
+});
+
+const App = () => moInstance.render();
ReactDOM.render(, document.getElementById('root'));
```
diff --git a/website/docs/quick-start.md b/website/docs/quick-start.md
index 47dae66ee..5094f98a7 100644
--- a/website/docs/quick-start.md
+++ b/website/docs/quick-start.md
@@ -47,16 +47,14 @@ Open the `src/App.js` file and replace the contents of the file with the followi
```js title="src/App.js"
import React from 'react';
-import { MoleculeProvider, Workbench } from '@dtinsight/molecule';
+import { create, Workbench } from '@dtinsight/molecule';
import '@dtinsight/molecule/esm/style/mo.css';
-function App() {
- return (
-
-
-
- );
-}
+const moInstance = create({
+ extensions: [],
+});
+
+const App = () => moInstance.render();
export default App;
```
diff --git a/website/docs/the-first-extension.md b/website/docs/the-first-extension.md
index b3196ea48..edc566511 100644
--- a/website/docs/the-first-extension.md
+++ b/website/docs/the-first-extension.md
@@ -99,7 +99,7 @@ Pay more attention: In reality, the **data type** returned by `API.getFolderTree
### Use extension
-After defining class `FirstExtension`, it is used with [MoleculeProvider][provider-url]. Here we export all **extension objects** that need to be loaded in `extensions/index.ts` by default:
+After defining class `FirstExtension`, it is used with [create][create-url]. Here we export all **extension objects** that need to be loaded in `extensions/index.ts` by default:
```ts title="/src/extensions/index.ts"
import { IExtension } from '@dtinsight/molecule/esm/model';
@@ -115,12 +115,12 @@ Import the `FirstExtension` object and instantiate it, and finally use `extensio
```tsx title="/src/app.tsx"
import extensions from './extensions';
-
-
-;
+const moInstance = create({
+ extensions,
+});
```
-Finally, introduce `extensions` and pass in the `extensions` property of [MoleculeProvider][provider-url].
+Finally, introduce `extensions` and pass in the `extensions` property of [create][create-url].
:::info
The above example is just a very simple application scenario. If you want to achieve a richer extension to [Workbench](/guides/extend-workbench.md), you can refer to [Workbench Extension Guide](./guides/extend-workbench.md) ).
@@ -137,4 +137,4 @@ Please [view][demo-url] the complete source code of **First Extension**
[demo-url]: https://github.com/DTStack/molecule-examples/tree/main/packages/molecule-demo/src/extensions/theFirstExtension
[foldertree-url]: ./guides/extend-builtin-ui#foldertree
-[provider-url]: ./api/classes/MoleculeProvider
+[create-url]: ./api#create
diff --git a/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/guides/builtin.md b/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/guides/builtin.md
new file mode 100644
index 000000000..7153c1b82
--- /dev/null
+++ b/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/guides/builtin.md
@@ -0,0 +1,66 @@
+---
+title: 内置数据(Builtin)
+sidebar_label: 内置数据
+---
+
+为了方便用户,Molecule 会用一些内置数据来初始化 UI 界面。但是有时候,用户并不需要这些默认的数据。举个例子,如果我们这时候想要初始化一个没有默认 activity bar 数据的 Molecule 应用。
+
+在 `src/App.js` 文件中, 我们有如下代码:
+
+```js title="src/App.js"
+import React from 'react';
+import { create, Workbench } from '@dtinsight/molecule';
+import '@dtinsight/molecule/esm/style/mo.css';
+
+const moInstance = create({
+ extensions: [],
+});
+
+const App = () => moInstance.render();
+
+export default App;
+```
+
+然后 Molecule 中有一个 `builtinService` 服务,用来管理内置数据。如果我们想要**禁用**默认的 activity bar,我们可以通过调用 `molecule.builtin.inactiveModule` 方法来禁用默认模块。
+
+但是我们应该在什么地方调用这个方法呢?
+
+如果我们在扩展(Extensions)里调用 `inactiveModule` 方法是不生效的。因为当 molecule 加载扩展的时候,界面 UI 早已经初始化成功了,而默认数据也早已经加载到页面上。所以很明显在初始化成功之后去禁用默认模块是不生效的。
+
+## hooks
+
+为了解决调用的时机问题,我们有一些 hooks 以供调用。
+
+### onBeforeInit
+
+`onBeforeInit` 是在初始化之前被调用。在这个阶段,界面 UI 还未初始化,扩展(Extensions)也还没加载。
+
+用户可以在这个 hook 去禁用默认数据。
+
+### onBeforeLoad
+
+`onBeforeLoad` 是在加载扩展之前,初始化界面之后。在这个阶段,界面 UI 已经初始化,但是扩展还没加载。
+
+在这个界面,用户禁用默认数据会失效。但是可以禁用扩展(Extensions)。
+
+## 例子
+
+```js title="src/App.js"
+import React from 'react';
+import { create, Workbench } from '@dtinsight/molecule';
+import '@dtinsight/molecule/esm/style/mo.css';
+
+const moInstance = create({
+ extensions: [],
+});
+
+moInstance.onBeforeInit(() => {
+ molecule.builtin.inactiveModule('activityBarData');
+});
+
+const App = () => moInstance.render();
+
+export default App;
+```
+
+模块默认值可以参考 [内置数据变量](https://github.com/DTStack/molecule/blob/main/src/services/builtinService/const.ts#L96)
diff --git a/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/guides/extend-color-theme.md b/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/guides/extend-color-theme.md
index ccd09a3e7..b845dbfcb 100644
--- a/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/guides/extend-color-theme.md
+++ b/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/guides/extend-color-theme.md
@@ -93,13 +93,11 @@ export { OneDarkPro };
```js title="src/App.js"
import { OneDarkPro } from './extensions/OneDark-Pro';
-function App() {
- return (
-
-
-
- );
-}
+const moInstance = create({
+ extensions: [OneDarkPro],
+});
+
+const App = () => moInstance.render();
```
我们可以通过快捷键 `Command/Ctrl + K` 快速访问**「颜色主题面板」**。
@@ -216,19 +214,17 @@ export { MyTheme };
### 应用颜色主题扩展
-同样, 自定义的主题扩展程序也是在 `App.js` 中的 [MoleculeProvider](../api/classes/MoleculeProvider) 组件中引入:
+同样, 自定义的主题扩展程序也是在 `App.js` 中的 [create](../api#create) 方法中传入:
```js title="src/App.js"
import { OneDarkPro } from './extensions/OneDark-Pro';
import { MyTheme } from './extensions/MyTheme';
-function App() {
- return (
-
-
-
- );
-}
+const moInstance = create({
+ extensions: [OneDarkPro, MyTheme],
+});
+
+const App = () => moInstance.render();
```
打开在**颜色主题快速访问面板**,我们应该就能看到 `My Theme` 的主题了。选择该主题后,底部 [StatusBar](extend-workbench#状态栏statusbar) 的**背景颜色**即变成了红色。
diff --git a/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/guides/extension.md b/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/guides/extension.md
index 5ce470385..c4a600259 100644
--- a/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/guides/extension.md
+++ b/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/guides/extension.md
@@ -67,32 +67,30 @@ molecule.extension.getExtension(extensionId);
```ts
import React from 'react';
import molecule from '@dtinsight/molecule';
-import { MoleculeProvider, Workbench } from '@dtinsight/molecule';
+import { create, Workbench } from '@dtinsight/molecule';
import '@dtinsight/molecule/esm/style/mo.css';
// All Extension instances
import extensions from './extensions';
-molecule.extension.inactive((extension: IExtension) => {
- // Inactive the Extension which id is ExampleExt
- if (extension.id === 'ExampleExt') {
- return true;
- }
+const moInstance = create({
+ extensions,
});
-function App() {
- return (
-
-
-
- );
-}
+moInstance.onBeforeLoad(() => {
+ molecule.extension.inactive((ext) => {
+ // Inactive the Extension which id is ExampleExt
+ return extension.id === 'ExampleExt';
+ });
+});
+
+const App = () => moInstance.render();
export default App;
```
:::caution
-需要注意到是,[inactive][inactive-url] 方法,需要在 [MoleculeProvider](../api/classes/MoleculeProvider) 之前声明
+需要注意到是,[inactive][inactive-url] 方法,需要在 [create](../api#create) 导出的生命周期 onBeforeLoad 中使用。
:::
[inactive-url]: ../api/interfaces/molecule.IExtensionService#inactive
diff --git a/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/introduction.md b/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/introduction.md
index 9239eb3a5..48b604793 100644
--- a/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/introduction.md
+++ b/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/introduction.md
@@ -52,14 +52,14 @@ yarn add @dtinsight/molecule
```javascript
import React from 'react';
import ReactDOM from 'react-dom';
-import { MoleculeProvider, Workbench } from '@dtinsight/molecule';
+import { create, Workbench } from '@dtinsight/molecule';
import '@dtinsight/molecule/esm/style/mo.css';
-const App = () => (
-
-
-
-);
+const moInstance = create({
+ extensions: [],
+});
+
+const App = () => moInstance.render();
ReactDOM.render(, document.getElementById('root'));
```
diff --git a/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-start.md b/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-start.md
index d86b63b63..312233eef 100644
--- a/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-start.md
+++ b/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/quick-start.md
@@ -47,16 +47,14 @@ npm install @dtinsight/molecule
```js title="src/App.js"
import React from 'react';
-import { MoleculeProvider, Workbench } from '@dtinsight/molecule';
+import { create, Workbench } from '@dtinsight/molecule';
import '@dtinsight/molecule/esm/style/mo.css';
-function App() {
- return (
-
-
-
- );
-}
+const moInstance = create({
+ extensions: [],
+});
+
+const App = () => moInstance.render();
export default App;
```
diff --git a/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/the-first-extension.md b/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/the-first-extension.md
index ed1bfb9dd..1fccea467 100644
--- a/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/the-first-extension.md
+++ b/website/i18n/zh-CN/docusaurus-plugin-content-docs/current/the-first-extension.md
@@ -98,7 +98,7 @@ export function handleSelectFolderTree() {
### 使用扩展
-定义好的 `FirstExtension` 对象,最后需要配合 [MoleculeProvider][provider-url] 来使用。这里我们默认在 `extensions/index.ts` 中导出所有需要加载的**扩展对象**:
+定义好的 `FirstExtension` 对象,最后需要配合 [create][create-url] 来使用。这里我们默认在 `extensions/index.ts` 中导出所有需要加载的**扩展对象**:
```ts title="/src/extensions/index.ts"
import { IExtension } from '@dtinsight/molecule/esm/model';
@@ -109,17 +109,17 @@ const extensions: IExtension[] = [new FirstExtension()];
export default extensions;
```
-导入 `FirstExtension` 对象并将其实例化,最后使用 `extensions` 导出所有**扩展对象实例**。
+导入 `FirstExtension` 对象并将其实例化,最后使用 `create` 传入所有**扩展对象实例**。
```tsx title="/src/app.tsx"
import extensions from './extensions';
-
-
-;
+const moInstance = create({
+ extensions,
+});
```
-最后,引入 `extensions` 并传入 [MoleculeProvider][provider-url] 的 `extensions` 属性。
+最后,引入 `extensions` 并传入 [create][create-url] 的 `extensions` 参数。
:::info
上例只是一个很简单的应用场景,想要实现对 [Workbench](/guides/extend-workbench.md) 更丰富的扩展,可以参考 [工作台扩展指南](./guides/extend-workbench.md)。
@@ -135,4 +135,4 @@ import extensions from './extensions';
[demo-url]: https://github.com/DTStack/molecule-examples/tree/main/packages/molecule-demo/src/extensions/theFirstExtension
[foldertree-url]: ./guides/extend-builtin-ui#文件树foldertree
-[provider-url]: ./api/classes/MoleculeProvider
+[create-url]: ./api#create
diff --git a/website/sidebars.js b/website/sidebars.js
index 16155caf6..97bcb5846 100644
--- a/website/sidebars.js
+++ b/website/sidebars.js
@@ -22,6 +22,7 @@ module.exports = {
label: 'Guides',
collapsed: false,
items: [
+ 'guides/builtin',
'guides/extension',
{
type: 'category',