Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
* When using `skeleton` and `cssExtract`, use `<link rel=preload>` to load CSS asynchronously instead of `<link rel=stylesheet>`, which will let browser render Skeleton earlier (lavas-project#73).
* lavas-template-basic/appshell also modified.
* All test cases can run concurrently.
  • Loading branch information
xiaoiver authored Mar 13, 2018
1 parent c2832fe commit ae31e1f
Show file tree
Hide file tree
Showing 29 changed files with 720 additions and 225 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,4 @@ coverage
package-lock.json
packages/lavas-core-vue/test/fixtures/**/dist
packages/lavas-core-vue/test/fixtures/**/.lavas
packages/lavas-core-vue/test/temp
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"build:lavas-core-vue": "babel packages/lavas-core-vue/core --out-dir packages/lavas-core-vue/dist --copy-files",
"build:lavas-cli": "babel packages/lavas-cli/src --out-dir packages/lavas-cli/dist --copy-files",
"lint": "fecs ./ --rule --type 'vue,js,css'",
"test": "nyc ava -v",
"test": "rimraf packages/lavas-core-vue/test/temp && nyc ava -v",
"nyc:report": "nyc report --reporter=html",
"publish:core": "lerna publish --scope=lavas-core-vue"
},
Expand All @@ -35,8 +35,9 @@
"npm": ">= 3.0.0"
},
"ava": {
"concurrency": 1,
"serial": false,
"failFast": true,
"concurrency": 10,
"files": [
"packages/lavas-core-vue/test/unit/**/*.test.js",
"packages/lavas-core-vue/test/spec/**/*.js",
Expand Down Expand Up @@ -150,7 +151,9 @@
"fecs": "^1.4.0",
"koa": "^2.5.0",
"nyc": "^10.3.2",
"rimraf": "^2.6.2",
"semver": "^5.4.1",
"sinon": "^4.4.2",
"superkoa": "^1.0.3",
"supertest": "^3.0.0",
"vuetify": "^0.17.6",
Expand Down
22 changes: 21 additions & 1 deletion packages/lavas-core-vue/core/builder/base-builder.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,15 @@ import {join, basename, normalize} from 'path';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import SkeletonWebpackPlugin from 'vue-skeleton-webpack-plugin';
import VueSSRClientPlugin from 'vue-server-renderer/client-plugin';
import OmmitCSSPlugin from '../plugins/ommit-css-webpack-plugin';

import {TEMPLATE_HTML, SPA_TEMPLATE_HTML, DEFAULT_ENTRY_NAME, DEFAULT_SKELETON_PATH,
CONFIG_FILE, LAVAS_DIRNAME_IN_DIST, CLIENT_MANIFEST, STORE_FILE} from '../constants';
import {assetsPath, resolveAliasPath, camelCaseToDash} from '../utils/path';
import {enableHotReload} from '../utils/webpack';
import * as JsonUtil from '../utils/json';
import templateUtil from '../utils/template';
import Logger from '../utils/logger';

import RouteManager from '../route-manager';
import WebpackConfig from '../webpack';
Expand Down Expand Up @@ -162,7 +164,7 @@ export default class BaseBuilder {
*/
async addHtmlPlugin(spaConfig, baseUrl = '/') {
// allow user to provide a custom HTML template
let rootDir = this.config.globals.rootDir;
let {globals: {rootDir}, skeleton: {enable: enableSkeleton, asyncCSS}, build: {cssExtract}} = this.config;
let htmlFilename;
let templatePath;
let tempTemplatePath;
Expand All @@ -188,6 +190,24 @@ export default class BaseBuilder {
templateUtil.client(await readFile(templatePath, 'utf8'), baseUrl)
);

/**
* don't inject <link rel=stylesheet> in head,
* use <link rel=preload> to load CSS asynchronously instead
* https://github.com/lavas-project/lavas/issues/73
*/
let entryClientContent = await readFile(join(rootDir, 'core/entry-client.js'), 'utf8');
let shouldUpdateLavasTemplate = entryClientContent.indexOf('window.mountLavas') === -1;
let enableAsyncCSS = asyncCSS && enableSkeleton && cssExtract;
this.config.enableAsyncCSS = enableAsyncCSS && !shouldUpdateLavasTemplate;
if (enableAsyncCSS) {
if (shouldUpdateLavasTemplate) {
Logger.warn('build', 'If you want to render Skeleton faster, please update `entry-client.js`. You can refer to https://github.com/lavas-project/lavas/issues/73.');
}
else {
spaConfig.plugin('ommit-css').use(OmmitCSSPlugin);
}
}

// add html webpack plugin
spaConfig.plugin('html').use(HtmlWebpackPlugin, [{
filename: htmlFilename,
Expand Down
8 changes: 5 additions & 3 deletions packages/lavas-core-vue/core/config-reader.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ const DEFAULT_CONFIG = {
}
},
skeleton: {
enable: true
enable: true,
asyncCSS: true
},
router: {},
errorHandler: {
Expand Down Expand Up @@ -109,7 +110,7 @@ const DEFAULT_CONFIG = {
};

/**
* config items used in runtime
* config items used in runtime, which will be injected in .lavas/config.json
*/
export const RUMTIME_ITEMS = {
buildVersion: true,
Expand All @@ -123,7 +124,8 @@ export const RUMTIME_ITEMS = {
errorHandler: true,
serviceWorker: {
swDest: true
}
},
skeleton: true
};

export default class ConfigReader {
Expand Down
21 changes: 21 additions & 0 deletions packages/lavas-core-vue/core/plugins/ommit-css-webpack-plugin.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
/**
* @file OmmitCSSPlugin
* @author panyuqi
* @desc filter css
*/

export default class OmmitCSSPlugin {
constructor() {}

apply(compiler) {
compiler.plugin('compilation', (compilation) => {
compilation.plugin(
'html-webpack-plugin-alter-asset-tags',
(args, cb) => {
args.head = args.head.filter((link) => link.attributes.rel !== 'stylesheet');
cb(null, args);
}
);
});
}
}
6 changes: 5 additions & 1 deletion packages/lavas-core-vue/core/templates/client.html.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@
<link rel="preload" href="<%= '\<%= jsFilePath %\>' %>" as="script">
<%= "\<% } %\>" %>
<%= "\<% for (var cssFilePath of htmlWebpackPlugin.files.css) { %\>" %>
<link rel="preload" href="<%= '\<%= cssFilePath %\>' %>" as="style">
<%= "\<% if (htmlWebpackPlugin.options.config.enableAsyncCSS) { %\>" %>
<link rel="preload" href="<%= '\<%= cssFilePath %\>' %>" as="style" onload="this.onload=null;this.rel='stylesheet';window.STYLE_READY=1;window.mountLavas&&window.mountLavas();">
<%= "\<% } else { %\>" %>
<link rel="preload" href="<%= '\<%= cssFilePath %\>' %>" as="style">
<%= "\<% } %\>" %>
<%= "\<% } %\>" %>

<!-- @CUSTOM_HEAD@ -->
Expand Down
37 changes: 10 additions & 27 deletions packages/lavas-core-vue/core/utils/workbox.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,17 @@ export function getWorkboxFiles(isProd) {
*
* @param {Object} webpackConfig webpack config
* @param {Object} lavasConfig lavas config
* @param {?Object} entryConfig entry config (undefined when SPA and SSR)
*/
export function useWorkbox(webpackConfig, lavasConfig, entryConfig) {
let {buildVersion, build: {publicPath, ssr}, globals, router: {base = '/'}} = lavasConfig;
let workboxConfig = entryConfig ? entryConfig.serviceWorker : lavasConfig.serviceWorker;
export function useWorkbox(webpackConfig, lavasConfig) {
let {
buildVersion,
build: {publicPath, ssr},
globals,
router: {base = '/'},
serviceWorker: workboxConfig
} = lavasConfig;
let {swSrc, appshellUrl, appshellUrls} = workboxConfig;

if (entryConfig) {
swSrc = getEntryConfigValue(swSrc, entryConfig.name);
workboxConfig.swDest = getEntryConfigValue(workboxConfig.swDest, entryConfig.name);
workboxConfig.swPath = getEntryConfigValue(workboxConfig.swPath, entryConfig.name);
}

if (base !== '/' && !base.endsWith('/')) {
base += '/';
}
Expand Down Expand Up @@ -79,8 +77,7 @@ export function useWorkbox(webpackConfig, lavasConfig, entryConfig) {
}
}
else {
let entryHtml = entryConfig ? `${entryConfig.name}.html` : 'index.html';
registerNavigationClause = `workboxSW.router.registerNavigationRoute('${base}${entryHtml}');`;
registerNavigationClause = `workboxSW.router.registerNavigationRoute('${base}index.html');`;
}

if (!/workboxSW\.router\.registerNavigationRoute/.test(serviceWorkerContent)) {
Expand All @@ -95,24 +92,10 @@ export function useWorkbox(webpackConfig, lavasConfig, entryConfig) {


// write new service worker in .lavas/sw.js
let tempSwSrc = entryConfig
? join(globals.rootDir, './.lavas', entryConfig.name, 'sw-temp.js')
: join(globals.rootDir, './.lavas', 'sw-temp.js');
let tempSwSrc = join(globals.rootDir, './.lavas', 'sw-temp.js');
writeFileSync(tempSwSrc, serviceWorkerContent, 'utf8');
workboxConfig.swSrc = tempSwSrc;

// use [email protected]
webpackConfig.plugin('workbox').use(WorkboxWebpackPlugin, [workboxConfig]);
}

/**
* replace [entryName] with real value
* entries/[entryName]/service-worker.js => entries/index/service-worker.js
*
* @param {string} value sericeWorker config value
* @param {string} entryName entry name
* @return {string} real value
*/
function getEntryConfigValue(value, entryName) {
return value ? value.replace(/\[entryName\]/g, entryName) : undefined;
}
2 changes: 1 addition & 1 deletion packages/lavas-core-vue/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "lavas-core-vue",
"version": "1.1.4",
"version": "1.1.5",
"description": "Lavas core implemented by Vue",
"main": "dist/index.js",
"files": [
Expand Down
22 changes: 18 additions & 4 deletions packages/lavas-core-vue/test/fixtures/simple/core/entry-client.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/**
* @file client entry
* @author *__ author __*{% if: *__ email __* %}(*__ email __*){% /if %}
* @author xiaoiver([email protected])
*/

import Vue from 'vue';
import {getMiddlewares, execSeries, getClientContext} from '@/core/middleware';
import {getMiddlewares, execSeries, getClientContext} from '@/.lavas/middleware';
import lavasConfig from '@/.lavas/config';
import {createApp} from './app';
import ProgressBar from '@/components/ProgressBar';
Expand All @@ -14,7 +14,7 @@ import '@/assets/stylus/main.styl';

let loading = Vue.prototype.$loading = new Vue(ProgressBar).$mount();
let {App, router, store} = createApp();
let {ssr, middleware: middConf = {}} = lavasConfig;
let {build: {ssr, cssExtract}, middleware: middConf = {}, skeleton: {enable: enableSkeleton, asyncCSS}} = lavasConfig;
let app;

// Sync with server side state.
Expand Down Expand Up @@ -80,9 +80,23 @@ if (!usingAppshell && ssr) {
});
}
else {
/**
* Use async CSS in SPA under following
* 1. `skeleton.enable`
* 2. `skeleton.asyncCSS`
* 3. `build.cssExtract`
*/
let enableAsyncCSS = enableSkeleton && asyncCSS && cssExtract;
window.mountLavas = () => {
setTimeout(() => app.$mount('#app'), 0);
};
// Fetch data in client side.
handleAsyncData();
app = new App().$mount('#app');
app = new App();
if (!enableAsyncCSS
|| (enableAsyncCSS && window.STYLE_READY)) {
window.mountLavas();
}
}

function handleMiddlewares() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">

{{{ meta.title.text() }}}
{{{ meta.meta.text() }}}
Expand Down Expand Up @@ -43,7 +43,7 @@
<title></title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">

<!-- Add to home screen for Android and modern mobile browsers -->
<link rel="manifest" href="<<= htmlWebpackPlugin.options.config.build.publicPath >>static/manifest.json?v=<<= htmlWebpackPlugin.options.config.buildVersion >>">
Expand All @@ -55,7 +55,11 @@
<link rel="preload" href="<<= jsFilePath >>" as="script">
<< } >>
<< for (var cssFilePath of htmlWebpackPlugin.files.css) { >>
<link rel="preload" href="<<= cssFilePath >>" as="style">
<< if (htmlWebpackPlugin.options.config.enableAsyncCSS) { >>
<link rel="preload" href="<<= cssFilePath >>" as="style" onload="this.onload=null;this.rel='stylesheet';window.STYLE_READY=1;window.mountLavas&&window.mountLavas();">
<< } else { >>
<link rel="preload" href="<<= cssFilePath >>" as="style">
<< } >>
<< } >>
</head>
<body>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">

{{{ meta.title.text() }}}
{{{ meta.meta.text() }}}
Expand Down Expand Up @@ -43,7 +43,7 @@
<title></title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">

<!-- Add to home screen for Android and modern mobile browsers -->
<link rel="manifest" href="<<= htmlWebpackPlugin.options.config.build.publicPath >>static/manifest.json?v=<<= htmlWebpackPlugin.options.config.buildVersion >>">
Expand All @@ -55,7 +55,11 @@
<link rel="preload" href="<<= jsFilePath >>" as="script">
<< } >>
<< for (var cssFilePath of htmlWebpackPlugin.files.css) { >>
<link rel="preload" href="<<= cssFilePath >>" as="style">
<< if (htmlWebpackPlugin.options.config.enableAsyncCSS) { >>
<link rel="preload" href="<<= cssFilePath >>" as="style" onload="this.onload=null;this.rel='stylesheet';window.STYLE_READY=1;">
<< } else { >>
<link rel="preload" href="<<= cssFilePath >>" as="style">
<< } >>
<< } >>
</head>
<body>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">

{{{ meta.title.text() }}}
{{{ meta.meta.text() }}}
Expand Down Expand Up @@ -43,7 +43,7 @@
<title></title>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1, user-scalable=no">

<!-- Add to home screen for Android and modern mobile browsers -->
<link rel="manifest" href="<<= htmlWebpackPlugin.options.config.build.publicPath >>static/manifest.json?v=<<= htmlWebpackPlugin.options.config.buildVersion >>">
Expand All @@ -55,7 +55,11 @@
<link rel="preload" href="<<= jsFilePath >>" as="script">
<< } >>
<< for (var cssFilePath of htmlWebpackPlugin.files.css) { >>
<link rel="preload" href="<<= cssFilePath >>" as="style">
<< if (htmlWebpackPlugin.options.config.enableAsyncCSS) { >>
<link rel="preload" href="<<= cssFilePath >>" as="style" onload="this.onload=null;this.rel='stylesheet';window.STYLE_READY=1;">
<< } else { >>
<link rel="preload" href="<<= cssFilePath >>" as="style">
<< } >>
<< } >>
</head>
<body>
Expand Down
Loading

0 comments on commit ae31e1f

Please sign in to comment.