forked from Automattic/wp-calypso
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathsections-middleware.js
117 lines (100 loc) · 4.25 KB
/
sections-middleware.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
import config from '@automattic/calypso-config';
import page from 'page';
import * as LoadingError from 'calypso/layout/error';
import { performanceTrackerStart } from 'calypso/lib/performance-tracking';
import { addReducerToStore } from 'calypso/state/add-reducer';
import { bumpStat } from 'calypso/state/analytics/actions';
import { setSectionLoading } from 'calypso/state/ui/actions';
import { activateNextLayoutFocus } from 'calypso/state/ui/layout-focus/actions';
import * as controller from './controller/index.web';
import sections from './sections';
import isSectionEnabled from './sections-filter';
import { receiveSections, load } from './sections-helper';
import { pathToRegExp } from './utils';
receiveSections( sections );
function activateSection( section, context ) {
controller.setSectionMiddleware( section )( context );
context.store.dispatch( activateNextLayoutFocus() );
}
async function loadSection( context, sectionDefinition ) {
context.store.dispatch( setSectionLoading( true ) );
// If the section chunk is not loaded within 400ms, report it to analytics
const loadReportTimeout = setTimeout( () => {
context.store.dispatch( bumpStat( 'calypso_chunk_waiting', sectionDefinition.name ) );
}, 400 );
try {
// load the section module, i.e., its webpack chunk
const requiredModule = await load( sectionDefinition.name, sectionDefinition.module );
// call the module initialization function (possibly async, registers page.js handlers etc.)
await requiredModule.default( controller.clientRouter, addReducerToStore( context.store ) );
} finally {
context.store.dispatch( setSectionLoading( false ) );
// If the load was faster than the timeout, this will cancel the analytics reporting
clearTimeout( loadReportTimeout );
}
}
/**
* Cache of already loaded or loading section modules. Every section module is in one of
* three states regarding the cache:
* - no record in the cache: not loaded or not currently loading
* - record value is `true`: already loaded and initialized
* - record value is a `Promise`: is currently loading, the promise will fulfill when done.
* Don't start a second load with `loadSection` but rather wait for the existing promise.
*/
const _loadedSections = {};
function createPageDefinition( path, sectionDefinition ) {
// skip this section if it's not enabled in current environment
const { envId } = sectionDefinition;
if ( envId && ! envId.includes( config( 'env_id' ) ) ) {
return;
}
const pathRegex = pathToRegExp( path );
// if the section doesn't support logged-out views, redirect to login if user is not logged in
if ( ! sectionDefinition.enableLoggedOut ) {
page( pathRegex, controller.redirectLoggedOut );
}
// Install navigation performance tracking.
if ( sectionDefinition.trackLoadPerformance ) {
page( pathRegex, performanceTrackerStart( sectionDefinition.name ) );
}
page( pathRegex, async function ( context, next ) {
try {
const loadedSection = _loadedSections[ sectionDefinition.module ];
if ( loadedSection ) {
// wait for the promise if loading, do nothing when already loaded
if ( loadedSection !== true ) {
await loadedSection;
}
} else {
// start loading the section and record the `Promise` in a map
const loadingSection = loadSection( context, sectionDefinition );
_loadedSections[ sectionDefinition.module ] = loadingSection;
// wait until the section module is loaded and the set the map record to `true`
await loadingSection;
_loadedSections[ sectionDefinition.module ] = true;
}
// activate the section after ensuring it's fully loaded
activateSection( sectionDefinition, context );
next();
} catch ( error ) {
// delete the cache record on failure; next attempt to load will start from scratch
delete _loadedSections[ sectionDefinition.module ];
console.error( error ); // eslint-disable-line
if ( ! LoadingError.isRetry() && process.env.NODE_ENV !== 'development' ) {
LoadingError.retry( sectionDefinition.name );
} else {
LoadingError.show( context, sectionDefinition.name );
}
}
} );
}
export const setupRoutes = () => {
for ( const section of sections ) {
if ( ! isSectionEnabled( section ) ) {
continue;
}
for ( const path of section.paths ) {
createPageDefinition( path, section );
}
}
};