Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Release 2.4.0 #306

Merged
merged 7 commits into from
Jun 16, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ module.exports = deepmerge(tslint, {
'@typescript-eslint/explicit-member-accessibility': 'off',
'@typescript-eslint/explicit-function-return-type': 'off',
'@typescript-eslint/interface-name-prefix': 1,
'no-unused-expressions': 'off',
},
settings: {
react: {
Expand Down
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,12 @@

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.4.0

- [feat] support appending extra attributes for scripts when using `loadScriptMode = script`. ([#276](https://github.com/ice-lab/icestark/issues/276))
- [fix] unexpectable sandbox's cleaning up when load modules. ([#293](https://github.com/ice-lab/icestark/issues/293))
- [fix] missing `ErrorComponent` causes React rendering's error. ([#312](https://github.com/ice-lab/icestark/issues/312))

## 2.3.2

- [refact] compatible with sandbox spell error.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ice/stark",
"version": "2.3.2",
"version": "2.4.0",
"description": "Icestark is a JavaScript library for multiple projects, Ice workbench solution.",
"scripts": {
"install:deps": "rm -rf node_modules && rm -rf ./packages/*/node_modules && yarn install && lerna exec -- npm install",
Expand Down
5 changes: 5 additions & 0 deletions packages/icestark-data/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
# Changelog

## 0.1.3

- [feat] support `Symbol` key for index. ([#298](https://github.com/ice-lab/icestark/issues/298))
2 changes: 1 addition & 1 deletion packages/icestark-data/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ice/stark-data",
"version": "0.1.2",
"version": "0.1.3",
"description": "icestark-data is a JavaScript library for icestark, used for communication.",
"scripts": {
"build": "rm -rf lib && tsc",
Expand Down
32 changes: 17 additions & 15 deletions packages/icestark-data/src/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ import { setCache, getCache } from './cache';

const eventNameSpace = 'event';

type StringSymbolUnion = string | symbol;

interface Hooks {
emit(key: string, value: any): void;
on(key: string, callback: (value: any) => void): void;
off(key: string, callback?: (value: any) => void): void;
has(key: string): boolean;
emit(key: StringSymbolUnion, value: any): void;
on(key: StringSymbolUnion, callback: (value: any) => void): void;
off(key: StringSymbolUnion, callback?: (value: any) => void): void;
has(key: StringSymbolUnion): boolean;
}

class Event implements Hooks {
Expand All @@ -19,11 +21,11 @@ class Event implements Hooks {
this.eventEmitter = {};
}

emit(key: string, ...args) {
emit(key: StringSymbolUnion, ...args) {
const keyEmitter = this.eventEmitter[key];

if (!isArray(keyEmitter) || (isArray(keyEmitter) && keyEmitter.length === 0)) {
warn(`event.emit: no callback is called for ${key}`);
warn(`event.emit: no callback is called for ${String(key)}`);
return;
}

Expand All @@ -32,12 +34,11 @@ class Event implements Hooks {
});
}

on(key: string, callback: (value: any) => void) {
if (typeof key !== 'string') {
warn('event.on: key should be string');
on(key: StringSymbolUnion, callback: (value: any) => void) {
if (typeof key !== 'string' && typeof key !== 'symbol') {
warn('event.on: key should be string / symbol');
return;
}

if (callback === undefined || typeof callback !== 'function') {
warn('event.on: callback is required, should be function');
return;
Expand All @@ -50,14 +51,15 @@ class Event implements Hooks {
this.eventEmitter[key].push(callback);
}

off(key: string, callback?: (value: any) => void) {
if (typeof key !== 'string') {
warn('event.off: key should be string');
off(key: StringSymbolUnion, callback?: (value: any) => void) {
if (typeof key !== 'string' && typeof key !== 'symbol') {
warn('event.off: key should be string / symbol');
return;

}

if (!isArray(this.eventEmitter[key])) {
warn(`event.off: ${key} has no callback`);
warn(`event.off: ${String(key)} has no callback`);
return;
}

Expand All @@ -69,7 +71,7 @@ class Event implements Hooks {
this.eventEmitter[key] = this.eventEmitter[key].filter(cb => cb !== callback);
}

has(key: string) {
has(key: StringSymbolUnion) {
const keyEmitter = this.eventEmitter[key];
return isArray(keyEmitter) && keyEmitter.length > 0;
}
Expand Down
59 changes: 32 additions & 27 deletions packages/icestark-data/src/store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,18 @@ import { setCache, getCache } from './cache';

const storeNameSpace = 'store';

type StringSymbolUnion = string | symbol;

// eslint-disable-next-line @typescript-eslint/interface-name-prefix
interface IO {
set(key: any, value?: any): void;
get(key?: string): void;
set(key: string | symbol | object, value?: any): void;
get(key?: StringSymbolUnion): void;
}

interface Hooks {
on(key: string, callback: (value: any) => void, force?: boolean): void;
off(key: string, callback?: (value: any) => void): void;
has(key: string): boolean;
on(key: StringSymbolUnion, callback: (value: any) => void, force?: boolean): void;
off(key: StringSymbolUnion, callback?: (value: any) => void): void;
has(key: StringSymbolUnion): boolean;
}

class Store implements IO, Hooks {
Expand All @@ -27,16 +30,16 @@ class Store implements IO, Hooks {
this.storeEmitter = {};
}

_getValue(key: string) {
_getValue(key: StringSymbolUnion) {
return this.store[key];
}

_setValue(key: string, value: any) {
_setValue(key: StringSymbolUnion, value: any) {
this.store[key] = value;
this._emit(key);
}

_emit(key) {
_emit(key: StringSymbolUnion) {
const keyEmitter = this.storeEmitter[key];

if (!isArray(keyEmitter) || (isArray(keyEmitter) && keyEmitter.length === 0)) {
Expand All @@ -49,39 +52,41 @@ class Store implements IO, Hooks {
});
}

get(key?: string) {
get(key?: StringSymbolUnion) {
if (key === undefined) {
return this.store;
}

if (typeof key !== 'string') {
warn(`store.get: key should be string`);
if (typeof key !== 'string' && typeof key !== 'symbol') {
warn(`store.get: key should be string / symbol`);
return null;
}

return this._getValue(key);
}

set(key: any, value?: any) {
if (typeof key !== 'string') {
if (!isObject(key)) {
warn('store.set: key should be string / object');
return;
}
set<T>(key: string | symbol | object, value?: T) {
if (typeof key !== 'string'
&& typeof key !== 'symbol'
&& !isObject(key)) {
warn('store.set: key should be string / symbol / object');
return;
}

if (isObject(key)) {
Object.keys(key).forEach(k => {
const v = key[k];

this._setValue(k, v);
});
} else {
this._setValue(key as StringSymbolUnion, value);
}

this._setValue(key, value);
}

on(key: string, callback: (value: any) => void, force?: boolean) {
if (typeof key !== 'string') {
warn('store.on: key should be string');
on(key: StringSymbolUnion, callback: (value: any) => void, force?: boolean) {
if (typeof key !== 'string' && typeof key !== 'symbol') {
warn('store.on: key should be string / symbol');
return;
}

Expand All @@ -101,14 +106,14 @@ class Store implements IO, Hooks {
}
}

off(key: string, callback?: (value: any) => void) {
if (typeof key !== 'string') {
warn('store.off: key should be string');
off(key: StringSymbolUnion, callback?: (value: any) => void) {
if (typeof key !== 'string' && typeof key !== 'symbol') {
warn('store.off: key should be string / symbol');
return;
}

if (!isArray(this.storeEmitter[key])) {
warn(`store.off: ${key} has no callback`);
warn(`store.off: ${String(key)} has no callback`);
return;
}

Expand All @@ -120,7 +125,7 @@ class Store implements IO, Hooks {
this.storeEmitter[key] = this.storeEmitter[key].filter(cb => cb !== callback);
}

has(key: string) {
has(key: StringSymbolUnion) {
const keyEmitter = this.storeEmitter[key];
return isArray(keyEmitter) && keyEmitter.length > 0;
}
Expand Down
4 changes: 2 additions & 2 deletions packages/icestark-data/tests/event.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ describe('event', () => {
};

event.on([]);
expect(warnMockFn).toBeCalledWith('event.on: key should be string');
expect(warnMockFn).toBeCalledWith('event.on: key should be string / symbol');

event.on('testOn');
expect(warnMockFn).toBeCalledWith('event.on: callback is required, should be function');
Expand All @@ -33,7 +33,7 @@ describe('event', () => {
};

event.off([]);
expect(warnMockFn).toBeCalledWith('event.off: key should be string');
expect(warnMockFn).toBeCalledWith('event.off: key should be string / symbol');

event.off('testOff');
expect(warnMockFn).toBeCalledWith('event.off: testOff has no callback');
Expand Down
8 changes: 4 additions & 4 deletions packages/icestark-data/tests/store.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ describe('store', () => {
expect(store.get()).toStrictEqual({});

store.get([]);
expect(warnMockFn).toBeCalledWith('store.get: key should be string');
expect(warnMockFn).toBeCalledWith('store.get: key should be string / symbol');

expect(store.get('test')).toBeUndefined();
});
Expand All @@ -27,7 +27,7 @@ describe('store', () => {
};

store.set([]);
expect(warnMockFn).toBeCalledWith('store.set: key should be string / object');
expect(warnMockFn).toBeCalledWith('store.set: key should be string / symbol / object');

const testArray = [];
const testObj = {};
Expand All @@ -50,7 +50,7 @@ describe('store', () => {
};

store.on([]);
expect(warnMockFn).toBeCalledWith('store.on: key should be string');
expect(warnMockFn).toBeCalledWith('store.on: key should be string / symbol');

store.on('testOn');
expect(warnMockFn).toBeCalledWith('store.on: callback is required, should be function');
Expand All @@ -75,7 +75,7 @@ describe('store', () => {
};

store.off([]);
expect(warnMockFn).toBeCalledWith('store.off: key should be string');
expect(warnMockFn).toBeCalledWith('store.off: key should be string / symbol');

store.off('testOff');
expect(warnMockFn).toBeCalledWith('store.off: testOff has no callback');
Expand Down
4 changes: 2 additions & 2 deletions src/AppRouter.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -55,14 +55,14 @@ export default class AppRouter extends React.Component<AppRouterProps, AppRouter

private unmounted: boolean = false;

private err: string = ''; // js assets load err
private err: string | Error = ''; // js assets load err

private appKey: string = '';

static defaultProps = {
onRouteChange: () => {},
// eslint-disable-next-line react/jsx-filename-extension
ErrorComponent: ({ err }) => <div>{ err || 'Error' }</div>,
ErrorComponent: ({ err }: { err: string | Error}) => <div>{ typeof err === 'string' ? err : err?.message }</div>,
LoadingComponent: <div>Loading...</div>,
NotFoundComponent: <div>NotFound</div>,
shouldAssetsRemove: () => true,
Expand Down
27 changes: 21 additions & 6 deletions src/apps.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,22 @@ import Sandbox, { SandboxConstructor, SandboxProps } from '@ice/sandbox';
import * as isEmpty from 'lodash.isempty';
import { NOT_LOADED, NOT_MOUNTED, LOADING_ASSETS, UNMOUNTED, LOAD_ERROR, MOUNTED } from './util/constant';
import { matchActivePath, MatchOptions, PathData, PathOptions } from './util/matchPath';
import { createSandbox, getUrlAssets, getEntryAssets, appendAssets, loadAndAppendCssAssets, emptyAssets, Assets } from './util/handleAssets';
import {
createSandbox,
getUrlAssets,
getEntryAssets,
loadAndAppendCssAssets,
loadAndAppendJsAssets,
emptyAssets,
Assets,
} from './util/handleAssets';
import { setCache } from './util/cache';
import { loadBundle } from './util/loader';
import { globalConfiguration, StartConfiguration } from './start';
import { getLifecyleByLibrary, getLifecyleByRegister } from './util/getLifecycle';

export type ScriptAttributes = string[] | ((url: string) => string[]);

interface ActiveFn {
(url: string): boolean;
}
Expand Down Expand Up @@ -44,6 +54,10 @@ export interface BaseConfig extends PathOptions {
props?: object;
cached?: boolean;
title?: string;
/**
* custom script attributes,only effective when scripts load by `<scrpit />`
*/
scriptAttributes?: ScriptAttributes;
}

interface LifeCycleFn {
Expand Down Expand Up @@ -146,8 +160,8 @@ export async function loadAppModule(appConfig: AppConfig) {

let lifecycle: ModuleLifeCycle = {};
onLoadingApp(appConfig);
const appSandbox = createSandbox(appConfig.sandbox);
const { url, container, entry, entryContent, name } = appConfig;
const appSandbox = createSandbox(appConfig.sandbox) as Sandbox;
const { url, container, entry, entryContent, name, scriptAttributes = [] } = appConfig;
const appAssets = url ? getUrlAssets(url) : await getEntryAssets({
root: container,
entry,
Expand All @@ -167,7 +181,10 @@ export async function loadAppModule(appConfig: AppConfig) {
await loadAndAppendCssAssets(appAssets);
lifecycle = await loadBundle(appAssets.jsList, appSandbox);
} else {
await appendAssets(appAssets, appSandbox, fetch);
await Promise.all([
loadAndAppendCssAssets(appAssets),
loadAndAppendJsAssets(appAssets, { sandbox: appSandbox, fetch, scriptAttributes }),
]);

lifecycle =
getLifecyleByLibrary() ||
Expand All @@ -180,8 +197,6 @@ export async function loadAppModule(appConfig: AppConfig) {

onFinishLoading(appConfig);

// clear appSandbox
appSandbox?.clear();
return combineLifecyle(lifecycle, appConfig);
}

Expand Down
Loading