added CSR fallback and optionally disable SSR

This commit is contained in:
William Welling
2017-07-19 12:11:15 -05:00
parent bd76342e85
commit 1c2818002f
9 changed files with 96 additions and 27 deletions

View File

@@ -15,11 +15,19 @@ module.exports = {
// NOTE: Space is capitalized because 'namespace' is a reserved string in TypeScript // NOTE: Space is capitalized because 'namespace' is a reserved string in TypeScript
nameSpace: '/dspace-spring-rest/api' nameSpace: '/dspace-spring-rest/api'
}, },
// Caching settings
cache: { cache: {
// NOTE: how long should objects be cached for by default // NOTE: how long should objects be cached for by default
msToLive: 15 * 60 * 1000, // 15 minute msToLive: 15 * 60 * 1000, // 15 minute
control: 'max-age=60' // revalidate browser control: 'max-age=60' // revalidate browser
}, },
// Angular Universal settings
universal: {
preboot: true,
async: true,
time: false
},
// Log directory
logDirectory: '.', logDirectory: '.',
// NOTE: rehydrate or replay // NOTE: rehydrate or replay
// rehydrate will transfer prerender state to browser state, actions do not need to replay // rehydrate will transfer prerender state to browser state, actions do not need to replay

View File

@@ -1,6 +1,7 @@
{ {
"watch": [ "watch": [
"dist", "dist",
"config",
"src/index.html" "src/index.html"
], ],
"ext": "js ts json html" "ext": "js ts json html"

View File

@@ -1,12 +1,14 @@
import { ServerConfig } from './server-config.interface'; import { ServerConfig } from './server-config.interface';
import { CacheConfig } from './cache-config.interface'; import { CacheConfig } from './cache-config.interface';
import { UniversalConfig } from './universal-config.interface';
export interface GlobalConfig { export interface GlobalConfig {
ui: ServerConfig; ui: ServerConfig;
rest: ServerConfig; rest: ServerConfig;
prerenderStrategy: string;
production: boolean; production: boolean;
cache: CacheConfig; cache: CacheConfig;
universal: UniversalConfig;
logDirectory: string; logDirectory: string;
prerenderStrategy: string;
debug: boolean; debug: boolean;
} }

View File

@@ -0,0 +1,5 @@
export interface UniversalConfig {
preboot: boolean,
async: boolean,
time: boolean
}

19
src/index.csr.html Normal file
View File

@@ -0,0 +1,19 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<base href="/">
<title>DSpace</title>
<meta name="viewport" content="width=device-width,minimum-scale=1">
<link rel="icon" type="image/x-icon" href="assets/images/favicon.ico" />
</head>
<body>
<ds-app></ds-app>
</body>
<!-- this is needed for CSR fallback -->
<script async src="/client.js"></script>
</html>

View File

@@ -13,4 +13,6 @@
<ds-app></ds-app> <ds-app></ds-app>
</body> </body>
<!-- do not include client bundle, it is injected with Zone already loaded -->
</html> </html>

View File

@@ -56,7 +56,7 @@ app.set('view engine', 'html');
app.set('views', 'src'); app.set('views', 'src');
function cacheControl(req, res, next) { function cacheControl(req, res, next) {
// instruct browser to revalidate in 60 seconds // instruct browser to revalidate
res.header('Cache-Control', ENV_CONFIG.cache.control || 'max-age=60'); res.header('Cache-Control', ENV_CONFIG.cache.control || 'max-age=60');
next(); next();
} }
@@ -67,18 +67,34 @@ app.use('/', cacheControl, express.static('dist', { index: false }));
// app.get('/data.json', serverApi); // app.get('/data.json', serverApi);
// app.use('/api', createMockApi()); // app.use('/api', createMockApi());
function ngApp(req, res) {
function onHandleError(parentZoneDelegate, currentZone, targetZone, error) {
console.warn('Error in SSR, serving for direct CSR');
res.sendFile('index.csr.html', { root: './src' });
}
if (ENV_CONFIG.universal.preboot) {
Zone.current.fork({ name: 'CSR fallback', onHandleError }).run(() => {
res.render('../dist/index', {
req,
res,
preboot: ENV_CONFIG.universal.preboot,
async: ENV_CONFIG.universal.async,
time: ENV_CONFIG.universal.time,
baseUrl: ENV_CONFIG.ui.nameSpace,
originUrl: ENV_CONFIG.ui.baseUrl,
requestUrl: req.originalUrl
});
});
} else {
console.log('Universal preboot off, service for direct CSD');
res.sendFile('index.csr.html', { root: './src' });
}
}
ROUTES.forEach((route: string) => { ROUTES.forEach((route: string) => {
app.get(route, (req, res) => { app.get(route, ngApp);
res.cookie('ui_origin', ENV_CONFIG.ui.baseUrl, {
maxAge: 1000 * 60 * 15,
httpOnly: true,
signed: false
});
res.render('../dist/index', {
req: req,
res: res
});
});
}); });
function serverStarted() { function serverStarted() {

View File

@@ -44,7 +44,7 @@ app.set('view engine', 'html');
app.set('views', 'src'); app.set('views', 'src');
function cacheControl(req, res, next) { function cacheControl(req, res, next) {
// instruct browser to revalidate in 60 seconds // instruct browser to revalidate
res.header('Cache-Control', ENV_CONFIG.cache.control || 'max-age=60'); res.header('Cache-Control', ENV_CONFIG.cache.control || 'max-age=60');
next(); next();
} }
@@ -55,18 +55,34 @@ app.use('/', cacheControl, express.static('dist', { index: false }));
// app.get('/data.json', serverApi); // app.get('/data.json', serverApi);
// app.use('/api', createMockApi()); // app.use('/api', createMockApi());
function ngApp(req, res) {
function onHandleError(parentZoneDelegate, currentZone, targetZone, error) {
console.warn('Error in SSR, serving for direct CSR');
res.sendFile('index.csr.html', { root: './src' });
}
if (ENV_CONFIG.universal.preboot) {
Zone.current.fork({ name: 'CSR fallback', onHandleError }).run(() => {
res.render('../dist/index', {
req,
res,
preboot: ENV_CONFIG.universal.preboot,
async: ENV_CONFIG.universal.async,
time: ENV_CONFIG.universal.time,
baseUrl: ENV_CONFIG.ui.nameSpace,
originUrl: ENV_CONFIG.ui.baseUrl,
requestUrl: req.originalUrl
});
});
} else {
console.log('Universal preboot off, service for direct CSD');
res.sendFile('index.csr.html', { root: './src' });
}
}
ROUTES.forEach((route: string) => { ROUTES.forEach((route: string) => {
app.get(route, (req, res) => { app.get(route, ngApp);
res.cookie('ui_origin', ENV_CONFIG.ui.baseUrl, {
maxAge: 1000 * 60 * 15,
httpOnly: true,
signed: false
});
res.render('../dist/index', {
req: req,
res: res
});
});
}); });
function serverStarted() { function serverStarted() {

View File

@@ -27,7 +27,7 @@ export class BrowserTransferState extends TransferState {
if (this.config.prerenderStrategy === 'replay') { if (this.config.prerenderStrategy === 'replay') {
if (cache.actions !== undefined) { if (cache.actions !== undefined) {
if (this.config.debug) { if (this.config.debug) {
console.info('Replay:', cache.actions); console.info('Replay:', (cache.actions !== undefined && cache.actions !== null) ? cache.actions : []);
} }
this.store.dispatch(new StoreAction(StoreActionTypes.REPLAY, cache.actions)); this.store.dispatch(new StoreAction(StoreActionTypes.REPLAY, cache.actions));
} else { } else {
@@ -35,7 +35,7 @@ export class BrowserTransferState extends TransferState {
} }
} else if (this.config.prerenderStrategy === 'rehydrate') { } else if (this.config.prerenderStrategy === 'rehydrate') {
if (this.config.debug) { if (this.config.debug) {
console.info('Rehydrate:', cache.state); console.info('Rehydrate:', (cache.state !== undefined && cache.state !== null) ? cache.state : []);
} }
this.store.dispatch(new StoreAction(StoreActionTypes.REHYDRATE, cache.state)); this.store.dispatch(new StoreAction(StoreActionTypes.REHYDRATE, cache.state));
} else { } else {