Skip to content
New issue

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

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

Already on GitHub? # to your account

Feat: add pwa #1188

Merged
merged 6 commits into from
Aug 2, 2019
Merged
Show file tree
Hide file tree
Changes from 5 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
8 changes: 8 additions & 0 deletions packages/rax-plugin-app/src/config/web/getBase.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ const babelMerge = require('babel-merge');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');

const UniversalDocumentPlugin = require('../../plugins/UniversalDocumentPlugin');
const PWAAppShellPlugin = require('../../plugins/PWAAppShellPlugin');
const babelConfig = require('../babel.config');

const babelConfigWeb = babelMerge.all([{
Expand Down Expand Up @@ -85,6 +86,13 @@ module.exports = (rootDir) => {
render: serverRender.renderToString,
}]);

config.plugin('PWAAppShell')
.use(PWAAppShellPlugin, [{
rootDir,
path: 'src/shell/index.jsx',
render: serverRender.renderToString,
}]);

config.plugin('minicss')
.use(MiniCssExtractPlugin, [{
filename: '[name].css',
Expand Down
47 changes: 47 additions & 0 deletions packages/rax-plugin-app/src/plugins/PWAAppShellPlugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
const path = require('path');
const babel = require('@babel/core');
const { RawSource } = require('webpack-sources');
const { readFileSync, existsSync } = require('fs');

const babelConfig = require('../config/babel.config.js');

const NAME = 'PWAAppShellPlugin';

module.exports = class PWAAppShellPlugin {
constructor(options) {
this.render = options.render;

this.rootDir = options.rootDir ? options.rootDir : process.cwd();
this.shellPath = options.path ? options.path : 'src/shell/index.jsx';
}

apply(compiler) {
const filename = path.resolve(this.rootDir, this.shellPath);
if (!existsSync(filename)) return;

// render to index html
compiler.hooks.emit.tapAsync(NAME, (compilation, callback) => {
const htmlValue = compilation.assets['index.html'].source();

// get shell code
const fileContent = readFileSync(filename, 'utf-8');
const { code } = babel.transformSync(fileContent, babelConfig);

// code export
const fn = new Function('module', 'exports', 'require', code);
fn({ exports: {} }, module.exports, require);
const shellElement = module.exports.__esModule ? module.exports.default : module.exports;

// get shell element string
const source = this.render(require('rax').createElement(shellElement, {}));

// pre-render app shell element to index.html
compilation.assets['index.html'] = new RawSource(htmlValue.replace(
/<div(.*?) id=\"root\">(.*?)<\/div>/,
`<div id="root">${source}</div>`
));

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

export {
// core app
useAppEffect, _invokeAppCycle,
// core page
usePageEffect,
// core router
useRouter, push, go, goBack, goForward, canGo, replace,
useRouter, push, go, goBack, goForward, canGo, replace, preload, prerender
};
48 changes: 46 additions & 2 deletions packages/universal-app-runtime/src/router.js
Original file line number Diff line number Diff line change
@@ -1,16 +1,20 @@
import { createElement } from 'rax';
import * as RaxUseRouter from 'rax-use-router';
import { isWeb } from 'universal-env';
import { createHashHistory } from 'history';
import encodeQS from 'querystring/encode';


let _history = null;
let _routerConfig = {};

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

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

if (!component || Array.isArray(component) && component.length === 0) {
// Return null directly if not matched.
Expand Down Expand Up @@ -69,6 +73,46 @@ export function canGo(n) {
return _history.canGo(n);
}

/**
* Preload WebApp's page resource.
* @param config {Object}
* eg:
* 1. preload({pageIndex: 0}) // preload dynamic import page bundle
* 2. preload({href: '//xxx.com/font.woff', as: 'font', crossorigin: true}); // W3C preload
*/
export function preload(config) {
if (!isWeb) return;
if (config.pageIndex !== undefined) {
_routerConfig.routes[config.pageIndex].component();
} else {
const linkElement = document.createElement('link');
linkElement.rel = 'preload';
linkElement.as = config.as;
linkElement.href = config.href;
config.crossorigin && (linkElement.crossorigin = true);
document.head.appendChild(linkElement);
}
}

/**
* Rrerender WebApp's page content.
* @param config {Object}
* eg:
* 1. prerender({pageIndex: 0}) // preload dynamic import page bundle for now(todo page alive)
* 2. prerender({href:'https://m.taobao.com'}); // W3C prerender
*/
export function prerender(config) {
if (!isWeb) return;
if (config.pageIndex !== undefined) {
_routerConfig.routes[config.pageIndex].component();
} else {
const linkElement = document.createElement('link');
linkElement.rel = 'prerender';
linkElement.href = config.href;
document.head.appendChild(linkElement);
}
}

function checkHistory() {
if (_history === null) throw new Error('Router not initized properly, please call useRouter first.');
}
20 changes: 17 additions & 3 deletions packages/universal-app-shell-loader/src/index.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
const { join } = require('path');
const { getOptions } = require('loader-utils');
const { existsSync } = require('fs');

const historyMemory = {
hash: 'createHashHistory',
Expand All @@ -21,11 +22,15 @@ module.exports = function(content) {
routes = [];
}

let appRender = '';
let fixRootStyle = '';
/**
* Weex only support memory history.
*/
if (options.type === 'weex') historyType = 'memory';
if (options.type === 'weex') {
historyType = 'memory';
appRender = 'render(createElement(Entry), null, { driver: DriverUniversal });';
}
/**
* Web only compatible with 750rpx.
*/
Expand All @@ -35,6 +40,12 @@ module.exports = function(content) {
const html = document.documentElement;
html.style.fontSize = html.clientWidth / 750 * ${mutiple} + 'px';
`;
appRender = 'render(createElement(Entry), document.getElementById("root"), { driver: DriverUniversal });';
// app shell
if (existsSync(join(this.rootContext, 'src/shell/index.jsx'))) {
appRender = `import Shell from "${getDepPath('shell/index', this.rootContext)}";`;
appRender += 'render(createElement(Shell, {}, createElement(Entry)), document.getElementById("root"), { driver: DriverUniversal, hydrate: true });';
}
}

/**
Expand All @@ -49,10 +60,13 @@ module.exports = function(content) {
const assembleRoutes = routes.map((route, index) => {
// First level function to support hooks will autorun function type state,
// Second level function to support rax-use-router rule autorun function type component.
const dynamicImportComponent = `() => import(/* webpackChunkName: "${route.component.replace(/\//g, '_')}" */ '${getDepPath(route.component, this.rootContext)}').then((mod) => () => interopRequire(mod))`;
const importComponent = `() => () => interopRequire(require('${getDepPath(route.component, this.rootContext)}'))`;

return `routes.push({
index: ${index},
path: '${route.path}',
component: () => () => interopRequire(require('${getDepPath(route.component, this.rootContext)}')),
component: ${options.type === 'web' ? dynamicImportComponent : importComponent}
});`;
}).join('\n');

Expand Down Expand Up @@ -95,7 +109,7 @@ module.exports = function(content) {
return app;
}

render(createElement(Entry), null, { driver: DriverUniversal });
${appRender}
`;
return source;
} else {
Expand Down