From 0559677086e5e8b035bcdc864a4685ae38f37123 Mon Sep 17 00:00:00 2001 From: maoxiaoke Date: Mon, 25 Apr 2022 14:36:03 +0800 Subject: [PATCH 1/6] =?UTF-8?q?chore:=20=F0=9F=A4=96=20version?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- package.json | 2 +- packages/icestark/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index f22cbb24..df583dfc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "icestark-monorepo", - "version": "2.7.3", + "version": "2.8.0", "private": true, "description": "Icestark is a JavaScript library for multiple projects, Ice workbench solution.", "scripts": { diff --git a/packages/icestark/package.json b/packages/icestark/package.json index 9c4a6e2f..f358f1af 100644 --- a/packages/icestark/package.json +++ b/packages/icestark/package.json @@ -1,6 +1,6 @@ { "name": "@ice/stark", - "version": "2.7.3", + "version": "2.8.0", "description": "Icestark is a JavaScript library for multiple projects, Ice workbench solution.", "scripts": { "build": "rm -rf lib && tsc", From a085929ea2066940081ce6a92fa93204cfd47b70 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=A3=E5=90=92?= Date: Thu, 28 Apr 2022 15:04:22 +0800 Subject: [PATCH 2/6] Revert "Feat/sandbox inject custom proxy (#577)" (#580) * Revert "Revert "Feat/sandbox inject custom proxy (#577)"" --- packages/sandbox/CHANGELOG.md | 4 ++++ packages/sandbox/__tests__/index.spec.ts | 28 ++++++++++++++++++++++++ packages/sandbox/package.json | 2 +- packages/sandbox/src/index.ts | 17 ++++++++++++-- 4 files changed, 48 insertions(+), 3 deletions(-) diff --git a/packages/sandbox/CHANGELOG.md b/packages/sandbox/CHANGELOG.md index 0526bbe6..6fc17359 100644 --- a/packages/sandbox/CHANGELOG.md +++ b/packages/sandbox/CHANGELOG.md @@ -1,5 +1,9 @@ # Changelog +## 1.1.5 + +- [fix] exposes `injection` through constructor. + ## 1.1.4 - [fix] simply copy callable funtions's extra properties. diff --git a/packages/sandbox/__tests__/index.spec.ts b/packages/sandbox/__tests__/index.spec.ts index fea1ee99..06d6c6a0 100644 --- a/packages/sandbox/__tests__/index.spec.ts +++ b/packages/sandbox/__tests__/index.spec.ts @@ -151,3 +151,31 @@ describe('callable functions in sandbox', () => { expect(error).toBe(null); }); }); + +describe('inject value to sandbox', () => { + const testObject = { a: 1 }; + const testProxy = new Proxy(testObject, { + get(target, p, receiver) { + if(p === 'a') { + return 2; + } + return Reflect.get(target, p); + } + }) + // in order to pass value outof sandbox to validate, set multiMode false + const sandbox = new Sandbox({multiMode: false, injection: {testObject: testProxy}}); + test('inject proxy object in sandbox', () => { + // @ts-ignore + window.testObject = testObject; + // @ts-ignore + window.result = undefined; + sandbox.execScriptInSandbox( + ` + window.result = window.testObject.a; + `, + ); + + // @ts-ignore + expect(window.result).toBe(2); + }) +}) diff --git a/packages/sandbox/package.json b/packages/sandbox/package.json index 9433e009..2fcf8084 100644 --- a/packages/sandbox/package.json +++ b/packages/sandbox/package.json @@ -1,6 +1,6 @@ { "name": "@ice/sandbox", - "version": "1.1.4", + "version": "1.1.5", "description": "sandbox for execute scripts", "main": "lib/index.js", "scripts": { diff --git a/packages/sandbox/src/index.ts b/packages/sandbox/src/index.ts index b91cf98e..34a5fe88 100644 --- a/packages/sandbox/src/index.ts +++ b/packages/sandbox/src/index.ts @@ -1,5 +1,6 @@ export interface SandboxProps { multiMode?: boolean; + injection?: Record; } export interface SandboxConstructor { @@ -33,6 +34,8 @@ export default class Sandbox { private multiMode = false; + private injection = {}; + private eventListeners = {}; private timeoutIds: number[] = []; @@ -46,7 +49,7 @@ export default class Sandbox { public sandboxDisabled: boolean; constructor(props: SandboxProps = {}) { - const { multiMode } = props; + const { multiMode, injection } = props; if (!window.Proxy) { console.warn('proxy sandbox is not support by current browser'); this.sandboxDisabled = true; @@ -54,8 +57,13 @@ export default class Sandbox { // enable multiMode in case of create mulit sandbox in same time this.multiMode = multiMode; this.sandbox = null; + this.injection = injection; } + /** + * create proxy sandbox + * @param injection @deprecated will be deprecated in the future + */ createProxySandbox(injection?: object) { const { propertyAdded, originalValues, multiMode } = this; const proxyWindow = Object.create(null) as Window; @@ -65,6 +73,9 @@ export default class Sandbox { const originalSetInterval = window.setInterval; const originalSetTimeout = window.setTimeout; + // `this` in Proxy traps will retarget to the trap. + const _self = this; + // hijack addEventListener proxyWindow.addEventListener = (eventName, fn, ...rest) => { this.eventListeners[eventName] = (this.eventListeners[eventName] || []); @@ -135,7 +146,8 @@ export default class Sandbox { } // search from injection - const injectionValue = injection && injection[p]; + const injectionValue = _self.injection?.[p] ?? injection?.[p]; + if (injectionValue) { return injectionValue; } @@ -159,6 +171,7 @@ export default class Sandbox { // Axios, Moment, and other callable functions may have additional properties. // Simply copy them into boundValue. + // eslint-disable-next-line guard-for-in for (const key in value) { boundValue[key] = value[key]; } From 999f5425b4d5d863d675a1bccab9a4d12f058f6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=A3=E5=90=92?= Date: Thu, 28 Apr 2022 15:04:48 +0800 Subject: [PATCH 3/6] =?UTF-8?q?feat:=20=F0=9F=8E=B8=20cache=20logic=20(#44?= =?UTF-8?q?3)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: 🎸 cache logic --- .../icestark/__tests__/AppRouter.spec.tsx | 33 +++++++++ .../icestark/__tests__/appLifeCycle.spec.tsx | 44 ----------- .../icestark/__tests__/handleAssets.spec.tsx | 20 +++-- packages/icestark/src/AppRoute.tsx | 12 ++- packages/icestark/src/apps.ts | 34 +++++++-- packages/icestark/src/util/appLifeCycle.ts | 52 ------------- .../icestark/src/util/capturedListeners.ts | 1 + packages/icestark/src/util/constant.ts | 5 ++ packages/icestark/src/util/error.ts | 1 + packages/icestark/src/util/getLifecycle.ts | 2 +- packages/icestark/src/util/handleAssets.ts | 73 ++++++++++++------- 11 files changed, 135 insertions(+), 142 deletions(-) delete mode 100644 packages/icestark/__tests__/appLifeCycle.spec.tsx delete mode 100644 packages/icestark/src/util/appLifeCycle.ts diff --git a/packages/icestark/__tests__/AppRouter.spec.tsx b/packages/icestark/__tests__/AppRouter.spec.tsx index 43b731ce..69d52c07 100644 --- a/packages/icestark/__tests__/AppRouter.spec.tsx +++ b/packages/icestark/__tests__/AppRouter.spec.tsx @@ -6,6 +6,7 @@ import { getCache, setCache } from '../src/util/cache'; import * as React from 'react'; import { render } from '@testing-library/react'; import { AppRouter, AppRoute } from '../src/index'; +import { getMicroApps } from '../src/apps'; const delay = (milliscond: number) => new Promise(resolve => setTimeout(resolve, milliscond)); @@ -145,4 +146,36 @@ describe('AppRouter', () => { unmount(); }) + + test('app-cached', async () => { + (fetch as FetchMock).mockResponseOnce(umdSourceWithSetLibrary.toString()); + const { container, unmount } = render( + + + + ); + window.history.pushState({}, 'test', '/seller'); + + await delay(1000); + expect(container.innerHTML).toContain('商家平台') + + window.history.pushState({}, 'test', '/waiter'); + await delay(1000); + + const app = getMicroApps().find(app => app.name === 'seller'); + expect(app.status).toEqual('UNMOUNTED'); + expect(!!app.mount).toBeTruthy(); + expect(!!app.unmount).toBeTruthy(); + + unmount(); + }) }) \ No newline at end of file diff --git a/packages/icestark/__tests__/appLifeCycle.spec.tsx b/packages/icestark/__tests__/appLifeCycle.spec.tsx deleted file mode 100644 index c8c5233d..00000000 --- a/packages/icestark/__tests__/appLifeCycle.spec.tsx +++ /dev/null @@ -1,44 +0,0 @@ -import '@testing-library/jest-dom/extend-expect'; - -import { AppLifeCycleEnum, cacheApp, callAppEnter, callAppLeave, isCached, deleteCache } from '../src/util/appLifeCycle'; -import { setCache } from '../src/util/cache'; - -describe('appLifeCycle', () => { - test('callAppEnter', () => { - const appEnterMockFn = jest.fn(); - - setCache(AppLifeCycleEnum.AppEnter, appEnterMockFn); - - callAppEnter(); - expect(appEnterMockFn).toBeCalledTimes(1); - - setCache(AppLifeCycleEnum.AppEnter, null); - callAppEnter(); - expect(appEnterMockFn).toBeCalledTimes(1); - }); - - test('callAppLeave', () => { - const appLeaveMockFn = jest.fn(); - - setCache(AppLifeCycleEnum.AppLeave, appLeaveMockFn); - - callAppLeave(); - expect(appLeaveMockFn).toBeCalledTimes(1); - - setCache(AppLifeCycleEnum.AppLeave, null); - callAppLeave(); - expect(appLeaveMockFn).toBeCalledTimes(1); - }); - - test('cache app', () => { - const appEnterMockFn = jest.fn(); - const appLeaveMockFn = jest.fn(); - const appKey = 'appKey'; - setCache(AppLifeCycleEnum.AppEnter, appEnterMockFn); - setCache(AppLifeCycleEnum.AppLeave, appLeaveMockFn); - cacheApp(appKey); - expect(isCached(appKey)).toBe(true); - deleteCache(appKey); - expect(isCached(appKey)).toBe(false); - }) -}); diff --git a/packages/icestark/__tests__/handleAssets.spec.tsx b/packages/icestark/__tests__/handleAssets.spec.tsx index b236a31b..7860226f 100644 --- a/packages/icestark/__tests__/handleAssets.spec.tsx +++ b/packages/icestark/__tests__/handleAssets.spec.tsx @@ -649,12 +649,13 @@ describe('appendCSS', () => { const div = document.createElement('div'); appendCSS( - div, { type: AssetTypeEnum.EXTERNAL, content: '/test.css' - }, - 'icestark-css-0' + },{ + root: div, + id: 'icestark-css-0' + } ) .then(() => { expect(div.innerHTML).toContain('id="icestark-css-0"'); @@ -671,10 +672,13 @@ describe('appendCSS', () => { test('appendCSS -> style', () => { const div = document.createElement('div'); const style = '.test { color: #fff;}'; - appendCSS(div, { + appendCSS({ type: AssetTypeEnum.INLINE, content: style, - }, 'icestark-css-0') + }, { + root: div, + id: 'icestark-css-0' + }) .then(() => { expect(div.innerHTML).toContain('id="icestark-css-0"'); expect(div.innerHTML).toContain(style); @@ -694,12 +698,14 @@ describe('appendCSS', () => { const div = document.createElement('div'); appendCSS( - div, { type: AssetTypeEnum.EXTERNAL, content: '/test.css' }, - 'icestark-css-0' + { + root: div, + id: 'icestark-css-0' + } ) .then(() => { expect(div.innerHTML).toContain('id="icestark-css-0"'); diff --git a/packages/icestark/src/AppRoute.tsx b/packages/icestark/src/AppRoute.tsx index 738123a0..e327713d 100644 --- a/packages/icestark/src/AppRoute.tsx +++ b/packages/icestark/src/AppRoute.tsx @@ -1,9 +1,12 @@ import * as React from 'react'; import renderComponent from './util/renderComponent'; import { AppHistory } from './appHistory'; -import { unloadMicroApp, BaseConfig, createMicroApp } from './apps'; +import { unloadMicroApp, unmountMicroApp, BaseConfig, createMicroApp } from './apps'; import { converArray2String } from './util/helpers'; -import { callCapturedEventListeners, resetCapturedEventListeners } from './util/capturedListeners'; +import { + callCapturedEventListeners, + resetCapturedEventListeners, +} from './util/capturedListeners'; import isEqual from 'lodash.isequal'; import type { PathData } from './util/checkActive'; @@ -135,6 +138,7 @@ export default class AppRoute extends React.Component { resetCapturedEventListeners(); + const { onAppEnter } = this.props; // Trigger app enter @@ -150,7 +154,7 @@ export default class AppRoute extends React.Component { - const { name, onAppLeave } = this.props; + const { name, onAppLeave, cached } = this.props; // Trigger app leave if (typeof onAppLeave === 'function') { @@ -158,7 +162,7 @@ export default class AppRoute extends React.Component { - const lifeCycleCacheKey = `cache_${cacheKey}_${lifeCycle}`; - if (getCache(lifeCycle)) { - setCache(lifeCycleCacheKey, getCache(lifeCycle)); - } else if (getCache(lifeCycleCacheKey)) { - // set cache to current lifeCycle - setCache(lifeCycle, getCache(lifeCycleCacheKey)); - } - }); -} - -export function deleteCache(cacheKey: string) { - [AppLifeCycleEnum.AppEnter, AppLifeCycleEnum.AppLeave].forEach((lifeCycle) => { - setCache(`cache_${cacheKey}_${lifeCycle}`, null); - }); -} - -export function isCached(cacheKey: string) { - return !!getCache(`cache_${cacheKey}_${AppLifeCycleEnum.AppEnter}`); -} - -export function callAppEnter() { - const appEnterKey = AppLifeCycleEnum.AppEnter; - const registerAppEnterCallback = getCache(appEnterKey); - - if (registerAppEnterCallback) { - registerAppEnterCallback(); - setCache(appEnterKey, null); - } -} - -export function callAppLeave() { - // resetCapturedEventListeners when app change, remove react-router/vue-router listeners - resetCapturedEventListeners(); - - const appLeaveKey = AppLifeCycleEnum.AppLeave; - const registerAppLeaveCallback = getCache(appLeaveKey); - - if (registerAppLeaveCallback) { - registerAppLeaveCallback(); - setCache(appLeaveKey, null); - } -} diff --git a/packages/icestark/src/util/capturedListeners.ts b/packages/icestark/src/util/capturedListeners.ts index 47aab6e6..c212b0ce 100644 --- a/packages/icestark/src/util/capturedListeners.ts +++ b/packages/icestark/src/util/capturedListeners.ts @@ -84,3 +84,4 @@ export function resetCapturedEventListeners() { capturedEventListeners[CapturedEventNameEnum.POPSTATE] = []; capturedEventListeners[CapturedEventNameEnum.HASHCHANGE] = []; } + diff --git a/packages/icestark/src/util/constant.ts b/packages/icestark/src/util/constant.ts index 27613d0e..13ee6e0f 100644 --- a/packages/icestark/src/util/constant.ts +++ b/packages/icestark/src/util/constant.ts @@ -23,3 +23,8 @@ export const NOT_MOUNTED = 'NOT_MOUNTED'; export const MOUNTED = 'MOUNTED'; export const UNMOUNTED = 'UNMOUNTED'; + +export enum AppLifeCycleEnum { + AppEnter = 'appEnter', + AppLeave = 'appLeave', +} diff --git a/packages/icestark/src/util/error.ts b/packages/icestark/src/util/error.ts index c8b19c9a..6526d8d9 100644 --- a/packages/icestark/src/util/error.ts +++ b/packages/icestark/src/util/error.ts @@ -6,6 +6,7 @@ export enum ErrorCode { 'JS_LOAD_ERROR' = 5, 'CSS_LOAD_ERROR' = 6, 'ACTIVE_PATH_ITEM_CAN_NOT_BE_EMPTY' = 7, + 'CACHED_APP_USE_UNLOAD' = 8, } export function normalizeMsg(msg: string, args: string[]) { diff --git a/packages/icestark/src/util/getLifecycle.ts b/packages/icestark/src/util/getLifecycle.ts index fe578212..bc2b9850 100644 --- a/packages/icestark/src/util/getLifecycle.ts +++ b/packages/icestark/src/util/getLifecycle.ts @@ -1,5 +1,5 @@ import { getCache, setCache } from './cache'; -import { AppLifeCycleEnum } from './appLifeCycle'; +import { AppLifeCycleEnum } from './constant'; import type { ModuleLifeCycle } from '../apps'; export function getLifecyleByLibrary() { diff --git a/packages/icestark/src/util/handleAssets.ts b/packages/icestark/src/util/handleAssets.ts index 41c9ec59..cc31e92c 100644 --- a/packages/icestark/src/util/handleAssets.ts +++ b/packages/icestark/src/util/handleAssets.ts @@ -75,11 +75,16 @@ function isAssetExist(element: HTMLScriptElement | HTMLLinkElement, type: 'scrip /** * Create link/style element and append to root */ -export function appendCSS( - root: HTMLElement | ShadowRoot, - asset: Asset | HTMLElement, - id: string, -): Promise { +export function appendCSS(asset: Asset | HTMLElement, + { + root, + id, + cacheId, + }: { + root?: HTMLElement | ShadowRoot; + id?: string; + cacheId?: string; + }): Promise { return new Promise(async (resolve, reject) => { if (!root) reject(new Error('no root element for css asset')); @@ -95,6 +100,7 @@ export function appendCSS( const styleElement: HTMLStyleElement = document.createElement('style'); styleElement.id = id; styleElement.setAttribute(PREFIX, DYNAMIC); + cacheId && styleElement.setAttribute('data-cache', cacheId); styleElement.innerHTML = content; root.appendChild(styleElement); resolve(); @@ -112,6 +118,7 @@ export function appendCSS( styleElement.innerHTML = await cachedStyleContent[content]; styleElement.id = id; styleElement.setAttribute(PREFIX, DYNAMIC); + cacheId && styleElement.setAttribute('data-cache', cacheId); root.appendChild(styleElement); useExternalLink = false; resolve(); @@ -126,6 +133,7 @@ export function appendCSS( element.id = id; element.rel = 'stylesheet'; element.href = content; + cacheId && element.setAttribute('data-cache', cacheId); element.addEventListener( 'error', @@ -156,19 +164,21 @@ function setAttributeForScriptNode(element: HTMLScriptElement, { id, src, scriptAttributes, + cacheId, }: { module: boolean; id: string; src: string; scriptAttributes: ScriptAttributes; + cacheId?: string; }) { /* * stamped by icestark for recycle when needed. */ element.setAttribute(PREFIX, DYNAMIC); + cacheId && element.setAttribute('data-cache', cacheId); element.id = id; - element.type = module ? 'module' : 'text/javascript'; element.src = src; @@ -225,10 +235,12 @@ export function appendExternalScript(asset: string | Asset, id, root = document.getElementsByTagName('head')[0], scriptAttributes = [], + cacheId, }: { id: string; root?: HTMLElement | ShadowRoot; scriptAttributes?: ScriptAttributes; + cacheId?: string; }): Promise { return new Promise((resolve, reject) => { const { type, content, module } = (asset as Asset); @@ -239,6 +251,7 @@ export function appendExternalScript(asset: string | Asset, element.innerHTML = content; element.id = id; element.setAttribute(PREFIX, DYNAMIC); + cacheId && element.setAttribute('data-cache', cacheId); module && (element.type = 'module'); root.appendChild(element); @@ -254,6 +267,7 @@ export function appendExternalScript(asset: string | Asset, id, src: content || (asset as string), scriptAttributes, + cacheId, }); if (isAssetExist(element, 'script')) { @@ -653,21 +667,8 @@ export function emptyAssets( export function checkCacheKey(node: HTMLElement | HTMLLinkElement | HTMLStyleElement | HTMLScriptElement, cacheKey: string|boolean) { return (typeof cacheKey === 'boolean' && cacheKey) - || !node.getAttribute('cache') - || node.getAttribute('cache') === cacheKey; -} - -/** - * cache all assets loaded by current sub-application - */ -export function cacheAssets(cacheKey: string): void { - const assetsList = getAssetsNode(); - assetsList.forEach((assetsNode) => { - // set cache key if asset attributes without prefix=static and cache - if (assetsNode.getAttribute(PREFIX) !== STATIC && !assetsNode.getAttribute('cache')) { - assetsNode.setAttribute('cache', cacheKey); - } - }); + || !node.getAttribute('data-cache') + || node.getAttribute('data-cache') === cacheKey; } /** @@ -679,9 +680,11 @@ export function cacheAssets(cacheKey: string): void { export async function loadAndAppendCssAssets(cssList: Array, { cacheCss = false, fetch = defaultFetch, + cacheId, }: { cacheCss?: boolean; fetch?: Fetch; + cacheId?: string; }) { const cssRoot: HTMLElement = document.getElementsByTagName('head')[0]; @@ -704,18 +707,28 @@ export async function loadAndAppendCssAssets(cssList: Array // And supposed to be remove from 3.x if (!useLinks) { return await Promise.all([ - ...cssContents.map((content, index) => appendCSS( - cssRoot, - { content, type: AssetTypeEnum.INLINE }, `${PREFIX}-css-${index}`, - )), - ...cssList.filter((css) => isElement(css)).map((asset, index) => appendCSS(cssRoot, asset, `${PREFIX}-css-${index}`)), + ...cssContents.map((content, index) => appendCSS({ content, type: AssetTypeEnum.INLINE }, + { + root: cssRoot, + id: `${PREFIX}-css-${index}`, + cacheId, + })), + ...cssList.filter((css) => isElement(css)).map((asset, index) => appendCSS(asset, { + root: cssRoot, + id: `${PREFIX}-css-${index}`, + cacheId, + })), ]); } } // load css content - return await Promise.all( - cssList.map((asset, index) => appendCSS(cssRoot, asset, `${PREFIX}-css-${index}`)), + await Promise.all( + cssList.map((asset, index) => appendCSS(asset, { + root: cssRoot, + id: `${PREFIX}-css-${index}`, + cacheId, + })), ); } @@ -731,8 +744,10 @@ export function loadAndAppendJsAssets( assets: Assets, { scriptAttributes = [], + cacheId, }: { scriptAttributes?: ScriptAttributes; + cacheId?: string; }, ) { const jsRoot: HTMLElement = document.getElementsByTagName('head')[0]; @@ -748,6 +763,7 @@ export function loadAndAppendJsAssets( root: jsRoot, scriptAttributes, id: `${PREFIX}-js-${index}`, + cacheId, })); }, Promise.resolve()); } @@ -757,6 +773,7 @@ export function loadAndAppendJsAssets( root: jsRoot, scriptAttributes, id: `${PREFIX}-js-${index}`, + cacheId, })), ); } From 98fc9cce44a9e1961e3faf0b690fdcdcd2a6a64d Mon Sep 17 00:00:00 2001 From: CoffeeDeveloper Date: Thu, 5 Jan 2023 17:42:48 +0800 Subject: [PATCH 4/6] AppRouter support className and fix window.microApps not equal to insider microApps variable (#622) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: microApps reassign to window.microApps * feat: AppRouter support className props Co-authored-by: 鱼腩 --- .../icestark/__tests__/AppRouter.spec.tsx | 26 ++++++++++++- packages/icestark/__tests__/app.spec.tsx | 37 ++++++++++++++++++- packages/icestark/src/AppRouter.tsx | 4 +- packages/icestark/src/apps.ts | 2 +- 4 files changed, 64 insertions(+), 5 deletions(-) diff --git a/packages/icestark/__tests__/AppRouter.spec.tsx b/packages/icestark/__tests__/AppRouter.spec.tsx index 69d52c07..954c8757 100644 --- a/packages/icestark/__tests__/AppRouter.spec.tsx +++ b/packages/icestark/__tests__/AppRouter.spec.tsx @@ -178,4 +178,28 @@ describe('AppRouter', () => { unmount(); }) -}) \ No newline at end of file + + test('app-className-custom', async () => { + (fetch as FetchMock).mockResponseOnce(umdSourceWithSetLibrary.toString()); + const { container, unmount } = render( + + + + ); + + window.history.pushState({}, 'test', '/seller'); + await delay(1000); + + expect(container.querySelector('.ice-app-router-custom')).toBeTruthy(); + + unmount(); + }) +}) diff --git a/packages/icestark/__tests__/app.spec.tsx b/packages/icestark/__tests__/app.spec.tsx index 6a073436..089cdbfc 100644 --- a/packages/icestark/__tests__/app.spec.tsx +++ b/packages/icestark/__tests__/app.spec.tsx @@ -117,5 +117,38 @@ describe('app start', () => { const errorApp = await createMicroApp('app-error'); expect(errorApp).toBe(null); - }) -}); \ No newline at end of file + }); + + test('window.microApps should be equal to insider microApps', async () => { + let status = ''; + registerMicroApps([ + { + name: 'app7', + activePath: '/testapp', + url: ['//icestark.com/index.js'], + mount: () => { + status = MOUNTED; + }, + unmount: () => { + status = UNMOUNTED; + }, + } as AppConfig, + ]); + window.history.pushState({}, 'test', '/testapp'); + const findMicroAppByName = (microApps, name) => microApps.filter(d => d.name === name)[0]; + await mountMicroApp('app7'); + expect(status).toBe(MOUNTED); + expect(findMicroAppByName(getMicroApps(), 'app7').status).toEqual(findMicroAppByName((window as any).microApps, 'app7').status); + expect(findMicroAppByName(getMicroApps(), 'app7').status).toEqual(status); + + await unmountMicroApp('app7'); + expect(status).toBe(UNMOUNTED); + expect(findMicroAppByName(getMicroApps(), 'app7').status).toEqual(findMicroAppByName((window as any).microApps, 'app7').status); + expect(findMicroAppByName(getMicroApps(), 'app7').status).toEqual(status); + + await createMicroApp('app7'); + expect(status).toBe(MOUNTED); + expect(findMicroAppByName(getMicroApps(), 'app7').status).toEqual(findMicroAppByName((window as any).microApps, 'app7').status); + expect(findMicroAppByName(getMicroApps(), 'app7').status).toEqual(status); + }); +}); diff --git a/packages/icestark/src/AppRouter.tsx b/packages/icestark/src/AppRouter.tsx index 3294dec0..97ade800 100644 --- a/packages/icestark/src/AppRouter.tsx +++ b/packages/icestark/src/AppRouter.tsx @@ -35,6 +35,7 @@ export interface AppRouterProps { basename?: string; fetch?: Fetch; prefetch?: Prefetch; + className?: string; } interface AppRouterState { @@ -194,6 +195,7 @@ export default class AppRouter extends React.Component +
{appLoading === this.appKey ? renderComponent(LoadingComponent, {}) : null} {React.cloneElement(element, { key: this.appKey, diff --git a/packages/icestark/src/apps.ts b/packages/icestark/src/apps.ts index 0acc5b7d..511ce77f 100644 --- a/packages/icestark/src/apps.ts +++ b/packages/icestark/src/apps.ts @@ -159,7 +159,7 @@ export function getAppConfig(appName: string) { } export function updateAppConfig(appName: string, config) { - microApps = microApps.map((microApp) => { + (window as any).microApps = microApps = microApps.map((microApp) => { if (microApp.name === appName) { return { ...microApp, From 5f4d46726df16a3512bd9913267834ca813da0b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E9=82=A3=E5=90=92?= Date: Fri, 6 Jan 2023 10:27:03 +0800 Subject: [PATCH 5/6] =?UTF-8?q?fix:=20=F0=9F=90=9B=20When=20icestark=20unl?= =?UTF-8?q?oads,=20avoid=20re-triggering=20unloadMicroApp=20(#522)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 🐛 When icestark unloads, avoid re-triggering unloadMicroA * feat: 🎸 pass ci Co-authored-by: ClarkXia --- CHANGELOG.md | 5 +++++ packages/icestark/src/AppRoute.tsx | 3 ++- packages/icestark/src/start.ts | 2 +- 3 files changed, 8 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 72124cc5..a4357b4c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,10 @@ See [https://github.com/ice-lab/icestark/releases](https://github.com/ice-lab/icestark/releases) for what has changed in each version of icestark. +## 2.8.0 + +- [fix] When icestark unloads, avoid re-triggering 'unloadMicroApp'. ([#521](https://github.com/ice-lab/icestark/issues/521)) + ## 2.7.3 - [fix] empty value or `undefined` in `activePath` array will be ignored. ([#558](https://github.com/ice-lab/icestark/issues/558)) @@ -85,6 +89,7 @@ See [https://github.com/ice-lab/icestark/releases](https://github.com/ice-lab/ic ## 2.2.1 - [fix] css assets are unable to load when remove `umd` from sub-application. + ## 2.2.0 - [feat] no need to use `umd` anymore. Migrate to `loadScriptMode` or use `setLibraryName` in sub-application. ([#240](https://github.com/ice-lab/icestark/issues/240)) diff --git a/packages/icestark/src/AppRoute.tsx b/packages/icestark/src/AppRoute.tsx index e327713d..2f46dcf8 100644 --- a/packages/icestark/src/AppRoute.tsx +++ b/packages/icestark/src/AppRoute.tsx @@ -3,6 +3,7 @@ import renderComponent from './util/renderComponent'; import { AppHistory } from './appHistory'; import { unloadMicroApp, unmountMicroApp, BaseConfig, createMicroApp } from './apps'; import { converArray2String } from './util/helpers'; +import { started } from './start'; import { callCapturedEventListeners, resetCapturedEventListeners, @@ -161,7 +162,7 @@ export default class AppRoute extends React.Component Date: Fri, 6 Jan 2023 10:31:49 +0800 Subject: [PATCH 6/6] chore: lint error --- packages/icestark/src/apps.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/packages/icestark/src/apps.ts b/packages/icestark/src/apps.ts index 511ce77f..b61ab435 100644 --- a/packages/icestark/src/apps.ts +++ b/packages/icestark/src/apps.ts @@ -159,7 +159,7 @@ export function getAppConfig(appName: string) { } export function updateAppConfig(appName: string, config) { - (window as any).microApps = microApps = microApps.map((microApp) => { + microApps = microApps.map((microApp) => { if (microApp.name === appName) { return { ...microApp, @@ -168,6 +168,8 @@ export function updateAppConfig(appName: string, config) { } return microApp; }); + // Update global variable of microApps. + (window as any).microApps = microApps; } /**