@parameter1/base-cms-marko-web 4.8.0 → 4.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. package/components/browser-component.marko.js +2 -2
  2. package/components/document/components/body-wrapper.marko.js +2 -2
  3. package/components/document/components/error.marko.js +2 -2
  4. package/components/document/components/live-reload.marko.js +2 -2
  5. package/components/document/components/polyfill.marko.js +2 -2
  6. package/components/document/components/styles.marko +23 -0
  7. package/components/document/components/styles.marko.js +57 -0
  8. package/components/document/container.marko.js +2 -2
  9. package/components/document/index.marko +8 -19
  10. package/components/document/index.marko.js +15 -38
  11. package/components/element/array.marko.js +2 -2
  12. package/components/element/audio.marko.js +2 -2
  13. package/components/element/block.marko.js +2 -2
  14. package/components/element/clear.marko.js +2 -2
  15. package/components/element/components/image.marko.js +2 -2
  16. package/components/element/components/text.marko.js +2 -2
  17. package/components/element/content/address1.marko.js +2 -2
  18. package/components/element/content/address2.marko.js +2 -2
  19. package/components/element/content/audio.marko.js +2 -2
  20. package/components/element/content/authors.marko.js +2 -2
  21. package/components/element/content/body.marko +4 -2
  22. package/components/element/content/body.marko.js +8 -4
  23. package/components/element/content/byline.marko.js +2 -2
  24. package/components/element/content/city-state-zip.marko.js +2 -2
  25. package/components/element/content/contributors.marko.js +2 -2
  26. package/components/element/content/country.marko.js +2 -2
  27. package/components/element/content/embed-code.marko.js +2 -2
  28. package/components/element/content/end-date.marko.js +2 -2
  29. package/components/element/content/ends.marko.js +2 -2
  30. package/components/element/content/fax.marko.js +2 -2
  31. package/components/element/content/images.marko.js +2 -2
  32. package/components/element/content/mobile.marko.js +2 -2
  33. package/components/element/content/name.marko.js +2 -2
  34. package/components/element/content/phone.marko.js +2 -2
  35. package/components/element/content/photographers.marko.js +2 -2
  36. package/components/element/content/public-email.marko.js +2 -2
  37. package/components/element/content/published.marko.js +2 -2
  38. package/components/element/content/short-name.marko.js +2 -2
  39. package/components/element/content/sidebar-stubs.marko.js +2 -2
  40. package/components/element/content/sidebars.marko.js +2 -2
  41. package/components/element/content/source.marko.js +2 -2
  42. package/components/element/content/sponsors.marko.js +2 -2
  43. package/components/element/content/start-date.marko.js +2 -2
  44. package/components/element/content/starts.marko.js +2 -2
  45. package/components/element/content/teaser.marko.js +2 -2
  46. package/components/element/content/title.marko.js +2 -2
  47. package/components/element/content/tollfree.marko.js +2 -2
  48. package/components/element/content/transcript.marko.js +2 -2
  49. package/components/element/content/website.marko.js +2 -2
  50. package/components/element/date.marko.js +2 -2
  51. package/components/element/image/caption.marko.js +2 -2
  52. package/components/element/image/credit.marko.js +2 -2
  53. package/components/element/image/display-name.marko.js +2 -2
  54. package/components/element/image/slider.marko.js +2 -2
  55. package/components/element/img.marko.js +2 -2
  56. package/components/element/index.marko.js +2 -2
  57. package/components/element/link.marko.js +2 -2
  58. package/components/element/magazine-issue/description.marko.js +2 -2
  59. package/components/element/magazine-issue/digital-edition-url.marko.js +2 -2
  60. package/components/element/magazine-issue/name.marko.js +2 -2
  61. package/components/element/magazine-issue/pdf-url.marko.js +2 -2
  62. package/components/element/magazine-publication/cancel-url.marko.js +2 -2
  63. package/components/element/magazine-publication/change-address-url.marko.js +2 -2
  64. package/components/element/magazine-publication/description.marko.js +2 -2
  65. package/components/element/magazine-publication/einquiry-url.marko.js +2 -2
  66. package/components/element/magazine-publication/name.marko.js +2 -2
  67. package/components/element/magazine-publication/renewal-url.marko.js +2 -2
  68. package/components/element/magazine-publication/reprints-url.marko.js +2 -2
  69. package/components/element/magazine-publication/subscribe-url.marko.js +2 -2
  70. package/components/element/obj-array.marko.js +2 -2
  71. package/components/element/obj-audio.marko.js +2 -2
  72. package/components/element/obj-date.marko.js +2 -2
  73. package/components/element/obj-nodes.marko.js +2 -2
  74. package/components/element/obj-text.marko.js +2 -2
  75. package/components/element/obj.marko.js +2 -2
  76. package/components/element/picture.marko.js +2 -2
  77. package/components/element/text.marko.js +2 -2
  78. package/components/element/website-section/description.marko.js +2 -2
  79. package/components/element/website-section/hierarchy.marko.js +2 -2
  80. package/components/element/website-section/name.marko.js +2 -2
  81. package/components/font/google.marko.js +2 -2
  82. package/components/font/link.marko.js +2 -2
  83. package/components/font/typekit.marko.js +2 -2
  84. package/components/load-more/index.marko.js +2 -2
  85. package/components/load-more/trigger.marko.js +2 -2
  86. package/components/node/body.marko.js +2 -2
  87. package/components/node/element.marko.js +2 -2
  88. package/components/node/footer.marko.js +2 -2
  89. package/components/node/header.marko.js +2 -2
  90. package/components/node/image-inner-wrapper.marko.js +2 -2
  91. package/components/node/image-wrapper.marko.js +2 -2
  92. package/components/node/image.marko.js +2 -2
  93. package/components/node/index.marko.js +2 -2
  94. package/components/node-list/body.marko.js +2 -2
  95. package/components/node-list/element.marko.js +2 -2
  96. package/components/node-list/footer.marko.js +2 -2
  97. package/components/node-list/header.marko.js +2 -2
  98. package/components/node-list/index.marko.js +2 -2
  99. package/components/node-list/node.marko.js +2 -2
  100. package/components/node-list/nodes.marko.js +2 -2
  101. package/components/page/container.marko.js +2 -2
  102. package/components/page/description.marko.js +2 -2
  103. package/components/page/image.marko.js +2 -2
  104. package/components/page/layouts/content.marko.js +2 -2
  105. package/components/page/layouts/default.marko.js +2 -2
  106. package/components/page/layouts/dynamic-page.marko.js +2 -2
  107. package/components/page/layouts/magazine-issue.marko.js +2 -2
  108. package/components/page/layouts/magazine-publication.marko.js +2 -2
  109. package/components/page/layouts/website-section.marko.js +2 -2
  110. package/components/page/metadata/components/common.marko.js +2 -2
  111. package/components/page/metadata/content.marko.js +2 -2
  112. package/components/page/metadata/default.marko.js +2 -2
  113. package/components/page/metadata/dynamic-page.marko.js +2 -2
  114. package/components/page/metadata/magazine-issue.marko.js +2 -2
  115. package/components/page/metadata/magazine-publication.marko.js +2 -2
  116. package/components/page/metadata/website-section.marko.js +2 -2
  117. package/components/page/rel-canonical.marko.js +2 -2
  118. package/components/page/title.marko.js +2 -2
  119. package/components/page/wrapper.marko.js +2 -2
  120. package/components/resolve/page.marko.js +2 -2
  121. package/components/rss/website-section.marko.js +2 -2
  122. package/config/core.js +0 -41
  123. package/eslint.log +3 -0
  124. package/express/asset-loader.js +55 -0
  125. package/express/cdn.js +27 -0
  126. package/express/css-loader.js +117 -0
  127. package/express/embedded-media.js +4 -3
  128. package/express/error-handlers.js +2 -0
  129. package/express/index.js +12 -3
  130. package/middleware/with-content.js +4 -0
  131. package/middleware/with-dynamic-page.js +4 -0
  132. package/middleware/with-magazine-issue.js +4 -0
  133. package/middleware/with-magazine-publication.js +4 -0
  134. package/middleware/with-website-section.js +4 -0
  135. package/package.json +3 -3
  136. package/scss/fonts/alata-fallback.scss +7 -0
  137. package/scss/fonts/arimo-fallback.scss +7 -0
  138. package/scss/fonts/fira-sans-fallback.scss +1 -0
  139. package/scss/fonts/ibm-plex-sans-fallback.scss +7 -0
  140. package/scss/fonts/informapro-fallback.scss +6 -0
  141. package/scss/fonts/lato-fallback.scss +7 -0
  142. package/scss/fonts/montserrat-fallback.scss +1 -0
  143. package/scss/fonts/open-sans-condensed-fallback.scss +2 -2
  144. package/scss/fonts/open-sans-fallback.scss +1 -0
  145. package/scss/fonts/oswold-fallback.scss +1 -0
  146. package/scss/fonts/roboto-condensed-fallback.scss +7 -0
  147. package/scss/fonts/roboto-fallback.scss +7 -0
  148. package/scss/fonts/roboto-slab-fallback.scss +7 -0
  149. package/scss/fonts/solitaire-mvb-pro-fallback.scss +6 -0
  150. package/scss/fonts/source-sans-4-fallback.scss +1 -0
  151. package/scss/fonts/source-serif-pro-fallback.scss +7 -0
  152. package/scss/fonts/synthese-fallback.scss +6 -0
  153. package/base-cms-marko-web-0.7.4.tgz +0 -0
  154. package/base-cms-marko-web-0.9.37.tgz +0 -0
  155. package/base-cms-marko-web-0.9.55.tgz +0 -0
  156. package/config/dist-loader.js +0 -42
  157. package/express/purged-css.js +0 -11
  158. package/public/lazysizes/v5.3.2.js +0 -2
package/eslint.log ADDED
@@ -0,0 +1,3 @@
1
+ yarn run v1.22.10
2
+ $ eslint --ext .js --ext .vue --max-warnings 5 ./
3
+ Done in 3.75s.
@@ -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
+ });
@@ -11,13 +11,14 @@ module.exports = (app, { image, oembed, invalid } = {}) => {
11
11
  };
12
12
 
13
13
  // eslint-disable-next-line no-param-reassign
14
- app.locals.parseEmbeddedMedia = (body, res, options) => {
14
+ app.locals.parseEmbeddedMedia = (body, res, options, lazyloadFirstImage = true) => {
15
15
  const $global = buildMarkoGlobal(res);
16
16
 
17
- const replacements = extractEmbeddedTags(body).map((tag) => {
17
+ const replacements = extractEmbeddedTags(body).map((tag, index) => {
18
18
  const type = ['image', 'oembed'].includes(tag.type) && tag.isValid() ? tag.type : 'invalid';
19
19
  const pattern = tag.getRegExp();
20
- const replacement = handlers[type](tag, $global, options);
20
+ const replacementOptions = (index === 0 && type === 'image' && !lazyloadFirstImage) ? { ...options, lazyloadImages: false } : options;
21
+ const replacement = handlers[type](tag, $global, replacementOptions);
21
22
  return { pattern, replacement };
22
23
  });
23
24
 
@@ -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 purgedCSS = require('./purged-css');
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.8.0",
3
+ "version": "4.10.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.6.0",
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": "dcef09f69fd79065c563e850f19bf3c3826b4802"
63
+ "gitHead": "9aa14f8e69134504ed3b30fda0a6cf1b926da9d9"
64
64
  }
@@ -0,0 +1,7 @@
1
+ @font-face {
2
+ /*! critical */
3
+ font-family: alata-fallback;
4
+ size-adjust: 102.30000000000004%;
5
+ ascent-override: 110%;
6
+ src: local("Arial");
7
+ }
@@ -0,0 +1,7 @@
1
+ @font-face {
2
+ /*! critical */
3
+ font-family: arimo-fallback;
4
+ size-adjust: 100%;
5
+ ascent-override: 90%;
6
+ src: local("Arial");
7
+ }
@@ -1,4 +1,5 @@
1
1
  @font-face {
2
+ /*! critical */
2
3
  font-family: fira-sans-fallback;
3
4
  size-adjust: 102.56%;
4
5
  ascent-override: 92%;
@@ -0,0 +1,7 @@
1
+ @font-face {
2
+ /*! critical */
3
+ font-family: ibm-plex-sans-fallback;
4
+ size-adjust: 101.44000000000005%;
5
+ ascent-override: 106%;
6
+ src: local("Arial");
7
+ }
@@ -0,0 +1,6 @@
1
+ @font-face {
2
+ /*! critical */
3
+ font-family: informapro-fallback;
4
+ size-adjust: 96.59999999999997%;
5
+ src: local("Arial");
6
+ }
@@ -0,0 +1,7 @@
1
+ @font-face {
2
+ /*! critical */
3
+ font-family: lato-fallback;
4
+ size-adjust: 97.38%;
5
+ ascent-override: 101%;
6
+ src: local("Arial");
7
+ }
@@ -1,4 +1,5 @@
1
1
  @font-face {
2
+ /*! critical */
2
3
  font-family: montserrat-fallback;
3
4
  size-adjust: 113.39999999999998%;
4
5
  ascent-override: 82%;
@@ -1,6 +1,6 @@
1
1
  @font-face {
2
+ /*! critical */
2
3
  font-family: open-sans-condensed-fallback;
3
- size-adjust: 102.56%;
4
- ascent-override: 92%;
4
+ size-adjust: 89.60000000000002%;
5
5
  src: local("Arial");
6
6
  }
@@ -1,4 +1,5 @@
1
1
  @font-face {
2
+ /*! critical */
2
3
  font-family: open-sans-fallback;
3
4
  size-adjust: 105.42999999999994%;
4
5
  ascent-override: 105%;
@@ -1,4 +1,5 @@
1
1
  @font-face {
2
+ /*! critical */
2
3
  font-family: oswald-fallback;
3
4
  size-adjust: 81.91000000000001%;
4
5
  ascent-override: 154%;
@@ -0,0 +1,7 @@
1
+ @font-face {
2
+ /*! critical */
3
+ font-family: roboto-condensed-fallback;
4
+ size-adjust: 88.91000000000001%;
5
+ ascent-override: 110%;
6
+ src: local("Arial");
7
+ }
@@ -0,0 +1,7 @@
1
+ @font-face {
2
+ /*! critical */
3
+ font-family: roboto-fallback;
4
+ size-adjust: 100.06%;
5
+ ascent-override: 95%;
6
+ src: local("Arial");
7
+ }
@@ -0,0 +1,7 @@
1
+ @font-face {
2
+ /*! critical */
3
+ font-family: roboto-slab-fallback;
4
+ size-adjust: 117.79999999999995%;
5
+ ascent-override: 87%;
6
+ src: local("Times New Roman");
7
+ }
@@ -0,0 +1,6 @@
1
+ @font-face {
2
+ /*! critical */
3
+ font-family: "solitaire-mvb-pro-fallback";
4
+ size-adjust: 94.70000000000002%;
5
+ src: local("Arial");
6
+ }
@@ -1,4 +1,5 @@
1
1
  @font-face {
2
+ /*! critical */
2
3
  font-family: source-sans-4-fallback;
3
4
  size-adjust: 93.75%;
4
5
  ascent-override: 110%;
@@ -0,0 +1,7 @@
1
+ @font-face {
2
+ /*! critical */
3
+ font-family: source-serif-pro-fallback;
4
+ size-adjust: 110.86999999999993%;
5
+ ascent-override: 84%;
6
+ src: local("Times New Roman");
7
+ }
@@ -0,0 +1,6 @@
1
+ @font-face {
2
+ /*! critical */
3
+ font-family: synthese-fallback; /* stylelint-disable-line property-no-unknown */
4
+ size-adjust: 112%; /* stylelint-disable-line property-no-unknown */
5
+ src: local("Arial");
6
+ }
Binary file
Binary file
Binary file
@@ -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
- };
@@ -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:{});