Skip to content

Commit

Permalink
✨ add runAfterFirstMounted effect hook (#96)
Browse files Browse the repository at this point in the history
  • Loading branch information
kuitos authored and howel52 committed Sep 27, 2019
1 parent a068549 commit 39a3e8a
Show file tree
Hide file tree
Showing 5 changed files with 105 additions and 66 deletions.
139 changes: 78 additions & 61 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,79 +33,79 @@ npm i qiankun -S

## 🔨 Getting Started

1. Create master framework with qiankun

```ts
import { registerMicroApps, start } from 'qiankun';

function render({ appContent, loading }) {
const container = document.getElementById('container');
ReactDOM.render(<Framework loading={loading} content={appContent}/>, container);
}

function genActiveRule(routerPrefix) {
return (location) => location.pathname.startsWith(routerPrefix);
}

registerMicroApps(
[
{
name: 'react app', // app name registered
entry: '//localhost:7100',
render,
activeRule: genActiveRule('/react') },
{
name: 'vue app',
entry: { scripts: [ '//localhost:7100/main.js' ] },
render,
activeRule: genActiveRule('/vue')
},
],
);

start();
```

2. Export the lifecycles from your sub app entry
### 1. Create master framework with qiankun

```ts
import { registerMicroApps, start } from 'qiankun';

function render({ appContent, loading }) {
const container = document.getElementById('container');
ReactDOM.render(<Framework loading={loading} content={appContent}/>, container);
}

function genActiveRule(routerPrefix) {
return (location) => location.pathname.startsWith(routerPrefix);
}

registerMicroApps(
[
{
name: 'react app', // app name registered
entry: '//localhost:7100',
render,
activeRule: genActiveRule('/react') },
{
name: 'vue app',
entry: { scripts: [ '//localhost:7100/main.js' ] },
render,
activeRule: genActiveRule('/vue')
},
],
);

start();
```

```ts
export async function bootstrap() {
console.log('react app bootstraped');
}

export async function mount(props) {
console.log(props);
ReactDOM.render(<App/>, document.getElementById('react15Root'));
}

export async function unmount() {
ReactDOM.unmountComponentAtNode(document.getElementById('react15Root'));
}
```
For more lifecycle information, see [single-spa lifecycles](https://single-spa.js.org/docs/building-applications.html#registered-application-lifecycle)
### 2. Export the lifecycles from your sub app entry

```ts
export async function bootstrap() {
console.log('react app bootstraped');
}

export async function mount(props) {
console.log(props);
ReactDOM.render(<App/>, document.getElementById('react15Root'));
}

export async function unmount() {
ReactDOM.unmountComponentAtNode(document.getElementById('react15Root'));
}
```
For more lifecycle information, see [single-spa lifecycles](https://single-spa.js.org/docs/building-applications.html#registered-application-lifecycle)

### 3. Config your sub app bundler

3. Config your sub app bundler

While you wanna build a sub app to integrate to qiankun, pls make sure your bundler have the required configuration below:
##### webpack:

#### webpack:

```js
output: {
library: packageName,
libraryTarget: 'umd',
jsonpFunction: `webpackJsonp_${packageName}`,
}
```
```

see https://webpack.js.org/configuration/output/#outputlibrary
##### parcel:

#### parcel:

```shell
parcel serve entry.js --global myvariable
```
```

see https://en.parceljs.org/cli.html#expose-modules-as-umd

## 💿 Examples
Expand All @@ -120,6 +120,8 @@ Visit `http://localhost:7099`

![](./examples/example.gif)



## :sparkles: Features

* Based on [single-spa](https://github.com/CanopyTax/single-spa)
Expand Down Expand Up @@ -166,7 +168,22 @@ function registerMicroApps<T extends object = {}>(apps: Array<RegistrableApp<T>>
function start({ prefetch: boolean, jsSandbox: boolean, singular: boolean }): void;
```

### setDefaultMountApp

Set which sub app shoule be active by default after master loaded.

```typescript
function setDefaultMountApp(defaultAppLink: string): void
```

### runAfterFirstMounted

```typescript
function runAfterFirstMounted(effect: () => void): void
```

## 🎯 Roadmap

- [ ] Parcel apps integration (multiple sub apps displayed at the same time, but only one uses router at most)
- [ ] Communication development kits between master and sub apps
- [ ] Custom side effects hijacker
Expand Down
1 change: 0 additions & 1 deletion examples/main/Framework.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ export default function Framework(props) {
</ol>
</nav>
</header>
<button onClick={setInterval}>set master interval</button>
{loading ? <div>loading...</div> : null}
<div dangerouslySetInnerHTML={{ __html: content }} className={style.appContainer}/>
</>
Expand Down
5 changes: 3 additions & 2 deletions examples/main/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
import React from 'react';
import ReactDOM from 'react-dom';
// import Vue from 'vue';
import { registerMicroApps, runDefaultMountEffects, start } from '../../dist/index.esm';
import { registerMicroApps, runAfterFirstMounted, setDefaultMountApp, start } from '../../dist/index.esm';
import Framework from './Framework';
// import Framework from './Framework.vue';

Expand Down Expand Up @@ -69,6 +69,7 @@ registerMicroApps(
},
);

runDefaultMountEffects('/react');
setDefaultMountApp('/react');
runAfterFirstMounted(() => console.info('first app mounted'));

start();
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"types": "./dist/index.d.ts",
"sideEffects": false,
"scripts": {
"start": "npm run start:main & npm run start:react16 & npm run start:react15 & npm run start:vue",
"start": "concurrently \"npm run start:main\" \"npm run start:react16\" \"npm run start:react15\" \"npm run start:vue\"",
"install:examples": "npm run build && cd examples/main && npm i && cd ../react16 && npm i && cd ../react15 && npm i && cd ../vue && npm i",
"start:main": "cd examples/main && npm start",
"start:react16": "cd examples/react16 && npm start",
Expand Down Expand Up @@ -43,6 +43,7 @@
"devDependencies": {
"@types/lodash": "^4.14.129",
"babel-plugin-import": "^1.12.1",
"concurrently": "^4.1.2",
"father-build": "^1.7.0",
"husky": "^2.3.0",
"np": "^5.0.3",
Expand Down
23 changes: 22 additions & 1 deletion src/effects.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,34 @@
*/
import { getMountedApps, navigateToUrl } from 'single-spa';

export function runDefaultMountEffects(defaultAppLink: string) {
const firstMountLogLabel = '[qiankun]: first app mounted';
if (process.env.NODE_ENV === 'development') {
console.time(firstMountLogLabel);
}

export function setDefaultMountApp(defaultAppLink: string) {

window.addEventListener('single-spa:no-app-change', () => {
const mountedApps = getMountedApps();
if (!mountedApps.length) {
navigateToUrl(defaultAppLink);
}
}, { once: true });
}

export function runDefaultMountEffects(defaultAppLink: string) {
console.warn('runDefaultMountEffects will be removed in next version, please use setDefaultMountApp instead!');
setDefaultMountApp(defaultAppLink);
}

export function runAfterFirstMounted(effect: () => void) {

window.addEventListener('single-spa:first-mount', () => {

if (process.env.NODE_ENV === 'development') {
console.timeEnd(firstMountLogLabel);
}

effect();
}, { once: true });
}

0 comments on commit 39a3e8a

Please sign in to comment.