From 0bcaa24c812e740a0d53eabcd25202be70136294 Mon Sep 17 00:00:00 2001 From: imtaotao Date: Sat, 3 Jul 2021 19:55:44 +0800 Subject: [PATCH] feat: modify remote component to remote module --- dev/react/linkdeps.js | 2 +- dev/react/public/index.html | 2 +- dev/react/src/App.js | 14 +- dev/react/src/index.js | 2 +- dev/vue/linkdeps.js | 2 +- packages/runtime/core/src/garfish.ts | 6 +- packages/runtime/core/src/interface/index.ts | 6 +- packages/runtime/core/src/module/app.ts | 2 +- packages/runtime/core/src/plugins/preload.ts | 10 +- packages/runtime/core/src/utils.ts | 4 +- packages/runtime/garfish/src/index.ts | 4 +- packages/runtime/loader/src/appCache.ts | 4 +- packages/runtime/loader/src/index.ts | 18 +-- .../runtime/loader/src/managers/component.ts | 17 --- .../runtime/loader/src/managers/module.ts | 17 +++ packages/runtime/remote-component/README.md | 123 ------------------ .../remote-component/src/apis/toEsModule.ts | 6 - .../runtime/remote-component/src/index.ts | 28 ---- .../.npmignore | 0 .../LICENSE | 0 packages/runtime/remote-module/README.md | 121 +++++++++++++++++ .../__tests__/index.spec.ts | 0 .../api-extractor.json | 0 .../package.json | 10 +- .../src/actuator.ts | 12 +- .../remote-module/src/apis/esModule.ts | 6 + .../src/apis/loadModule.ts} | 22 ++-- .../src/apis/loadModuleSync.ts} | 34 ++--- .../src/apis/preload.ts | 6 +- .../src/apis/setExternal.ts | 4 +- .../src/common.ts | 20 +-- .../src/garfishPlugin.ts | 34 ++--- packages/runtime/remote-module/src/index.ts | 28 ++++ packages/runtime/utils/src/domApis.ts | 4 +- 34 files changed, 280 insertions(+), 288 deletions(-) delete mode 100644 packages/runtime/loader/src/managers/component.ts create mode 100644 packages/runtime/loader/src/managers/module.ts delete mode 100644 packages/runtime/remote-component/README.md delete mode 100644 packages/runtime/remote-component/src/apis/toEsModule.ts delete mode 100644 packages/runtime/remote-component/src/index.ts rename packages/runtime/{remote-component => remote-module}/.npmignore (100%) rename packages/runtime/{remote-component => remote-module}/LICENSE (100%) create mode 100644 packages/runtime/remote-module/README.md rename packages/runtime/{remote-component => remote-module}/__tests__/index.spec.ts (100%) rename packages/runtime/{remote-component => remote-module}/api-extractor.json (100%) rename packages/runtime/{remote-component => remote-module}/package.json (79%) rename packages/runtime/{remote-component => remote-module}/src/actuator.ts (62%) create mode 100644 packages/runtime/remote-module/src/apis/esModule.ts rename packages/runtime/{remote-component/src/apis/loadComponent.ts => remote-module/src/apis/loadModule.ts} (72%) rename packages/runtime/{remote-component/src/apis/loadComponentSync.ts => remote-module/src/apis/loadModuleSync.ts} (64%) rename packages/runtime/{remote-component => remote-module}/src/apis/preload.ts (61%) rename packages/runtime/{remote-component => remote-module}/src/apis/setExternal.ts (81%) rename packages/runtime/{remote-component => remote-module}/src/common.ts (70%) rename packages/runtime/{remote-component => remote-module}/src/garfishPlugin.ts (51%) create mode 100644 packages/runtime/remote-module/src/index.ts diff --git a/dev/react/linkdeps.js b/dev/react/linkdeps.js index 8ac36bb40..25a1f7c95 100644 --- a/dev/react/linkdeps.js +++ b/dev/react/linkdeps.js @@ -7,7 +7,7 @@ const { exec } = require('child_process'); '@garfish/browser-vm', '@garfish/core', '@garfish/loader', - '@garfish/remote-component', + '@garfish/remote-module', ].forEach((item) => { console.log(`link ${item}`); exec(`yarn link ${item}`, (error, stdout, stderr) => { diff --git a/dev/react/public/index.html b/dev/react/public/index.html index 3a9f188b5..f6cb2b739 100644 --- a/dev/react/public/index.html +++ b/dev/react/public/index.html @@ -2,7 +2,7 @@ - + diff --git a/dev/react/src/App.js b/dev/react/src/App.js index c9f7af689..bca1547dd 100644 --- a/dev/react/src/App.js +++ b/dev/react/src/App.js @@ -1,9 +1,5 @@ import React, { useState } from 'react'; -import { - toEsModule, - loadComponent, - loadComponentSync, -} from '@garfish/remote-component'; +import { esModule, loadModule, loadModuleSync } from '@garfish/remote-module'; import logo from './logo.svg'; import './App.css'; import { Modal, Button } from 'antd'; @@ -27,14 +23,14 @@ function App() { window.a.b.c = 1; }; - const RemoteComponent = loadComponentSync( + const RemoteComponent = loadModuleSync( 'http://localhost:3000/remoteComponent.js', ).One; const RemoteComponentTwo = React.lazy(() => { - return loadComponent( - 'http://localhost:3000/remoteComponent.js', - ).then((cms) => toEsModule(cms.Two)); + return loadModule('http://localhost:3000/remoteComponent.js').then((cms) => + esModule(cms.Two), + ); }); return ( diff --git a/dev/react/src/index.js b/dev/react/src/index.js index 8e6899aae..1a2dafa63 100644 --- a/dev/react/src/index.js +++ b/dev/react/src/index.js @@ -2,7 +2,7 @@ import React from 'react'; import ReactDOM from 'react-dom'; import './index.css'; import App from './App'; -import { preload, setExternal } from '@garfish/remote-component'; +import { preload, setExternal } from '@garfish/remote-module'; setExternal({ React }); diff --git a/dev/vue/linkdeps.js b/dev/vue/linkdeps.js index 8ac36bb40..25a1f7c95 100644 --- a/dev/vue/linkdeps.js +++ b/dev/vue/linkdeps.js @@ -7,7 +7,7 @@ const { exec } = require('child_process'); '@garfish/browser-vm', '@garfish/core', '@garfish/loader', - '@garfish/remote-component', + '@garfish/remote-module', ].forEach((item) => { console.log(`link ${item}`); exec(`yarn link ${item}`, (error, stdout, stderr) => { diff --git a/packages/runtime/core/src/garfish.ts b/packages/runtime/core/src/garfish.ts index 2b3b9027f..0b3c14a40 100644 --- a/packages/runtime/core/src/garfish.ts +++ b/packages/runtime/core/src/garfish.ts @@ -213,7 +213,7 @@ export class Garfish implements interfaces.Garfish { } else { try { let isHtmlMode, fakeEntryManager; - const resources = { js: [], link: [], components: [] }; // Default resources + const resources = { js: [], link: [], modules: [] }; // Default resources const { resourceManager: entryManager } = await this.loader.load( appName, transformUrl(location.href, appInfo.entry), @@ -222,14 +222,14 @@ export class Garfish implements interfaces.Garfish { // Html entry if (entryManager instanceof TemplateManager) { isHtmlMode = true; - const [js, link, components] = await fetchStaticResources( + const [js, link, modules] = await fetchStaticResources( appName, this.loader, entryManager, ); resources.js = js; resources.link = link; - resources.components = components; + resources.modules = modules; } else if (entryManager instanceof JavaScriptManager) { // Js entry isHtmlMode = false; diff --git a/packages/runtime/core/src/interface/index.ts b/packages/runtime/core/src/interface/index.ts index 7c1586851..448dfc0f8 100644 --- a/packages/runtime/core/src/interface/index.ts +++ b/packages/runtime/core/src/interface/index.ts @@ -3,8 +3,8 @@ import { SyncHook, AsyncSeriesBailHook } from '@garfish/hooks'; import { Loader, StyleManager, + ModuleManager, TemplateManager, - ComponentManager, JavaScriptManager, } from '@garfish/loader'; import { AppInterface } from '../module/app'; @@ -115,8 +115,8 @@ export namespace interfaces { } export interface StyleManagerInterface extends StyleManager {} + export interface ModuleManagerInterface extends ModuleManager {} export interface TemplateManagerInterface extends TemplateManager {} - export interface ComponentManagerInterface extends ComponentManager {} export interface JavaScriptManagerInterface extends JavaScriptManager {} export type Options = Config & HooksLifecycle; @@ -129,7 +129,7 @@ export namespace interfaces { export interface ResourceModules { js: Array; link: Array; - components: Array; + modules: Array; } export type BootStrapArgs = [Garfish, Options]; diff --git a/packages/runtime/core/src/module/app.ts b/packages/runtime/core/src/module/app.ts index 0ebc2c14f..b7e31b5c3 100644 --- a/packages/runtime/core/src/module/app.ts +++ b/packages/runtime/core/src/module/app.ts @@ -92,7 +92,7 @@ export class App { currentApp: this, loader: context.loader, externals: context.externals, - remoteComponentsCode: resources.components, + remoteModulesCode: resources.modules, }; this.cjsModules = { exports: {}, diff --git a/packages/runtime/core/src/plugins/preload.ts b/packages/runtime/core/src/plugins/preload.ts index f585041d0..8eef98c3a 100644 --- a/packages/runtime/core/src/plugins/preload.ts +++ b/packages/runtime/core/src/plugins/preload.ts @@ -1,7 +1,7 @@ import { warn, - transformUrl, isAbsolute, + transformUrl, callTestCallback, } from '@garfish/utils'; import { Loader, Manager, TemplateManager } from '@garfish/loader'; @@ -64,7 +64,7 @@ function safeLoad( loader: Loader, appName: string, url: string, - isComponent: boolean, + isModule: boolean, callback?: (m: Manager) => any, ) { requestQueue.add((next) => { @@ -84,8 +84,8 @@ function safeLoad( // edge requestIdleCallback(() => { try { - if (isComponent) { - loader.loadComponent(url).then(success, throwWarn); + if (isModule) { + loader.loadModule(url).then(success, throwWarn); } else { loader.load(appName, url).then(success, throwWarn); } @@ -126,7 +126,7 @@ export function loadAppResource(loader: Loader, info: interfaces.AppInfo) { } if (metaNodes) { metaNodes.forEach((node) => { - if (manager.DOMApis.isRemoteComponent(node)) { + if (manager.DOMApis.isRemoteModule(node)) { const src = manager.findAttributeValue(node, 'src'); if (isAbsolute(src)) { safeLoad(loader, info.name, src, true); diff --git a/packages/runtime/core/src/utils.ts b/packages/runtime/core/src/utils.ts index 3f8144b7d..366a12822 100644 --- a/packages/runtime/core/src/utils.ts +++ b/packages/runtime/core/src/utils.ts @@ -114,11 +114,11 @@ export const fetchStaticResources = ( entryManager .findAllMetaNodes() .map((node) => { - if (!entryManager.DOMApis.isRemoteComponent(node)) return; + if (!entryManager.DOMApis.isRemoteModule(node)) return; const async = entryManager.findAttributeValue(node, 'async'); if (!isAsync(async)) { const src = entryManager.findAttributeValue(node, 'src'); - return loader.loadComponent(src); + return loader.loadModule(src); } }) .filter(Boolean), diff --git a/packages/runtime/garfish/src/index.ts b/packages/runtime/garfish/src/index.ts index fa60f1062..c5c69a5ec 100644 --- a/packages/runtime/garfish/src/index.ts +++ b/packages/runtime/garfish/src/index.ts @@ -2,7 +2,7 @@ import { Garfish } from '@garfish/core'; import GarfishRouter from '@garfish/router'; import GarfishBrowserVm from '@garfish/browser-vm'; import GarfishBrowserSnapshot from '@garfish/browser-snapshot'; -import { remoteComponentPlugin } from '@garfish/remote-component'; +import { GarfishRemoteModulePlugin } from '@garfish/remote-module'; import { def, warn, @@ -56,7 +56,7 @@ export function createContext(): Garfish { GarfishRouter(), GarfishBrowserVm(), GarfishBrowserSnapshot(), - remoteComponentPlugin(), + GarfishRemoteModulePlugin(), ], }); diff --git a/packages/runtime/loader/src/appCache.ts b/packages/runtime/loader/src/appCache.ts index 63ed6704d..9aeee02b1 100644 --- a/packages/runtime/loader/src/appCache.ts +++ b/packages/runtime/loader/src/appCache.ts @@ -5,8 +5,8 @@ export const cachedDataSet = new WeakSet(); export enum FileTypes { js = 'js', css = 'css', + module = 'module', template = 'template', - component = 'component', } const MAX_SIZE = 10 * 1024 * 1024; @@ -14,8 +14,8 @@ const DEFAULT_POLL = Symbol('__defaultBufferPoll__'); const FILE_TYPES = [ FileTypes.js, FileTypes.css, + FileTypes.module, FileTypes.template, - FileTypes.component, DEFAULT_POLL, ]; diff --git a/packages/runtime/loader/src/index.ts b/packages/runtime/loader/src/index.ts index 18709df4c..7447807e3 100644 --- a/packages/runtime/loader/src/index.ts +++ b/packages/runtime/loader/src/index.ts @@ -3,20 +3,20 @@ import { PluginManager } from './pluginSystem'; import { request, copyResult, mergeConfig } from './utils'; import { FileTypes, cachedDataSet, AppCacheContainer } from './appCache'; import { StyleManager } from './managers/style'; +import { ModuleManager } from './managers/module'; import { TemplateManager } from './managers/template'; -import { ComponentManager } from './managers/component'; import { JavaScriptManager } from './managers/javascript'; // Export types and manager constructor export * from './managers/style'; +export * from './managers/module'; export * from './managers/template'; -export * from './managers/component'; export * from './managers/javascript'; export type Manager = | StyleManager + | ModuleManager | TemplateManager - | ComponentManager | JavaScriptManager; export interface LoaderOptions { @@ -83,15 +83,15 @@ export class Loader { } } - loadComponent(url: string) { - return this.load('components', url, true); + loadModule(url: string) { + return this.load('modules', url, true); } // Unable to know the final data type, so through "generics" load( scope: string, url: string, - isComponent = false, + isModule = false, ): Promise['value']> { const { options, loadingList, cacheStore } = this; @@ -133,9 +133,9 @@ export class Loader { .then(async ({ code, mimeType, result }) => { let managerCtor, fileType: FileTypes; - if (isComponent) { - fileType = FileTypes.component; - managerCtor = ComponentManager; + if (isModule) { + fileType = FileTypes.module; + managerCtor = ModuleManager; } else if (isHtml(mimeType) || /\.html/.test(result.url)) { fileType = FileTypes.template; managerCtor = TemplateManager; diff --git a/packages/runtime/loader/src/managers/component.ts b/packages/runtime/loader/src/managers/component.ts deleted file mode 100644 index 652bf0bda..000000000 --- a/packages/runtime/loader/src/managers/component.ts +++ /dev/null @@ -1,17 +0,0 @@ -export class ComponentManager { - public componentCode: string; - public url: string | null; - - constructor(componentCode: string, url?: string) { - this.url = url || null; - this.componentCode = componentCode; - } - - clone() { - // @ts-ignore - const cloned = new this.constructor(); - cloned.url = this.url; - cloned.componentCode = this.componentCode; - return cloned; - } -} diff --git a/packages/runtime/loader/src/managers/module.ts b/packages/runtime/loader/src/managers/module.ts new file mode 100644 index 000000000..5ae2105c1 --- /dev/null +++ b/packages/runtime/loader/src/managers/module.ts @@ -0,0 +1,17 @@ +export class ModuleManager { + public moduleCode: string; + public url: string | null; + + constructor(moduleCode: string, url?: string) { + this.url = url || null; + this.moduleCode = moduleCode; + } + + clone() { + // @ts-ignore + const cloned = new this.constructor(); + cloned.url = this.url; + cloned.moduleCode = this.moduleCode; + return cloned; + } +} diff --git a/packages/runtime/remote-component/README.md b/packages/runtime/remote-component/README.md deleted file mode 100644 index 4b1baa818..000000000 --- a/packages/runtime/remote-component/README.md +++ /dev/null @@ -1,123 +0,0 @@ -# `@garfish/remote-component` - -> TODO: description - -## Usage - -```jsx -// components -exports.One = function () { - return React.createElement('div'); -}; - -exports.Two = function () { - return React.createElement('span'); -}; -``` - -```js -import React from 'React'; -import { - preload, - toEsModule, - setExternal, - loadComponent, - loadComponentSync, - cacheComponents, -} from '@garfish/remote-component'; - -// Environment variables required by remoteComponents -setExternal({ React }); - -React.lazy(() => - loadComponent('https://xx.js').then((components) => { - console.log(components); // One, Two - return toEsModule(components.One); - }), -); - -// Or -loadComponent({ - cache: true, // This will cache the component instance - env: { React }, - url: 'https://xx.js', - error: (err) => { - console.error(err); - return 'render error content'; - }, -}).then((components) => { - console.log(components); // One, Two -}); - -// Or load the remote components synchronously -preload(['https://1.js', 'https://2.js']).then(() => { - const components = loadComponentSync('https://1.js'); - console.log(components); // One, Two -}); - -// View already cached components -console.log(cacheComponents); -``` - -## Combined with garfish - -If you are using "garfish" micro frontend. - -```jsx -// Child app -import { - preload, - setExternal, -} from '@garfish/remote-component'; - -export const provider = () => { - render({ dom }) { - // When the resources of the remote component are preloaded, - // You can use synchronous syntax to load remote components in the current application. - // You can combine "webpack5 module federation" or other "component markets" - preload(menu.remoteComponents).then(() => { - ReactDom.render(, dom) - }) - }, - - destroy() { - ... - } -} -``` - -You can also configure the information of remote components in the template, so that these components can be used synchronously when the child application is initialized. - -```html - - - - - - - - - - -``` - -```tsx -import { loadComponentSync } from '@garfish/remote-component'; - -function App() { - const { OneComponent } = loadComponentSync('https://xx.js'); - - return ( -
- -
- ); -} -``` diff --git a/packages/runtime/remote-component/src/apis/toEsModule.ts b/packages/runtime/remote-component/src/apis/toEsModule.ts deleted file mode 100644 index d6b5cbca2..000000000 --- a/packages/runtime/remote-component/src/apis/toEsModule.ts +++ /dev/null @@ -1,6 +0,0 @@ -export function toEsModule(component: T) { - return { - __esModule: true, - default: component, - }; -} diff --git a/packages/runtime/remote-component/src/index.ts b/packages/runtime/remote-component/src/index.ts deleted file mode 100644 index 74837e955..000000000 --- a/packages/runtime/remote-component/src/index.ts +++ /dev/null @@ -1,28 +0,0 @@ -import { preload } from './apis/preload'; -import { toEsModule } from './apis/toEsModule'; -import { setExternal } from './apis/setExternal'; -import { loadComponent } from './apis/loadComponent'; -import { loadComponentSync } from './apis/loadComponentSync'; -import { cacheComponents } from './common'; -import { remoteComponentPlugin } from './garfishPlugin'; - -// Micro component loader uses singleton mode -const loader = { - preload, - toEsModule, - setExternal, - loadComponent, - loadComponentSync, - cacheComponents, -}; - -export { - preload, - toEsModule, - setExternal, - loadComponent, - loadComponentSync, - remoteComponentPlugin, - cacheComponents, - loader as default, -}; diff --git a/packages/runtime/remote-component/.npmignore b/packages/runtime/remote-module/.npmignore similarity index 100% rename from packages/runtime/remote-component/.npmignore rename to packages/runtime/remote-module/.npmignore diff --git a/packages/runtime/remote-component/LICENSE b/packages/runtime/remote-module/LICENSE similarity index 100% rename from packages/runtime/remote-component/LICENSE rename to packages/runtime/remote-module/LICENSE diff --git a/packages/runtime/remote-module/README.md b/packages/runtime/remote-module/README.md new file mode 100644 index 000000000..fbf284770 --- /dev/null +++ b/packages/runtime/remote-module/README.md @@ -0,0 +1,121 @@ +# `@garfish/remote-module` + +## Usage + +```jsx +// Modules +exports.One = function () { + return React.createElement('div'); +}; + +exports.Two = function () { + return React.createElement('span'); +}; +``` + +```js +import React from 'React'; +import { + preload, + esModule, + setExternal, + loadModule, + loadModuleSync, + cacheModules, +} from '@garfish/remote-module'; + +// Environment variables required by remoteModules +setExternal({ React }); + +React.lazy(() => + loadModule('https://xx.js').then((modules) => { + console.log(modules); // One, Two + return esModule(modules.One); + }), +); + +// Or +loadModule({ + cache: true, // This will cache the module instance + env: { React }, + url: 'https://xx.js', + error: (err) => { + console.error(err); + return 'render error content'; + }, +}).then((modules) => { + console.log(modules); // One, Two +}); + +// Or load the remote modules synchronously +preload(['https://1.js', 'https://2.js']).then(() => { + const modules = loadModuleSync('https://1.js'); + console.log(modules); // One, Two +}); + +// View already cached modules +console.log(cacheModules); +``` + +## Combined with garfish + +If you are using "garfish" micro frontend. + +```jsx +// Child app +import { + preload, + setExternal, +} from '@garfish/remote-module'; + +export const provider = () => { + render({ dom }) { + // When the resources of the remote module are preloaded, + // You can use synchronous syntax to load remote modules in the current application. + // You can combine "webpack5 module federation" or other "module markets" + preload(menu.remoteModules).then(() => { + ReactDom.render(, dom) + }) + }, + + destroy() { + ... + } +} +``` + +You can also configure the information of remote modules in the template, so that these modules can be used synchronously when the child application is initialized. + +```html + + + + + + + + + + +``` + +```tsx +import { loadModuleSync } from '@garfish/remote-module'; + +function App() { + const { OneModule } = loadModuleSync('https://xx.js'); + + return ( +
+ +
+ ); +} +``` diff --git a/packages/runtime/remote-component/__tests__/index.spec.ts b/packages/runtime/remote-module/__tests__/index.spec.ts similarity index 100% rename from packages/runtime/remote-component/__tests__/index.spec.ts rename to packages/runtime/remote-module/__tests__/index.spec.ts diff --git a/packages/runtime/remote-component/api-extractor.json b/packages/runtime/remote-module/api-extractor.json similarity index 100% rename from packages/runtime/remote-component/api-extractor.json rename to packages/runtime/remote-module/api-extractor.json diff --git a/packages/runtime/remote-component/package.json b/packages/runtime/remote-module/package.json similarity index 79% rename from packages/runtime/remote-component/package.json rename to packages/runtime/remote-module/package.json index 13a31521f..c0c823b13 100644 --- a/packages/runtime/remote-component/package.json +++ b/packages/runtime/remote-module/package.json @@ -1,16 +1,16 @@ { - "name": "@garfish/remote-component", + "name": "@garfish/remote-module", "version": "0.0.30", - "description": "remote-component module.", + "description": "remote-module module.", "keywords": [ "garfish", - "remote-component" + "remote-module" ], "author": "chentao.arthur ", "homepage": "https://github.com/bytedance/garfish", "license": "Apache-2.0", "main": "index.js", - "module": "dist/remote-component.esm-bundler.js", + "module": "dist/remote-module.esm-bundler.js", "repository": { "type": "git", "url": "git+https://github.com/bytedance/garfish.git" @@ -19,7 +19,7 @@ "url": "https://github.com/bytedance/garfish/issues" }, "scripts": {}, - "types": "dist/remote-component.d.ts", + "types": "dist/remote-module.d.ts", "buildOptions": { "name": "MicroComponent", "devTemplate": "module", diff --git a/packages/runtime/remote-component/src/actuator.ts b/packages/runtime/remote-module/src/actuator.ts similarity index 62% rename from packages/runtime/remote-component/src/actuator.ts rename to packages/runtime/remote-module/src/actuator.ts index 58de55587..beaefb41b 100644 --- a/packages/runtime/remote-component/src/actuator.ts +++ b/packages/runtime/remote-module/src/actuator.ts @@ -1,12 +1,12 @@ import { evalWithEnv } from '@garfish/utils'; -import { ComponentManager } from '@garfish/loader'; +import { ModuleManager } from '@garfish/loader'; import { externals, getCurrentApp } from './common'; export class Actuator { - private manager: ComponentManager; + private manager: ModuleManager; private env: Record; - constructor(manager: ComponentManager, env?: Record) { + constructor(manager: ModuleManager, env?: Record) { this.manager = manager; this.env = { exports: {}, @@ -18,13 +18,13 @@ export class Actuator { execScript() { const app = getCurrentApp(); - const { url, componentCode } = this.manager; + const { url, moduleCode } = this.manager; if (app) { // Avoid conflict with Garfish cjs - app.execScript(componentCode, this.env, url, { noEntry: true }); + app.execScript(moduleCode, this.env, url, { noEntry: true }); } else { const sourceUrl = `\n${url ? `//# sourceURL=${url}\n` : ''}`; - evalWithEnv(`;${componentCode}\n${sourceUrl}`, this.env); + evalWithEnv(`;${moduleCode}\n${sourceUrl}`, this.env); } return this.env; } diff --git a/packages/runtime/remote-module/src/apis/esModule.ts b/packages/runtime/remote-module/src/apis/esModule.ts new file mode 100644 index 000000000..5f079a627 --- /dev/null +++ b/packages/runtime/remote-module/src/apis/esModule.ts @@ -0,0 +1,6 @@ +export function esModule(obj: T) { + return { + default: obj, + __esModule: true, + }; +} diff --git a/packages/runtime/remote-component/src/apis/loadComponent.ts b/packages/runtime/remote-module/src/apis/loadModule.ts similarity index 72% rename from packages/runtime/remote-component/src/apis/loadComponent.ts rename to packages/runtime/remote-module/src/apis/loadModule.ts index 051354c67..efea173e2 100644 --- a/packages/runtime/remote-component/src/apis/loadComponent.ts +++ b/packages/runtime/remote-module/src/apis/loadModule.ts @@ -2,22 +2,22 @@ import { assert, isPromise, isAbsolute } from '@garfish/utils'; import { Actuator } from '../actuator'; import { loader, + ModuleInfo, + cacheModules, fetchLoading, purifyOptions, - ComponentInfo, - cacheComponents, } from '../common'; -export function loadComponent( - options: ComponentInfo | string, +export function loadModule( + options: ModuleInfo | string, ): Promise | null> { const info = purifyOptions(options); const { url, env, cache, version, error, adapter } = info; - assert(url, 'Missing url for loading remote components'); + assert(url, 'Missing url for loading remote module'); assert( isAbsolute(url), - `The loading of the remote component must be an absolute path. "${url}"`, + `The loading of the remote module must be an absolute path. "${url}"`, ); // `1.0@https://xx.js` @@ -27,11 +27,11 @@ export function loadComponent( const asyncLoadProcess = async () => { let result = null; try { - const component = cacheComponents[urlWithVersion]; - if (cache && component) { - result = component; + const _module = cacheModules[urlWithVersion]; + if (cache && _module) { + result = _module; } else { - const data = await loader.loadComponent(url); + const data = await loader.loadModule(url); const actuator = new Actuator(data.resourceManager, env); let exports = actuator.execScript().exports; @@ -42,7 +42,7 @@ export function loadComponent( exports = adapter(exports); } result = exports; - cacheComponents[urlWithVersion] = result; + cacheModules[urlWithVersion] = result; } } catch (err) { if (typeof error === 'function') { diff --git a/packages/runtime/remote-component/src/apis/loadComponentSync.ts b/packages/runtime/remote-module/src/apis/loadModuleSync.ts similarity index 64% rename from packages/runtime/remote-component/src/apis/loadComponentSync.ts rename to packages/runtime/remote-module/src/apis/loadModuleSync.ts index 0660f4569..185282df2 100644 --- a/packages/runtime/remote-component/src/apis/loadComponentSync.ts +++ b/packages/runtime/remote-module/src/apis/loadModuleSync.ts @@ -4,45 +4,45 @@ import { isAbsolute, error as GarfishError, } from '@garfish/utils'; -import { Actuator } from '../actuator'; import { + ModuleInfo, + cacheModules, purifyOptions, - ComponentInfo, - cacheComponents, - getComponentCode, + getModuleCode, } from '../common'; +import { Actuator } from '../actuator'; -// If we want to have perfect synchronization syntax to load remote components, +// If we want to have perfect synchronization syntax to load remote modules, // the source code of the child application must be analyzed so that it can be loaded on demand. // In the future, we need to wait until garfish supports esModule, -// To consider loading remote components on demand when using synchronous syntax. +// To consider loading remote modules on demand when using synchronous syntax. // E.g. // 1. esModule - Static analysis, recursively build dependency tree. // 2. webpack - Analyze the source code ast and build into different package versions. -export function loadComponentSync( - options: ComponentInfo | string, +export function loadModuleSync( + options: ModuleInfo | string, ): Record { const info = purifyOptions(options); const { url, env, cache, version, error, adapter } = info; - assert(url, 'Missing url for loading remote components'); + assert(url, 'Missing url for loading remote module'); assert( isAbsolute(url), - `The loading of the remote component must be an absolute path. "${url}"`, + `The loading of the remote module must be an absolute path. "${url}"`, ); let result = null; const urlWithVersion = `${version || 'latest'}@${url}`; - const component = cacheComponents[urlWithVersion]; + const _module = cacheModules[urlWithVersion]; - if (cache && component) { - result = component; + if (cache && _module) { + result = _module; } else { - const manager = getComponentCode(url); + const manager = getModuleCode(url); assert( manager, - `Synchronously load components must load resources in advance. "${url}"`, + `Synchronously load module must load resources in advance. "${url}"`, ); try { @@ -54,10 +54,10 @@ export function loadComponentSync( result = exports; if (isPromise(result)) { GarfishError( - `The current component return a promise, you should switch to asynchronous loading. "${url}"`, + `The current module return a promise, you should switch to asynchronous loading. "${url}"`, ); } - cacheComponents[urlWithVersion] = result; + cacheModules[urlWithVersion] = result; } catch (err) { if (typeof error === 'function') { result = error(err); diff --git a/packages/runtime/remote-component/src/apis/preload.ts b/packages/runtime/remote-module/src/apis/preload.ts similarity index 61% rename from packages/runtime/remote-component/src/apis/preload.ts rename to packages/runtime/remote-module/src/apis/preload.ts index 1030741a0..121efdba7 100644 --- a/packages/runtime/remote-component/src/apis/preload.ts +++ b/packages/runtime/remote-module/src/apis/preload.ts @@ -1,7 +1,7 @@ import { assert, isAbsolute } from '@garfish/utils'; import { loader, storedResources } from '../common'; -// Preload the static resources of the component, so that the component can be loaded synchronously +// Preload the static resources of the module, so that the module can be loaded synchronously export function preload(urls: string | Array) { if (!Array.isArray(urls)) urls = [urls]; @@ -9,9 +9,9 @@ export function preload(urls: string | Array) { urls.map((url) => { assert( isAbsolute(url || ''), - `The loading of the remote component must be an absolute path. "${url}"`, + `The loading of the remote module must be an absolute path. "${url}"`, ); - return loader.loadComponent(url).then((data) => { + return loader.loadModule(url).then((data) => { storedResources.push(data.resourceManager); }); }), diff --git a/packages/runtime/remote-component/src/apis/setExternal.ts b/packages/runtime/remote-module/src/apis/setExternal.ts similarity index 81% rename from packages/runtime/remote-component/src/apis/setExternal.ts rename to packages/runtime/remote-module/src/apis/setExternal.ts index 6916c3167..ef6374b94 100644 --- a/packages/runtime/remote-component/src/apis/setExternal.ts +++ b/packages/runtime/remote-module/src/apis/setExternal.ts @@ -10,9 +10,7 @@ export function setExternal( for (const key in nameOrExtObj) { if (externals[key]) { __DEV__ && - warn( - `The "${key}" will be overwritten in remote components external.`, - ); + warn(`The "${key}" will be overwritten in remote module external.`); } externals[key] = nameOrExtObj[key]; } diff --git a/packages/runtime/remote-component/src/common.ts b/packages/runtime/remote-module/src/common.ts similarity index 70% rename from packages/runtime/remote-component/src/common.ts rename to packages/runtime/remote-module/src/common.ts index 59428ef00..6f8fec03b 100644 --- a/packages/runtime/remote-component/src/common.ts +++ b/packages/runtime/remote-module/src/common.ts @@ -1,7 +1,7 @@ import { deepMerge } from '@garfish/utils'; -import { Loader, ComponentManager } from '@garfish/loader'; +import { Loader, ModuleManager } from '@garfish/loader'; -export interface ComponentInfo { +export interface ModuleInfo { url: string; cache?: boolean; version?: string; @@ -18,8 +18,8 @@ try { } catch {} export const fetchLoading = Object.create(null); -export const cacheComponents = Object.create(null); -export const storedResources: Array = []; +export const cacheModules = Object.create(null); +export const storedResources: Array = []; export const externals: Record = garfishGlobalEnv ? { ...garfishGlobalEnv.externals } : {}; @@ -35,22 +35,22 @@ export const loader: Loader = (() => { return new Loader(); })(); -export const purifyOptions = (options: ComponentInfo | string) => { +export const purifyOptions = (options: ModuleInfo | string) => { if (typeof options === 'string') options = { url: options }; // Default use cache - return deepMerge({ cache: true }, options || {}) as ComponentInfo; + return deepMerge({ cache: true }, options || {}) as ModuleInfo; }; export const getCurrentApp = () => { return garfishGlobalEnv && garfishGlobalEnv.currentApp; }; -export const getComponentCode = (url: string) => { +export const getModuleCode = (url: string) => { if (garfishGlobalEnv) { - const { remoteComponentsCode } = garfishGlobalEnv; - if (Array.isArray(remoteComponentsCode)) { + const { remoteModulesCode } = garfishGlobalEnv; + if (Array.isArray(remoteModulesCode)) { return storedResources - .concat(remoteComponentsCode) + .concat(remoteModulesCode) .find((manager) => manager.url === url); } } diff --git a/packages/runtime/remote-component/src/garfishPlugin.ts b/packages/runtime/remote-module/src/garfishPlugin.ts similarity index 51% rename from packages/runtime/remote-component/src/garfishPlugin.ts rename to packages/runtime/remote-module/src/garfishPlugin.ts index 1e8c72b80..36245d1b1 100644 --- a/packages/runtime/remote-component/src/garfishPlugin.ts +++ b/packages/runtime/remote-module/src/garfishPlugin.ts @@ -1,36 +1,36 @@ import { warn } from '@garfish/utils'; import { interfaces } from '@garfish/core'; -import { cacheComponents } from './common'; +import { cacheModules } from './common'; import { preload } from './apis/preload'; +import { loadModule } from './apis/loadModule'; import { setExternal } from './apis/setExternal'; -import { loadComponent } from './apis/loadComponent'; -import { loadComponentSync } from './apis/loadComponentSync'; +import { loadModuleSync } from './apis/loadModuleSync'; declare module '@garfish/core' { export interface Garfish { preload: typeof preload; - loadComponent: typeof loadComponent; - loadComponentSync: typeof loadComponentSync; - cacheComponents: typeof cacheComponents; + loadModule: typeof loadModule; + loadModuleSync: typeof loadModuleSync; + cacheModules: typeof cacheModules; } export namespace interfaces { export interface Garfish { preload: typeof preload; - loadComponent: typeof loadComponent; - loadComponentSync: typeof loadComponentSync; - cacheComponents: typeof cacheComponents; + loadModule: typeof loadModule; + loadModuleSync: typeof loadModuleSync; + cacheModules: typeof cacheModules; } } } -export function remoteComponentPlugin() { +export function GarfishRemoteModulePlugin() { return (Garfish: interfaces.Garfish): interfaces.Plugin => { const warning = () => { __DEV__ && warn( 'If there is no need for performance optimization, ' + - 'you should not use the global component loading method.', + 'you should not use the `Garfish.loadModule()`.', ); }; @@ -39,20 +39,20 @@ export function remoteComponentPlugin() { return preload(urls); }; - Garfish.loadComponent = function (options) { + Garfish.loadModule = function (options) { warning(); - return loadComponent(options); + return loadModule(options); }; - Garfish.loadComponentSync = function (options) { + Garfish.loadModuleSync = function (options) { warning(); - return loadComponentSync(options); + return loadModuleSync(options); }; - Garfish.cacheComponents = cacheComponents; + Garfish.cacheModules = cacheModules; return { - name: 'micro-component', + name: 'remote-module', version: __VERSION__, bootstrap() { diff --git a/packages/runtime/remote-module/src/index.ts b/packages/runtime/remote-module/src/index.ts new file mode 100644 index 000000000..df005b0da --- /dev/null +++ b/packages/runtime/remote-module/src/index.ts @@ -0,0 +1,28 @@ +import { cacheModules } from './common'; +import { GarfishRemoteModulePlugin } from './garfishPlugin'; +import { preload } from './apis/preload'; +import { esModule } from './apis/esModule'; +import { loadModule } from './apis/loadModule'; +import { setExternal } from './apis/setExternal'; +import { loadModuleSync } from './apis/loadModuleSync'; + +// Remote module loader uses singleton mode +const loader = { + preload, + esModule, + setExternal, + loadModule, + loadModuleSync, + cacheModules, +}; + +export { + preload, + esModule, + setExternal, + loadModule, + loadModuleSync, + GarfishRemoteModulePlugin, + cacheModules, + loader as default, +}; diff --git a/packages/runtime/utils/src/domApis.ts b/packages/runtime/utils/src/domApis.ts index 34ca530a6..9419a7984 100644 --- a/packages/runtime/utils/src/domApis.ts +++ b/packages/runtime/utils/src/domApis.ts @@ -91,13 +91,13 @@ export const DOMApis = { return Boolean(hasRelAttr && hasAsAttr); }, - isRemoteComponent(node: Node) { + isRemoteModule(node: Node) { if (!this.isNode(node) || node.tagName !== 'meta') return false; let hasNameAttr, hasSrcAttr; for (const { key, value } of node.attributes) { if (key === 'name') { hasNameAttr = true; - if (value !== 'garfish-remote-component') { + if (value !== 'garfish-remote-module') { return false; } } else if (key === 'src') {