@parameter1/base-cms-marko-web 4.7.0 → 4.9.0
Sign up to get free protection for your applications and to get access to all the features.
- package/components/browser-component.marko.js +2 -2
- package/components/document/components/body-wrapper.marko.js +2 -2
- package/components/document/components/error.marko.js +2 -2
- package/components/document/components/live-reload.marko.js +2 -2
- package/components/document/components/polyfill.marko.js +2 -2
- package/components/document/components/styles.marko +23 -0
- package/components/document/components/styles.marko.js +57 -0
- package/components/document/container.marko.js +2 -2
- package/components/document/index.marko +8 -19
- package/components/document/index.marko.js +15 -38
- package/components/element/array.marko.js +2 -2
- package/components/element/audio.marko.js +2 -2
- package/components/element/block.marko.js +2 -2
- package/components/element/clear.marko.js +2 -2
- package/components/element/components/image.marko.js +2 -2
- package/components/element/components/text.marko.js +2 -2
- package/components/element/content/address1.marko.js +2 -2
- package/components/element/content/address2.marko.js +2 -2
- package/components/element/content/audio.marko.js +2 -2
- package/components/element/content/authors.marko.js +2 -2
- package/components/element/content/body.marko.js +2 -2
- package/components/element/content/byline.marko.js +2 -2
- package/components/element/content/city-state-zip.marko.js +2 -2
- package/components/element/content/contributors.marko.js +2 -2
- package/components/element/content/country.marko.js +2 -2
- package/components/element/content/embed-code.marko.js +2 -2
- package/components/element/content/end-date.marko.js +2 -2
- package/components/element/content/ends.marko.js +2 -2
- package/components/element/content/fax.marko.js +2 -2
- package/components/element/content/images.marko.js +2 -2
- package/components/element/content/mobile.marko.js +2 -2
- package/components/element/content/name.marko.js +2 -2
- package/components/element/content/phone.marko.js +2 -2
- package/components/element/content/photographers.marko.js +2 -2
- package/components/element/content/public-email.marko.js +2 -2
- package/components/element/content/published.marko.js +2 -2
- package/components/element/content/short-name.marko.js +2 -2
- package/components/element/content/sidebar-stubs.marko.js +2 -2
- package/components/element/content/sidebars.marko.js +2 -2
- package/components/element/content/source.marko.js +2 -2
- package/components/element/content/sponsors.marko.js +2 -2
- package/components/element/content/start-date.marko.js +2 -2
- package/components/element/content/starts.marko.js +2 -2
- package/components/element/content/teaser.marko.js +2 -2
- package/components/element/content/title.marko.js +2 -2
- package/components/element/content/tollfree.marko.js +2 -2
- package/components/element/content/transcript.marko.js +2 -2
- package/components/element/content/website.marko.js +2 -2
- package/components/element/date.marko.js +2 -2
- package/components/element/image/caption.marko.js +2 -2
- package/components/element/image/credit.marko.js +2 -2
- package/components/element/image/display-name.marko.js +2 -2
- package/components/element/image/slider.marko.js +2 -2
- package/components/element/img.marko.js +2 -2
- package/components/element/index.marko.js +2 -2
- package/components/element/link.marko.js +2 -2
- package/components/element/magazine-issue/description.marko.js +2 -2
- package/components/element/magazine-issue/digital-edition-url.marko.js +2 -2
- package/components/element/magazine-issue/name.marko.js +2 -2
- package/components/element/magazine-issue/pdf-url.marko.js +2 -2
- package/components/element/magazine-publication/cancel-url.marko.js +2 -2
- package/components/element/magazine-publication/change-address-url.marko.js +2 -2
- package/components/element/magazine-publication/description.marko.js +2 -2
- package/components/element/magazine-publication/einquiry-url.marko.js +2 -2
- package/components/element/magazine-publication/name.marko.js +2 -2
- package/components/element/magazine-publication/renewal-url.marko.js +2 -2
- package/components/element/magazine-publication/reprints-url.marko.js +2 -2
- package/components/element/magazine-publication/subscribe-url.marko.js +2 -2
- package/components/element/obj-array.marko.js +2 -2
- package/components/element/obj-audio.marko.js +2 -2
- package/components/element/obj-date.marko.js +2 -2
- package/components/element/obj-nodes.marko.js +2 -2
- package/components/element/obj-text.marko.js +2 -2
- package/components/element/obj.marko.js +2 -2
- package/components/element/object-link.js +1 -1
- package/components/element/picture.marko.js +2 -2
- package/components/element/text.marko.js +2 -2
- package/components/element/website-section/description.marko.js +2 -2
- package/components/element/website-section/hierarchy.marko.js +2 -2
- package/components/element/website-section/name.marko.js +2 -2
- package/components/font/google.marko.js +2 -2
- package/components/font/link.marko.js +2 -2
- package/components/font/typekit.marko.js +2 -2
- package/components/load-more/index.marko.js +2 -2
- package/components/load-more/trigger.marko.js +2 -2
- package/components/node/body.marko.js +2 -2
- package/components/node/element.marko.js +2 -2
- package/components/node/footer.marko.js +2 -2
- package/components/node/header.marko.js +2 -2
- package/components/node/image-inner-wrapper.marko.js +2 -2
- package/components/node/image-wrapper.marko.js +2 -2
- package/components/node/image.marko.js +2 -2
- package/components/node/index.marko.js +2 -2
- package/components/node-list/body.marko.js +2 -2
- package/components/node-list/element.marko.js +2 -2
- package/components/node-list/footer.marko.js +2 -2
- package/components/node-list/header.marko.js +2 -2
- package/components/node-list/index.marko.js +2 -2
- package/components/node-list/node.marko.js +2 -2
- package/components/node-list/nodes.marko.js +2 -2
- package/components/page/container.marko.js +2 -2
- package/components/page/description.marko.js +2 -2
- package/components/page/image.marko.js +2 -2
- package/components/page/layouts/content.marko.js +2 -2
- package/components/page/layouts/default.marko.js +2 -2
- package/components/page/layouts/dynamic-page.marko.js +2 -2
- package/components/page/layouts/magazine-issue.marko.js +2 -2
- package/components/page/layouts/magazine-publication.marko.js +2 -2
- package/components/page/layouts/website-section.marko.js +2 -2
- package/components/page/metadata/components/common.marko.js +2 -2
- package/components/page/metadata/content.marko.js +2 -2
- package/components/page/metadata/default.marko.js +2 -2
- package/components/page/metadata/dynamic-page.marko.js +2 -2
- package/components/page/metadata/magazine-issue.marko.js +2 -2
- package/components/page/metadata/magazine-publication.marko.js +2 -2
- package/components/page/metadata/website-section.marko.js +2 -2
- package/components/page/rel-canonical.marko.js +2 -2
- package/components/page/title.marko.js +2 -2
- package/components/page/wrapper.marko.js +2 -2
- package/components/resolve/page.marko.js +2 -2
- package/components/rss/website-section.marko.js +2 -2
- package/config/core.js +0 -41
- package/express/asset-loader.js +55 -0
- package/express/cdn.js +27 -0
- package/express/css-loader.js +117 -0
- package/express/error-handlers.js +2 -0
- package/express/index.js +12 -3
- package/middleware/with-content.js +4 -0
- package/middleware/with-dynamic-page.js +4 -0
- package/middleware/with-magazine-issue.js +4 -0
- package/middleware/with-magazine-publication.js +4 -0
- package/middleware/with-website-section.js +4 -0
- package/package.json +3 -3
- package/scss/fonts/alata-fallback.scss +7 -0
- package/scss/fonts/arimo-fallback.scss +7 -0
- package/scss/fonts/fira-sans-fallback.scss +1 -0
- package/scss/fonts/ibm-plex-sans-fallback.scss +7 -0
- package/scss/fonts/informapro-fallback.scss +6 -0
- package/scss/fonts/lato-fallback.scss +7 -0
- package/scss/fonts/montserrat-fallback.scss +1 -0
- package/scss/fonts/open-sans-condensed-fallback.scss +1 -0
- package/scss/fonts/open-sans-fallback.scss +1 -0
- package/scss/fonts/oswold-fallback.scss +1 -0
- package/scss/fonts/roboto-condensed-fallback.scss +7 -0
- package/scss/fonts/roboto-fallback.scss +7 -0
- package/scss/fonts/roboto-slab-fallback.scss +7 -0
- package/scss/fonts/solitaire-mvb-pro-fallback.scss +6 -0
- package/scss/fonts/source-sans-4-fallback.scss +1 -0
- package/scss/fonts/source-serif-pro-fallback.scss +7 -0
- package/config/dist-loader.js +0 -42
- package/express/purged-css.js +0 -11
- package/public/lazysizes/v5.3.2.js +0 -2
@@ -0,0 +1,55 @@
|
|
1
|
+
const path = require('path');
|
2
|
+
const { readFile } = require('fs').promises;
|
3
|
+
const { asyncRoute } = require('@parameter1/base-cms-utils');
|
4
|
+
|
5
|
+
const readManifest = async (loc) => {
|
6
|
+
try {
|
7
|
+
const contents = await readFile(loc, 'utf8');
|
8
|
+
return JSON.parse(contents);
|
9
|
+
} catch (e) {
|
10
|
+
if (e.code === 'ENOENT') return null;
|
11
|
+
throw e;
|
12
|
+
}
|
13
|
+
};
|
14
|
+
|
15
|
+
const getRelPathFromManifest = async ({ distDir, type, entry }) => {
|
16
|
+
const file = path.resolve(distDir, type, 'manifest.json');
|
17
|
+
const manifest = await readManifest(file);
|
18
|
+
if (!manifest) throw new Error(`Unable to load the asset manifest for type ${type}`);
|
19
|
+
|
20
|
+
const asset = manifest[entry];
|
21
|
+
if (!asset) throw new Error(`Unable to extract an asset for type ${type} using manifest entry ${entry}`);
|
22
|
+
return `${type}/${asset.file}`;
|
23
|
+
};
|
24
|
+
|
25
|
+
const isProduction = process.env.NODE_ENV === 'production';
|
26
|
+
const types = [
|
27
|
+
{ type: 'js', entry: 'browser/index.js' },
|
28
|
+
];
|
29
|
+
|
30
|
+
module.exports = ({ distDir }) => asyncRoute(async (req, res, next) => {
|
31
|
+
const { cdn } = res.locals;
|
32
|
+
const { app } = req;
|
33
|
+
|
34
|
+
if (!app.locals.assets) app.locals.assets = {};
|
35
|
+
const { assets } = app.locals;
|
36
|
+
|
37
|
+
// when on production, only load the file paths from the manifest once
|
38
|
+
// as long as the cdn configs are the same (allows for changing the cdn env var in prod)
|
39
|
+
if (isProduction && assets.files && assets.cdn === cdn.enabled) return next();
|
40
|
+
|
41
|
+
// get file paths from manifests
|
42
|
+
const rels = await Promise.all(types.map(async ({ type, entry }) => {
|
43
|
+
const rel = await getRelPathFromManifest({ distDir, type, entry });
|
44
|
+
return { type, rel };
|
45
|
+
}));
|
46
|
+
|
47
|
+
assets.files = rels.reduce((map, { type, rel }) => {
|
48
|
+
const href = cdn.dist(rel);
|
49
|
+
map.set(type, [href]);
|
50
|
+
return map;
|
51
|
+
}, new Map());
|
52
|
+
assets.cdn = cdn.enabled;
|
53
|
+
|
54
|
+
return next();
|
55
|
+
});
|
package/express/cdn.js
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
const { cleanPath } = require('@parameter1/base-cms-utils');
|
2
|
+
|
3
|
+
module.exports = ({ enabled = false, origin, siteVersion } = {}) => (req, res, next) => {
|
4
|
+
const { config, tenantKey } = req.app.locals;
|
5
|
+
const url = `${cleanPath(origin)}/web-assets/${tenantKey}/${config.website('id')}/v${siteVersion}`;
|
6
|
+
|
7
|
+
const key = '__cdn';
|
8
|
+
const values = new Set(['true', '1']);
|
9
|
+
let isEnabled = enabled;
|
10
|
+
if (values.has(req.query[key])) isEnabled = true;
|
11
|
+
if (values.has(req.cookies[key])) isEnabled = true;
|
12
|
+
|
13
|
+
res.locals.cdn = {
|
14
|
+
enabled: isEnabled,
|
15
|
+
origin,
|
16
|
+
url,
|
17
|
+
dist: (path) => {
|
18
|
+
const cleaned = `dist/${cleanPath(path)}`;
|
19
|
+
return isEnabled ? `${url}/${cleaned}` : `/${cleaned}`;
|
20
|
+
},
|
21
|
+
public: (path) => {
|
22
|
+
const cleaned = cleanPath(path);
|
23
|
+
return isEnabled ? `${url}/public/${cleaned}` : `/${cleaned}`;
|
24
|
+
},
|
25
|
+
};
|
26
|
+
next();
|
27
|
+
};
|
@@ -0,0 +1,117 @@
|
|
1
|
+
const path = require('path');
|
2
|
+
const { readFile } = require('fs').promises;
|
3
|
+
const { readFileSync } = require('fs');
|
4
|
+
const { asyncRoute } = require('@parameter1/base-cms-utils');
|
5
|
+
|
6
|
+
const modes = new Set(['main', 'purged', 'optimized', 'critical']);
|
7
|
+
|
8
|
+
const readManifest = async (loc) => {
|
9
|
+
try {
|
10
|
+
const contents = await readFile(loc, 'utf8');
|
11
|
+
return JSON.parse(contents);
|
12
|
+
} catch (e) {
|
13
|
+
if (e.code === 'ENOENT') return null;
|
14
|
+
throw e;
|
15
|
+
}
|
16
|
+
};
|
17
|
+
|
18
|
+
/**
|
19
|
+
* @typedef {import("@parameter1/base-cms-web-cli/build/utils/css.js")
|
20
|
+
* .WrittenCSSOutputAsset} WrittenCSSOutputAsset
|
21
|
+
*
|
22
|
+
* @param {object} params
|
23
|
+
* @param {string} params.distDir
|
24
|
+
* @returns {Promise<WrittenCSSOutputAsset[]>}
|
25
|
+
*/
|
26
|
+
const loadManifestEntries = async ({ distDir }) => {
|
27
|
+
const file = path.resolve(distDir, 'css', 'manifest.json');
|
28
|
+
const manifest = await readManifest(file);
|
29
|
+
if (!manifest) throw new Error('Unable to load the CSS asset manifest');
|
30
|
+
return Object.keys(manifest).map((key) => {
|
31
|
+
const asset = { key, ...manifest[key] };
|
32
|
+
return asset;
|
33
|
+
});
|
34
|
+
};
|
35
|
+
|
36
|
+
const isProduction = process.env.NODE_ENV === 'production';
|
37
|
+
|
38
|
+
module.exports = ({ distDir }) => asyncRoute(async (req, res, next) => {
|
39
|
+
const { cdn } = res.locals;
|
40
|
+
const { app } = req;
|
41
|
+
if (!app.locals.css) app.locals.css = {};
|
42
|
+
const { css } = app.locals;
|
43
|
+
|
44
|
+
// determine the current CSS mode
|
45
|
+
// use the env first and fallback to main (all).
|
46
|
+
let mode = process.env.CSS_MODE || 'main';
|
47
|
+
if (!modes.has(mode)) mode = 'main';
|
48
|
+
|
49
|
+
// then allow the request query or a cookie to override this.
|
50
|
+
const key = '__css';
|
51
|
+
if (modes.has(req.query[key])) {
|
52
|
+
mode = req.query[key];
|
53
|
+
} else if (modes.has(req.cookies[key])) {
|
54
|
+
mode = req.cookie[key];
|
55
|
+
}
|
56
|
+
|
57
|
+
// always set the mode to the app on every request.
|
58
|
+
css.mode = mode;
|
59
|
+
|
60
|
+
// when on production, only load the file paths and/or contents from the manifest once
|
61
|
+
// as long as the cdn configs are the same (allows for changing the cdn env var in prod)
|
62
|
+
if (isProduction && css.ready && css.cdn === cdn.enabled) return next();
|
63
|
+
|
64
|
+
css.cdn = cdn.enabled;
|
65
|
+
|
66
|
+
const items = await loadManifestEntries({ distDir });
|
67
|
+
const files = items.reduce((map, asset) => {
|
68
|
+
if (asset.embedded) return map;
|
69
|
+
map.set(asset.key, cdn.dist(`css/${asset.file}`));
|
70
|
+
return map;
|
71
|
+
}, new Map());
|
72
|
+
css.files = files;
|
73
|
+
|
74
|
+
const embeddable = items.reduce((map, asset) => {
|
75
|
+
if (!asset.embedded) return map;
|
76
|
+
map.set(asset.key, path.resolve(distDir, 'css', asset.file));
|
77
|
+
return map;
|
78
|
+
}, new Map());
|
79
|
+
css.embeddable = embeddable;
|
80
|
+
|
81
|
+
css.main = () => files.get('main');
|
82
|
+
css.purged = () => files.get('purged');
|
83
|
+
|
84
|
+
css.optimized = ({ kind, type } = {}) => {
|
85
|
+
// attempt to load the optimized file from most to least specific.
|
86
|
+
const keys = [];
|
87
|
+
if (kind && type) keys.push(`optimized-${kind}.${type}`);
|
88
|
+
if (kind) keys.push(`optimized-${kind}`);
|
89
|
+
keys.push('optimized');
|
90
|
+
|
91
|
+
return keys.reduce((file, k) => {
|
92
|
+
if (file) return file;
|
93
|
+
return files.get(k) || null;
|
94
|
+
}, null);
|
95
|
+
};
|
96
|
+
|
97
|
+
css.critical = ({ kind, type } = {}) => {
|
98
|
+
// attempt to load the critical file from most to least specific.
|
99
|
+
const keys = [];
|
100
|
+
if (kind && type) keys.push(`critical-${kind}.${type}`);
|
101
|
+
if (kind) keys.push(`critical-${kind}`);
|
102
|
+
keys.push('critical');
|
103
|
+
|
104
|
+
const critical = keys.reduce((file, k) => {
|
105
|
+
if (file) return file;
|
106
|
+
return embeddable.get(k) || null;
|
107
|
+
}, null);
|
108
|
+
if (!critical) return null;
|
109
|
+
// @todo determine if this should read contents all the time or store in memory?
|
110
|
+
const contents = readFileSync(critical, 'utf8');
|
111
|
+
return `/* ${critical.split('/').pop()} */ ${contents}`;
|
112
|
+
};
|
113
|
+
|
114
|
+
css.ready = true;
|
115
|
+
|
116
|
+
return next();
|
117
|
+
});
|
@@ -1,5 +1,6 @@
|
|
1
1
|
const { STATUS_CODES } = require('http');
|
2
2
|
const createError = require('http-errors');
|
3
|
+
const setRouteKind = require('@parameter1/base-cms-marko-express/utils/set-route-kind');
|
3
4
|
const errorTemplate = require('../components/document/components/error');
|
4
5
|
const getRedirect = require('./get-redirect');
|
5
6
|
const findContentAlias = require('./find-content-alias');
|
@@ -16,6 +17,7 @@ const noCache = (res) => {
|
|
16
17
|
};
|
17
18
|
|
18
19
|
const renderError = (res, { statusCode, err, template }) => {
|
20
|
+
setRouteKind(res, { kind: 'error', type: statusCode });
|
19
21
|
res.status(statusCode);
|
20
22
|
res.marko(template || errorTemplate, {
|
21
23
|
statusCode,
|
package/express/index.js
CHANGED
@@ -12,7 +12,9 @@ const embeddedMedia = require('./embedded-media');
|
|
12
12
|
const loadObject = require('./load-object');
|
13
13
|
const loadDocument = require('./load-document');
|
14
14
|
const oembed = require('./oembed');
|
15
|
-
const
|
15
|
+
const cdn = require('./cdn');
|
16
|
+
const assetLoader = require('./asset-loader');
|
17
|
+
const cssLoader = require('./css-loader');
|
16
18
|
const rss = require('./rss');
|
17
19
|
const sitemaps = require('./sitemaps');
|
18
20
|
const { version } = require('../package.json');
|
@@ -117,14 +119,21 @@ module.exports = (config = {}) => {
|
|
117
119
|
// Set website context.
|
118
120
|
app.use(websiteContext(app.locals.config));
|
119
121
|
|
122
|
+
// Load CDN info before dist and CSS loading (but after the website context).
|
123
|
+
app.use(cdn({
|
124
|
+
enabled: ['true', '1'].includes(process.env.USE_ASSET_CDN),
|
125
|
+
origin: process.env.ASSET_CDN_ORIGIN || 'https://cdn.parameter1.com',
|
126
|
+
siteVersion: sitePackage.version,
|
127
|
+
}));
|
128
|
+
app.use(cssLoader({ distDir }));
|
129
|
+
app.use(assetLoader({ distDir }));
|
130
|
+
|
120
131
|
// Register the Marko middleware.
|
121
132
|
app.use(markoMiddleware());
|
122
|
-
app.use(purgedCSS());
|
123
133
|
app.use(cleanMarkoResponse());
|
124
134
|
|
125
135
|
// Serve static assets
|
126
136
|
app.use('/dist/css', express.static(`${distDir}/css`, { maxAge: '2y', immutable: true }));
|
127
|
-
app.use('/dist/js/lazysizes', express.static(path.resolve(__dirname, '../public/lazysizes'), { maxAge: '2y', immutable: true }));
|
128
137
|
app.use('/dist/js', express.static(`${distDir}/js`, { maxAge: '2y', immutable: true }));
|
129
138
|
app.use('/dist', express.static(distDir));
|
130
139
|
|
@@ -2,6 +2,7 @@ const { get } = require('@parameter1/base-cms-object-path');
|
|
2
2
|
const { asyncRoute, isFunction: isFn } = require('@parameter1/base-cms-utils');
|
3
3
|
const { content: loader } = require('@parameter1/base-cms-web-common/page-loaders');
|
4
4
|
const { blockContent: queryFactory } = require('@parameter1/base-cms-web-common/query-factories');
|
5
|
+
const setRouteKind = require('@parameter1/base-cms-marko-express/utils/set-route-kind');
|
5
6
|
const PageNode = require('./page-node');
|
6
7
|
const buildContentInput = require('../utils/build-content-input');
|
7
8
|
const applyQueryParams = require('../utils/apply-query-params');
|
@@ -22,6 +23,9 @@ module.exports = ({
|
|
22
23
|
|
23
24
|
const additionalInput = buildContentInput({ req });
|
24
25
|
const content = await loader(apollo, { id, additionalInput, queryFragment: loaderQueryFragment });
|
26
|
+
|
27
|
+
// set the route kind
|
28
|
+
setRouteKind(res, { kind: 'content', type: content.type });
|
25
29
|
const redirectTo = isFn(redirectToFn) ? redirectToFn({ content }) : content.redirectTo;
|
26
30
|
const path = isFn(pathFn) ? pathFn({ content }) : get(content, 'siteContext.path');
|
27
31
|
|
@@ -2,6 +2,7 @@ const { get } = require('@parameter1/base-cms-object-path');
|
|
2
2
|
const { asyncRoute, isFunction: isFn } = require('@parameter1/base-cms-utils');
|
3
3
|
const { dynamicPage: loader } = require('@parameter1/base-cms-web-common/page-loaders');
|
4
4
|
const { blockDynamicPage: queryFactory } = require('@parameter1/base-cms-web-common/query-factories');
|
5
|
+
const setRouteKind = require('@parameter1/base-cms-marko-express/utils/set-route-kind');
|
5
6
|
const PageNode = require('./page-node');
|
6
7
|
const applyQueryParams = require('../utils/apply-query-params');
|
7
8
|
|
@@ -15,6 +16,9 @@ module.exports = ({
|
|
15
16
|
const { apollo, query } = req;
|
16
17
|
|
17
18
|
const page = await loader(apollo, { alias });
|
19
|
+
|
20
|
+
setRouteKind(res, { kind: 'dynamic-page', type: alias });
|
21
|
+
|
18
22
|
const { redirectTo } = page;
|
19
23
|
const path = get(page, 'siteContext.path');
|
20
24
|
if (redirectTo) {
|
@@ -1,6 +1,7 @@
|
|
1
1
|
const { asyncRoute } = require('@parameter1/base-cms-utils');
|
2
2
|
const { magazineIssue: loader } = require('@parameter1/base-cms-web-common/page-loaders');
|
3
3
|
const { blockMagazineIssue: queryFactory } = require('@parameter1/base-cms-web-common/query-factories');
|
4
|
+
const setRouteKind = require('@parameter1/base-cms-marko-express/utils/set-route-kind');
|
4
5
|
const PageNode = require('./page-node');
|
5
6
|
|
6
7
|
module.exports = ({
|
@@ -10,6 +11,9 @@ module.exports = ({
|
|
10
11
|
const { apollo } = req;
|
11
12
|
const id = Number(req.params.id);
|
12
13
|
const issue = await loader(apollo, { id });
|
14
|
+
|
15
|
+
// set the route kind
|
16
|
+
setRouteKind(res, { kind: 'magazine-issue', type: '' });
|
13
17
|
const pageNode = new PageNode(apollo, {
|
14
18
|
queryFactory,
|
15
19
|
queryFragment,
|
@@ -1,6 +1,7 @@
|
|
1
1
|
const { asyncRoute } = require('@parameter1/base-cms-utils');
|
2
2
|
const { magazinePublication: loader } = require('@parameter1/base-cms-web-common/page-loaders');
|
3
3
|
const { blockMagazinePublication: queryFactory } = require('@parameter1/base-cms-web-common/query-factories');
|
4
|
+
const setRouteKind = require('@parameter1/base-cms-marko-express/utils/set-route-kind');
|
4
5
|
const PageNode = require('./page-node');
|
5
6
|
|
6
7
|
module.exports = ({
|
@@ -10,6 +11,9 @@ module.exports = ({
|
|
10
11
|
const { apollo } = req;
|
11
12
|
const { id } = req.params;
|
12
13
|
const publication = await loader(apollo, { id });
|
14
|
+
|
15
|
+
// set the route kind
|
16
|
+
setRouteKind(res, { kind: 'magazine-publication', type: '' });
|
13
17
|
const pageNode = new PageNode(apollo, {
|
14
18
|
queryFactory,
|
15
19
|
queryFragment,
|
@@ -1,6 +1,7 @@
|
|
1
1
|
const { asyncRoute, isFunction: isFn } = require('@parameter1/base-cms-utils');
|
2
2
|
const { websiteSection: loader } = require('@parameter1/base-cms-web-common/page-loaders');
|
3
3
|
const { blockWebsiteSection: queryFactory } = require('@parameter1/base-cms-web-common/query-factories');
|
4
|
+
const setRouteKind = require('@parameter1/base-cms-marko-express/utils/set-route-kind');
|
4
5
|
const PageNode = require('./page-node');
|
5
6
|
const applyQueryParams = require('../utils/apply-query-params');
|
6
7
|
|
@@ -16,6 +17,9 @@ module.exports = ({
|
|
16
17
|
const cleanedAlias = alias.replace(/\/+$/, '').replace(/^\/+/, '');
|
17
18
|
|
18
19
|
const section = await loader(apollo, { alias: cleanedAlias });
|
20
|
+
|
21
|
+
// set the route kind
|
22
|
+
setRouteKind(res, { kind: 'website-section', type: section.alias });
|
19
23
|
const { redirectTo, canonicalPath } = section;
|
20
24
|
if (redirectTo) {
|
21
25
|
return res.redirect(301, applyQueryParams({ path: redirectTo, query }));
|
package/package.json
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
{
|
2
2
|
"name": "@parameter1/base-cms-marko-web",
|
3
|
-
"version": "4.
|
3
|
+
"version": "4.9.0",
|
4
4
|
"description": "Core Marko+Express components for BaseCMS websites",
|
5
5
|
"author": "Jacob Bare <jacob@parameter1.com>",
|
6
6
|
"main": "index.js",
|
@@ -31,7 +31,7 @@
|
|
31
31
|
"@parameter1/base-cms-html": "^4.5.12",
|
32
32
|
"@parameter1/base-cms-image": "^4.6.0",
|
33
33
|
"@parameter1/base-cms-inflector": "^4.5.12",
|
34
|
-
"@parameter1/base-cms-marko-express": "^4.
|
34
|
+
"@parameter1/base-cms-marko-express": "^4.9.0",
|
35
35
|
"@parameter1/base-cms-marko-node-require": "^4.5.12",
|
36
36
|
"@parameter1/base-cms-marko-web-deferred-script-loader": "^4.5.12",
|
37
37
|
"@parameter1/base-cms-object-path": "^4.5.12",
|
@@ -60,5 +60,5 @@
|
|
60
60
|
"publishConfig": {
|
61
61
|
"access": "public"
|
62
62
|
},
|
63
|
-
"gitHead": "
|
63
|
+
"gitHead": "4e879581f5dea1692abd1b2942c1be27c1910bf4"
|
64
64
|
}
|
package/config/dist-loader.js
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
const path = require('path');
|
2
|
-
const { readFileSync } = require('fs');
|
3
|
-
|
4
|
-
const read = (file) => {
|
5
|
-
try {
|
6
|
-
return JSON.parse(readFileSync(file, 'utf8'));
|
7
|
-
} catch (e) {
|
8
|
-
if (e.code === 'ENOENT') return null;
|
9
|
-
throw e;
|
10
|
-
}
|
11
|
-
};
|
12
|
-
|
13
|
-
const loadFromManifest = ({ distDir, type, entry }) => {
|
14
|
-
const file = path.resolve(distDir, type, 'manifest.json');
|
15
|
-
const manifest = read(file);
|
16
|
-
if (!manifest) throw new Error(`Unable to load the asset manifest for type ${type}`);
|
17
|
-
const asset = manifest[entry];
|
18
|
-
if (!asset) throw new Error(`Unable to extract an asset for type ${type} using manifest entry ${entry}`);
|
19
|
-
return `/dist/${type}/${asset.file}`;
|
20
|
-
};
|
21
|
-
|
22
|
-
const load = ({ distDir, file }) => readFileSync(path.resolve(distDir, `.${file.replace('/dist/', '/')}`), 'utf8');
|
23
|
-
|
24
|
-
module.exports = ({ distDir, type, entry }) => {
|
25
|
-
let file;
|
26
|
-
let contents;
|
27
|
-
return ({ embedded } = {}) => {
|
28
|
-
const isDevelopment = process.env.NODE_ENV !== 'production';
|
29
|
-
// when on dev, always return the file from the manifest
|
30
|
-
// as it may have changed during build.
|
31
|
-
if (isDevelopment) {
|
32
|
-
const f = loadFromManifest({ distDir, type, entry });
|
33
|
-
if (!embedded) return f;
|
34
|
-
return load({ distDir, file: f });
|
35
|
-
}
|
36
|
-
// otherwise, only retrieve it once
|
37
|
-
if (!file) file = loadFromManifest({ distDir, type, entry });
|
38
|
-
if (!embedded) return file;
|
39
|
-
if (!contents) contents = load({ distDir, file });
|
40
|
-
return contents;
|
41
|
-
};
|
42
|
-
};
|
package/express/purged-css.js
DELETED
@@ -1,11 +0,0 @@
|
|
1
|
-
module.exports = () => (req, res, next) => {
|
2
|
-
res.locals.usePurgedCSS = ['cookies', 'query'].some((key) => {
|
3
|
-
const { __purgecss: purge } = req[key];
|
4
|
-
return purge && !['false', '0', 'null'].includes(purge);
|
5
|
-
});
|
6
|
-
res.locals.embedCSS = ['cookies', 'query'].some((key) => {
|
7
|
-
const { __embedcss: embed } = req[key];
|
8
|
-
return embed && !['false', '0', 'null'].includes(embed);
|
9
|
-
});
|
10
|
-
next();
|
11
|
-
};
|
@@ -1,2 +0,0 @@
|
|
1
|
-
/*! lazysizes - v5.3.2 */
|
2
|
-
!function(e){var t=function(u,D,f){"use strict";var k,H;if(function(){var e;var t={lazyClass:"lazyload",loadedClass:"lazyloaded",loadingClass:"lazyloading",preloadClass:"lazypreload",errorClass:"lazyerror",autosizesClass:"lazyautosizes",fastLoadedClass:"ls-is-cached",iframeLoadMode:0,srcAttr:"data-src",srcsetAttr:"data-srcset",sizesAttr:"data-sizes",minSize:40,customMedia:{},init:true,expFactor:1.5,hFac:.8,loadMode:2,loadHidden:true,ricTimeout:0,throttleDelay:125};H=u.lazySizesConfig||u.lazysizesConfig||{};for(e in t){if(!(e in H)){H[e]=t[e]}}}(),!D||!D.getElementsByClassName){return{init:function(){},cfg:H,noSupport:true}}var O=D.documentElement,i=u.HTMLPictureElement,P="addEventListener",$="getAttribute",q=u[P].bind(u),I=u.setTimeout,U=u.requestAnimationFrame||I,o=u.requestIdleCallback,j=/^picture$/i,r=["load","error","lazyincluded","_lazyloaded"],a={},G=Array.prototype.forEach,J=function(e,t){if(!a[t]){a[t]=new RegExp("(\\s|^)"+t+"(\\s|$)")}return a[t].test(e[$]("class")||"")&&a[t]},K=function(e,t){if(!J(e,t)){e.setAttribute("class",(e[$]("class")||"").trim()+" "+t)}},Q=function(e,t){var a;if(a=J(e,t)){e.setAttribute("class",(e[$]("class")||"").replace(a," "))}},V=function(t,a,e){var i=e?P:"removeEventListener";if(e){V(t,a)}r.forEach(function(e){t[i](e,a)})},X=function(e,t,a,i,r){var n=D.createEvent("Event");if(!a){a={}}a.instance=k;n.initEvent(t,!i,!r);n.detail=a;e.dispatchEvent(n);return n},Y=function(e,t){var a;if(!i&&(a=u.picturefill||H.pf)){if(t&&t.src&&!e[$]("srcset")){e.setAttribute("srcset",t.src)}a({reevaluate:true,elements:[e]})}else if(t&&t.src){e.src=t.src}},Z=function(e,t){return(getComputedStyle(e,null)||{})[t]},s=function(e,t,a){a=a||e.offsetWidth;while(a<H.minSize&&t&&!e._lazysizesWidth){a=t.offsetWidth;t=t.parentNode}return a},ee=function(){var a,i;var t=[];var r=[];var n=t;var s=function(){var e=n;n=t.length?r:t;a=true;i=false;while(e.length){e.shift()()}a=false};var e=function(e,t){if(a&&!t){e.apply(this,arguments)}else{n.push(e);if(!i){i=true;(D.hidden?I:U)(s)}}};e._lsFlush=s;return e}(),te=function(a,e){return e?function(){ee(a)}:function(){var e=this;var t=arguments;ee(function(){a.apply(e,t)})}},ae=function(e){var a;var i=0;var r=H.throttleDelay;var n=H.ricTimeout;var t=function(){a=false;i=f.now();e()};var s=o&&n>49?function(){o(t,{timeout:n});if(n!==H.ricTimeout){n=H.ricTimeout}}:te(function(){I(t)},true);return function(e){var t;if(e=e===true){n=33}if(a){return}a=true;t=r-(f.now()-i);if(t<0){t=0}if(e||t<9){s()}else{I(s,t)}}},ie=function(e){var t,a;var i=99;var r=function(){t=null;e()};var n=function(){var e=f.now()-a;if(e<i){I(n,i-e)}else{(o||r)(r)}};return function(){a=f.now();if(!t){t=I(n,i)}}},e=function(){var v,m,c,h,e;var y,z,g,p,C,b,A;var n=/^img$/i;var d=/^iframe$/i;var E="onscroll"in u&&!/(gle|ing)bot/.test(navigator.userAgent);var _=0;var w=0;var M=0;var N=-1;var L=function(e){M--;if(!e||M<0||!e.target){M=0}};var x=function(e){if(A==null){A=Z(D.body,"visibility")=="hidden"}return A||!(Z(e.parentNode,"visibility")=="hidden"&&Z(e,"visibility")=="hidden")};var W=function(e,t){var a;var i=e;var r=x(e);g-=t;b+=t;p-=t;C+=t;while(r&&(i=i.offsetParent)&&i!=D.body&&i!=O){r=(Z(i,"opacity")||1)>0;if(r&&Z(i,"overflow")!="visible"){a=i.getBoundingClientRect();r=C>a.left&&p<a.right&&b>a.top-1&&g<a.bottom+1}}return r};var t=function(){var e,t,a,i,r,n,s,o,l,u,f,c;var d=k.elements;if((h=H.loadMode)&&M<8&&(e=d.length)){t=0;N++;for(;t<e;t++){if(!d[t]||d[t]._lazyRace){continue}if(!E||k.prematureUnveil&&k.prematureUnveil(d[t])){R(d[t]);continue}if(!(o=d[t][$]("data-expand"))||!(n=o*1)){n=w}if(!u){u=!H.expand||H.expand<1?O.clientHeight>500&&O.clientWidth>500?500:370:H.expand;k._defEx=u;f=u*H.expFactor;c=H.hFac;A=null;if(w<f&&M<1&&N>2&&h>2&&!D.hidden){w=f;N=0}else if(h>1&&N>1&&M<6){w=u}else{w=_}}if(l!==n){y=innerWidth+n*c;z=innerHeight+n;s=n*-1;l=n}a=d[t].getBoundingClientRect();if((b=a.bottom)>=s&&(g=a.top)<=z&&(C=a.right)>=s*c&&(p=a.left)<=y&&(b||C||p||g)&&(H.loadHidden||x(d[t]))&&(m&&M<3&&!o&&(h<3||N<4)||W(d[t],n))){R(d[t]);r=true;if(M>9){break}}else if(!r&&m&&!i&&M<4&&N<4&&h>2&&(v[0]||H.preloadAfterLoad)&&(v[0]||!o&&(b||C||p||g||d[t][$](H.sizesAttr)!="auto"))){i=v[0]||d[t]}}if(i&&!r){R(i)}}};var a=ae(t);var S=function(e){var t=e.target;if(t._lazyCache){delete t._lazyCache;return}L(e);K(t,H.loadedClass);Q(t,H.loadingClass);V(t,B);X(t,"lazyloaded")};var i=te(S);var B=function(e){i({target:e.target})};var T=function(e,t){var a=e.getAttribute("data-load-mode")||H.iframeLoadMode;if(a==0){e.contentWindow.location.replace(t)}else if(a==1){e.src=t}};var F=function(e){var t;var a=e[$](H.srcsetAttr);if(t=H.customMedia[e[$]("data-media")||e[$]("media")]){e.setAttribute("media",t)}if(a){e.setAttribute("srcset",a)}};var s=te(function(t,e,a,i,r){var n,s,o,l,u,f;if(!(u=X(t,"lazybeforeunveil",e)).defaultPrevented){if(i){if(a){K(t,H.autosizesClass)}else{t.setAttribute("sizes",i)}}s=t[$](H.srcsetAttr);n=t[$](H.srcAttr);if(r){o=t.parentNode;l=o&&j.test(o.nodeName||"")}f=e.firesLoad||"src"in t&&(s||n||l);u={target:t};K(t,H.loadingClass);if(f){clearTimeout(c);c=I(L,2500);V(t,B,true)}if(l){G.call(o.getElementsByTagName("source"),F)}if(s){t.setAttribute("srcset",s)}else if(n&&!l){if(d.test(t.nodeName)){T(t,n)}else{t.src=n}}if(r&&(s||l)){Y(t,{src:n})}}if(t._lazyRace){delete t._lazyRace}Q(t,H.lazyClass);ee(function(){var e=t.complete&&t.naturalWidth>1;if(!f||e){if(e){K(t,H.fastLoadedClass)}S(u);t._lazyCache=true;I(function(){if("_lazyCache"in t){delete t._lazyCache}},9)}if(t.loading=="lazy"){M--}},true)});var R=function(e){if(e._lazyRace){return}var t;var a=n.test(e.nodeName);var i=a&&(e[$](H.sizesAttr)||e[$]("sizes"));var r=i=="auto";if((r||!m)&&a&&(e[$]("src")||e.srcset)&&!e.complete&&!J(e,H.errorClass)&&J(e,H.lazyClass)){return}t=X(e,"lazyunveilread").detail;if(r){re.updateElem(e,true,e.offsetWidth)}e._lazyRace=true;M++;s(e,t,r,i,a)};var r=ie(function(){H.loadMode=3;a()});var o=function(){if(H.loadMode==3){H.loadMode=2}r()};var l=function(){if(m){return}if(f.now()-e<999){I(l,999);return}m=true;H.loadMode=3;a();q("scroll",o,true)};return{_:function(){e=f.now();k.elements=D.getElementsByClassName(H.lazyClass);v=D.getElementsByClassName(H.lazyClass+" "+H.preloadClass);q("scroll",a,true);q("resize",a,true);q("pageshow",function(e){if(e.persisted){var t=D.querySelectorAll("."+H.loadingClass);if(t.length&&t.forEach){U(function(){t.forEach(function(e){if(e.complete){R(e)}})})}}});if(u.MutationObserver){new MutationObserver(a).observe(O,{childList:true,subtree:true,attributes:true})}else{O[P]("DOMNodeInserted",a,true);O[P]("DOMAttrModified",a,true);setInterval(a,999)}q("hashchange",a,true);["focus","mouseover","click","load","transitionend","animationend"].forEach(function(e){D[P](e,a,true)});if(/d$|^c/.test(D.readyState)){l()}else{q("load",l);D[P]("DOMContentLoaded",a);I(l,2e4)}if(k.elements.length){t();ee._lsFlush()}else{a()}},checkElems:a,unveil:R,_aLSL:o}}(),re=function(){var a;var n=te(function(e,t,a,i){var r,n,s;e._lazysizesWidth=i;i+="px";e.setAttribute("sizes",i);if(j.test(t.nodeName||"")){r=t.getElementsByTagName("source");for(n=0,s=r.length;n<s;n++){r[n].setAttribute("sizes",i)}}if(!a.detail.dataAttr){Y(e,a.detail)}});var i=function(e,t,a){var i;var r=e.parentNode;if(r){a=s(e,r,a);i=X(e,"lazybeforesizes",{width:a,dataAttr:!!t});if(!i.defaultPrevented){a=i.detail.width;if(a&&a!==e._lazysizesWidth){n(e,r,i,a)}}}};var e=function(){var e;var t=a.length;if(t){e=0;for(;e<t;e++){i(a[e])}}};var t=ie(e);return{_:function(){a=D.getElementsByClassName(H.autosizesClass);q("resize",t)},checkElems:t,updateElem:i}}(),t=function(){if(!t.i&&D.getElementsByClassName){t.i=true;re._();e._()}};return I(function(){H.init&&t()}),k={cfg:H,autoSizer:re,loader:e,init:t,uP:Y,aC:K,rC:Q,hC:J,fire:X,gW:s,rAF:ee}}(e,e.document,Date);e.lazySizes=t,"object"==typeof module&&module.exports&&(module.exports=t)}("undefined"!=typeof window?window:{});
|