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

Feat/universal app runtime #1179

Merged
merged 6 commits into from
Jul 31, 2019
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
16 changes: 16 additions & 0 deletions packages/universal-app-runtime/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"name": "universal-app-runtime",
"version": "0.1.1",
"description": "Provide framework level runtime support of universal app.",
"main": "lib/index.js",
"author": "Rax Team",
"dependencies": {
"history": "^4.9.0",
"querystring": "^0.2.0",
"rax-use-router": "^2.0.2",
"universal-env": "^1.0.1"
},
"peerDependencies": {
"rax": "^1.0.8"
}
}
12 changes: 12 additions & 0 deletions packages/universal-app-runtime/src/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import invokeCycle from './invokeCycle';

export const appCycles = {};

export function useAppEffect(cycle, callback) {
const cycles = appCycles[cycle] = appCycles[cycle] || [];
cycles.push(callback);
}

export function invokeAppCycle(cycle, ...args) {
invokeCycle(appCycles, cycle, ...args);
}
12 changes: 12 additions & 0 deletions packages/universal-app-runtime/src/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { useAppEffect, invokeAppCycle as _invokeAppCycle } from './app';
import { usePageEffect } from './page';
import { useRouter, push, go, goBack, goForward, canGo, replace } from './router';

export {
// core app
useAppEffect, _invokeAppCycle,
// core page
usePageEffect,
// core router
useRouter, push, go, goBack, goForward, canGo, replace,
};
16 changes: 16 additions & 0 deletions packages/universal-app-runtime/src/invokeCycle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

export default function invokeCycle(cycleMap, cycle, ...args) {
if (cycleMap.hasOwnProperty(cycle)) {
const cycles = cycleMap[cycle];
let fn;
let error;
while (fn = cycles.shift()) { // eslint-disable-line
try {
fn(...args);
} catch (err) {
error = err;
}
}
if (error) throw error;
}
}
52 changes: 52 additions & 0 deletions packages/universal-app-runtime/src/page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { useEffect } from 'rax';
import { isWeb, isWeex } from 'universal-env';

const visibleListeners = {
show: [],
hide: [],
};
let initialShow = false;
let prevVisibleState = true;

export function usePageEffect(cycle, callback) {
switch (cycle) {
case 'show':
case 'hide':
useEffect(() => {
visibleListeners[cycle].push(callback);
return () => {
const index = visibleListeners[cycle].indexOf(callback);
visibleListeners[cycle].splice(index, 1);
};
});
}

// Invoke first time show.
if (cycle === 'show') {
if (initialShow === false) {
initialShow = true;
useEffect(() => {
invokeCycle('show');
});
}
}
}

function invokeCycle(cycle, ...args) {
for (let i = 0, l = visibleListeners[cycle].length; i < l; i++) {
visibleListeners[cycle][i](...args);
}
}

if (isWeb) {
document.addEventListener('visibilitychange', function() {
const currentVisibleState = document.visibilityState === 'visible';
if (prevVisibleState !== currentVisibleState) {
invokeCycle(currentVisibleState ? 'show' : 'hide');
}
prevVisibleState = currentVisibleState;
});
} else if (isWeex) {
// require('@weex/module')
// todo support weex.
}
74 changes: 74 additions & 0 deletions packages/universal-app-runtime/src/router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { createElement } from 'rax';
import * as RaxUseRouter from 'rax-use-router';
import { createHashHistory } from 'history';
import encodeQS from 'querystring/encode';

let _history = null;

export function useRouter(routerConfig) {
const { history = createHashHistory(), routes } = routerConfig;
_history = history;

function Router(props) {
const { component } = RaxUseRouter.useRouter(() => routerConfig);

if (!component || Array.isArray(component) && component.length === 0) {
// Return null directly if not matched.
return null;
} else {
return createElement(component, props);
}
}

return { Router };
}

export function Link(props) {
const { to, query, hash, state, type = 'span', onClick, ...others } = props;
const throughProps = Object.assign({}, others, {
onClick: (evt) => {
if (to) {
let url = to;
if (query) url += '?' + encodeQS(query);
if (hash) url += '#' + hash;
push(url, state);
}
onClick(evt);
}
});
return createElement(type, throughProps);
}

export function push(path, state) {
checkHistory();
return _history.push(path, state);
}

export function replace(path, state) {
checkHistory();
return _history.replace(path, state);
}

export function go(n) {
checkHistory();
return _history.go(n);
}

export function goBack() {
checkHistory();
return _history.goBack();
}

export function goForward() {
checkHistory();
return _history.goForward();
}

export function canGo(n) {
checkHistory();
return _history.canGo(n);
}

function checkHistory() {
if (_history === null) throw new Error('Router not initized properly, please call useRouter first.');
}