Skip to content

Commit

Permalink
release: icestark@1.1.0 (#27)
Browse files Browse the repository at this point in the history
* fix: rm localUrl api

* fix: rm localUrl

* chore: migrate testing-library

ref testing-library/dom-testing-library#260

* feat: add AppRoute render/component props

* chore: rm setupFilesAfterEnv

* fix: adjust for cr

* fix: adjust JS asset to js asset

* fix: rm useless cleanup-after-each

* feat: add AppRouteComponentProps ts

* chore: update version

* fix: interface match to Match
  • Loading branch information
daysai authored and imsobear committed Nov 13, 2019
1 parent eca33fb commit 619b175
Show file tree
Hide file tree
Showing 8 changed files with 281 additions and 96 deletions.
8 changes: 4 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@ice/stark",
"version": "1.0.0",
"version": "1.1.0",
"description": "Icestark is a JavaScript library for multiple projects, Ice workbench solution.",
"scripts": {
"build": "rm -rf lib && tsc",
Expand Down Expand Up @@ -46,6 +46,8 @@
"@commitlint/cli": "^7.5.2",
"@commitlint/config-conventional": "^7.5.0",
"@ice/spec": "^0.1.4",
"@testing-library/react": "^9.3.2",
"@testing-library/jest-dom": "^4.2.3",
"@types/jest": "^24.0.12",
"@types/node": "^12.0.0",
"@types/path-to-regexp": "^1.7.0",
Expand All @@ -54,13 +56,11 @@
"@types/url-parse": "^1.4.3",
"codecov": "^3.4.0",
"eslint": "^5.16.0",
"stylelint": "^10.1.0",
"husky": "^2.2.0",
"jest": "^24.7.1",
"jest-dom": "^3.4.0",
"react": "^16.7.0",
"react-dom": "^16.7.0",
"react-testing-library": "^7.0.0",
"stylelint": "^10.1.0",
"ts-jest": "^24.0.2",
"typescript": "^3.4.4"
},
Expand Down
4 changes: 2 additions & 2 deletions packages/icestark-app/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,14 +38,14 @@
"@commitlint/cli": "^7.5.2",
"@commitlint/config-conventional": "^7.5.0",
"@ice/spec": "^0.1.4",
"@testing-library/jest-dom": "^4.2.3",
"@types/jest": "^24.0.12",
"@types/node": "^12.0.0",
"codecov": "^3.4.0",
"eslint": "^5.16.0",
"stylelint": "^10.1.0",
"husky": "^2.2.0",
"jest": "^24.7.1",
"jest-dom": "^3.4.0",
"stylelint": "^10.1.0",
"ts-jest": "^24.0.2",
"typescript": "^3.4.4"
},
Expand Down
2 changes: 1 addition & 1 deletion packages/icestark-app/tests/index.spec.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import 'jest-dom/extend-expect';
import '@testing-library/jest-dom/extend-expect';

import {
getBasename,
Expand Down
57 changes: 30 additions & 27 deletions src/AppRoute.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import * as React from 'react';
import * as ReactDOM from 'react-dom';
import { AppHistory } from './appHistory';
import { loadAssets, emptyAssets } from './handleAssets';
import { ICESTSRK_NOT_FOUND } from './constant';
import { setCache, getCache } from './cache';

const statusElementId = 'icestarkStatusContainer';
Expand All @@ -23,6 +23,25 @@ interface AppRouteState {
// "hashbang" - “ajax crawlable” (deprecated by Google) hashes like #!/ and #!/sunshine/lollipops
type hashType = 'hashbang' | 'noslash' | 'slash';

interface Match<Params extends { [K in keyof Params]?: string } = {}> {
params: Params;
isExact: boolean;
path: string;
url: string;
}

interface Location<Query extends { [K in keyof Query]?: string } = {}> {
pathname: string;
query: Query;
hash: string;
}

export interface AppRouteComponentProps<Params extends { [K in keyof Params]?: string } = {}> {
match: Match<Params>;
location: Location;
history: AppHistory;
}

export interface AppConfig {
title?: string;
hashType?: boolean | hashType;
Expand All @@ -35,11 +54,12 @@ export interface AppConfig {

export interface AppRouteProps extends AppConfig {
path: string | string[];
url: string | string[];
url?: string | string[];
useShadow?: boolean;
ErrorComponent?: any;
LoadingComponent?: any;
NotFoundComponent?: any;
component?: React.ReactElement;
render?: (props?: AppRouteComponentProps) => React.ReactElement;
forceRenderCount?: number;
onAppEnter?: (appConfig: AppConfig) => void;
onAppLeave?: (appConfig: AppConfig) => void;
Expand All @@ -60,8 +80,6 @@ function getAppConfig(appRouteProps: AppRouteProps): AppConfig {
'useShadow',
'ErrorComponent',
'LoadingComponent',
'NotFoundComponent',
'useShadow',
'onAppEnter',
'onAppLeave',
];
Expand All @@ -84,8 +102,6 @@ export default class AppRoute extends React.Component<AppRouteProps, AppRouteSta

private unmounted: boolean = false;

private triggerNotFound: boolean = false;

static defaultProps = {
useShadow: false,
exact: false,
Expand Down Expand Up @@ -129,13 +145,11 @@ export default class AppRoute extends React.Component<AppRouteProps, AppRouteSta
*/
renderChild = (prevAppConfig?: AppConfig): void => {
const {
path,
url,
title,
rootId,
ErrorComponent,
LoadingComponent,
NotFoundComponent,
useShadow,
onAppEnter,
onAppLeave,
Expand All @@ -162,7 +176,7 @@ export default class AppRoute extends React.Component<AppRouteProps, AppRouteSta
this.removeElementFromBase(rootId);
let rootElement: any = this.appendElementToBase(rootId);

// Prevent duplicate creation of shadowRoot
// prevent duplicate creation of shadowRoot
if (useShadow && !rootElement.shadowRoot) {
rootElement = rootElement.attachShadow
? rootElement.attachShadow({ mode: 'open', delegatesFocus: false })
Expand All @@ -171,25 +185,15 @@ export default class AppRoute extends React.Component<AppRouteProps, AppRouteSta

setCache('root', rootElement);

// Empty useless assets before loading
// empty useless assets before loading
emptyAssets(useShadow);

// Handle NotFound
if (path === ICESTSRK_NOT_FOUND && url === ICESTSRK_NOT_FOUND) {
// loadAssets callback maybe slower than render NotFoundComponent
this.triggerNotFound = true;
this.renderStatusElement(NotFoundComponent);
return;
}

this.triggerNotFound = false;

if (title) document.title = title;

// Generate bundleList
// generate bundleList
const bundleList: string[] = Array.isArray(url) ? url : [url];

// Handle loading
// handle loading
this.setState({ cssLoading: true });
this.renderStatusElement(LoadingComponent);

Expand All @@ -202,13 +206,12 @@ export default class AppRoute extends React.Component<AppRouteProps, AppRouteSta
if (err) {
// Handle error
this.renderStatusElement(ErrorComponent, { err });
this.removeElementFromBase(rootId);
this.setState({ cssLoading: false });
return true;
}

if (!this.triggerNotFound) {
// loadAssets callback maybe slower than render NotFoundComponent
this.removeElementFromBase(statusElementId);
}
this.removeElementFromBase(statusElementId);

return this.unmounted;
},
Expand Down
61 changes: 42 additions & 19 deletions src/AppRouter.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import * as React from 'react';
import * as urlParse from 'url-parse';
import AppRoute, { AppConfig, AppRouteProps } from './AppRoute';
import { AppConfig, AppRouteProps, AppRouteComponentProps } from './AppRoute';
import appHistory from './appHistory';
import matchPath from './matchPath';
import { recordAssets } from './handleAssets';
import { ICESTSRK_NOT_FOUND } from './constant';
Expand Down Expand Up @@ -51,13 +52,25 @@ function getHashPath(hash: string = '/'): string {
return searchIndex === -1 ? hashPath : hashPath.substr(0, searchIndex);
}

/**
* Render Component, compatible with Component and <Component>
*/
function renderComponent(Component: any, props = {}): React.ReactElement {
return React.isValidElement(Component) ? (
React.cloneElement(Component, props)
) : (
<Component {...props} />
);
}

export default class AppRouter extends React.Component<AppRouterProps, AppRouterState> {
private originalPush: OriginalStateFunction = window.history.pushState;

private originalReplace: OriginalStateFunction = window.history.replaceState;

static defaultProps = {
ErrorComponent: <div>js bundle loaded error</div>,
onRouteChange: () => {},
ErrorComponent: ({ err }) => <div>{err}</div>,
NotFoundComponent: <div>NotFound</div>,
useShadow: false,
};
Expand All @@ -76,15 +89,21 @@ export default class AppRouter extends React.Component<AppRouterProps, AppRouter
this.handleRouteChange(location.href, 'init');

// render NotFoundComponent eventListener
window.addEventListener('icestark:not-found', () => {
this.setState({ url: ICESTSRK_NOT_FOUND });
});
window.addEventListener('icestark:not-found', this.triggerNotFound);
}

componentWillUnmount() {
this.unHijackHistory();
window.removeEventListener('icestark:not-found', this.triggerNotFound);
}

/**
* Trigger NotFound
*/
triggerNotFound = () => {
this.setState({ url: ICESTSRK_NOT_FOUND });
};

/**
* Hijack window.history
*/
Expand All @@ -103,7 +122,7 @@ export default class AppRouter extends React.Component<AppRouterProps, AppRouter
};

/**
* Unhijacking history
* Unhijack window.history
*/
unHijackHistory = (): void => {
window.history.pushState = this.originalPush;
Expand Down Expand Up @@ -157,7 +176,6 @@ export default class AppRouter extends React.Component<AppRouterProps, AppRouter
const { url, forceRenderCount } = this.state;

const { pathname, query, hash } = urlParse(url, true);
const { localUrl } = query;

let match: any = null;
let element: any;
Expand Down Expand Up @@ -187,25 +205,30 @@ export default class AppRouter extends React.Component<AppRouterProps, AppRouter
onAppEnter,
onAppLeave,
};
if (localUrl) {
extraProps.url = localUrl;
}

if (match) {
const { path, basename } = element.props as AppRouteProps;
const { path, basename, render, component } = element.props as AppRouteProps;

const commonProps: AppRouteComponentProps = {
location: { pathname, query, hash },
match,
history: appHistory,
};

if (component) {
return renderComponent(component, commonProps);
}

if (render && typeof render === 'function') {
return render(commonProps);
}

// render AppRoute
setCache('basename', basename || (Array.isArray(path) ? path[0] : path));

return React.cloneElement(element, extraProps);
}

return (
<AppRoute
path={ICESTSRK_NOT_FOUND}
url={ICESTSRK_NOT_FOUND}
NotFoundComponent={NotFoundComponent}
useShadow={useShadow}
/>
);
return renderComponent(NotFoundComponent, {});
}
}
15 changes: 10 additions & 5 deletions src/appHistory.ts
Original file line number Diff line number Diff line change
@@ -1,20 +1,25 @@
const appHistory = {
push: (url: string) => {
export interface AppHistory {
push(path: string): void;
replace(path: string): void;
}

const appHistory: AppHistory = {
push: (path: string) => {
window.history.pushState(
{
forceRender: true,
},
null,
url,
path,
);
},
replace: (url: string) => {
replace: (path: string) => {
window.history.replaceState(
{
forceRender: true,
},
null,
url,
path,
);
},
};
Expand Down
2 changes: 1 addition & 1 deletion src/handleAssets.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ function loadAsset(
element.addEventListener(
'error',
() => {
callback(isCss ? undefined : new Error(`JS asset loaded error: ${url}`));
callback(isCss ? undefined : `js asset loaded error: ${url}`);
},
false,
);
Expand Down
Loading

0 comments on commit 619b175

Please sign in to comment.