diff --git a/packages/marko-core/components/resolve.marko b/packages/marko-core/components/resolve.marko index 56e4d9d24..32d5a33bd 100644 --- a/packages/marko-core/components/resolve.marko +++ b/packages/marko-core/components/resolve.marko @@ -13,15 +13,18 @@ $ const { isArray } = Array; <${input.onError} err=err /> -
An unexpected error occurred: ${err.message}
+
+        An unexpected error occurred: ${err.message}
+      
${err.stack}
- $ console.error(err); $ const { errors } = err.networkError.result; -
${JSON.stringify(errors, null, 2)}
+
+            ${JSON.stringify(errors, null, 2)}
+          
diff --git a/packages/marko-web/components/document/components/error.marko b/packages/marko-web/components/document/components/error.marko index bcbc35214..815e18b97 100644 --- a/packages/marko-web/components/document/components/error.marko +++ b/packages/marko-web/components/document/components/error.marko @@ -14,7 +14,7 @@ $ const error = input.error || {}; <@page for="error"> <@section> -

${input.statusCode} ${input.statusMessage}

+

${input.statusCode} ${input.statusMessage}

${error.message}

${error.stack}
diff --git a/packages/marko-web/config/asset-manifest.js b/packages/marko-web/config/asset-manifest.js deleted file mode 100644 index 6a253c1ce..000000000 --- a/packages/marko-web/config/asset-manifest.js +++ /dev/null @@ -1,43 +0,0 @@ -const { join } = require('path'); - -class AssetManifest { - constructor({ distDir } = {}) { - this.distDir = distDir; - } - - js() { - if (!this.scripts) { - const { js } = this.load(); - this.scripts = [js['browser/index.js']]; - } - return this.scripts; - } - - css() { - if (!this.stylesheets) { - const { css } = this.load(); - this.stylesheets = [css['server/styles/index.scss']]; - } - return this.stylesheets; - } - - load() { - if (!this.manifest) { - this.manifest = { - js: this.loadDataFor('js'), - css: this.loadDataFor('css'), - }; - } - return this.manifest; - } - - loadDataFor(type) { - const { distDir } = this; - const distFolder = distDir.split('/').pop(); - // eslint-disable-next-line global-require, import/no-dynamic-require - const json = require(join(distDir, type, 'manifest.json')); - return Object.keys(json).reduce((o, k) => ({ ...o, [k]: join('/', distFolder, type, json[k].file) }), {}); - } -} - -module.exports = AssetManifest; diff --git a/packages/marko-web/config/core.js b/packages/marko-web/config/core.js index 827fb166d..5fded6bef 100644 --- a/packages/marko-web/config/core.js +++ b/packages/marko-web/config/core.js @@ -1,6 +1,6 @@ const { get } = require('@parameter1/base-cms-object-path'); const AbstractConfig = require('./abstract-config'); -const AssetManifest = require('./asset-manifest'); +const distLoader = require('./dist-loader'); class CoreConfig extends AbstractConfig { /** @@ -9,7 +9,11 @@ class CoreConfig extends AbstractConfig { */ constructor(config) { super(config); - this.assets = new AssetManifest({ distDir: this.get('distDir') }); + const distDir = this.get('distDir'); + this.assetLoader = { + js: distLoader({ distDir, type: 'js', entry: 'browser/index.js' }), + css: distLoader({ distDir, type: 'css', entry: 'server/styles/index.scss' }), + }; } setWebsiteContext(context) { @@ -55,11 +59,13 @@ class CoreConfig extends AbstractConfig { } sources() { - return this.assets.js(); + const js = this.assetLoader.js(); + return [js]; } styles() { - return this.assets.css(); + const css = this.assetLoader.css(); + return [css]; } } diff --git a/packages/marko-web/config/dist-loader.js b/packages/marko-web/config/dist-loader.js new file mode 100644 index 000000000..c97c4b952 --- /dev/null +++ b/packages/marko-web/config/dist-loader.js @@ -0,0 +1,24 @@ +const path = require('path'); +const { readFileSync } = require('fs'); + +const loadFromManifest = ({ distDir, type, entry }) => { + const file = path.resolve(distDir, type, 'manifest.json'); + const json = readFileSync(file, { encoding: 'utf8' }); + const manifest = JSON.parse(json); + const asset = manifest[entry]; + if (!asset) throw new Error(`Unable to extract an asset for type ${type} using manifest entry ${entry}`); + return `/dist/${type}/${asset.file}`; +}; + +module.exports = ({ distDir, type, entry }) => { + let file; + const isDevelopment = process.env.NODE_ENV !== 'production'; + return () => { + // when on dev, always return the file from the manifest + // as it may have changed during build. + if (isDevelopment) return loadFromManifest({ distDir, type, entry }); + // otherwise, only retrieve it once + if (!file) file = loadFromManifest({ distDir, type, entry }); + return file; + }; +}; diff --git a/packages/marko-web/integration/test-website-boot.js b/packages/marko-web/integration/test-website-boot.js index 6b83b76dc..a5a108469 100644 --- a/packages/marko-web/integration/test-website-boot.js +++ b/packages/marko-web/integration/test-website-boot.js @@ -1,27 +1,36 @@ const fetch = require('node-fetch'); +const { htmlEntities } = require('@parameter1/base-cms-html'); const { error, log } = console; +const url = process.env.MARKO_WEB_INTEGRATION_TEST_URL || 'http://localhost:80'; + setInterval(async () => { try { - const res = await fetch('http://localhost:80', { method: 'get' }); + const res = await fetch(url, { method: 'get' }); if (!res.ok) { error('Response not ok!', res.status, res.statusText); process.exit(1); } else { const html = await res.text(); + // check for in-body body errors + const matches = [...html.matchAll(/data-marko-error="(.*?)"/g)]; + const errors = []; + matches.forEach((values) => { + const value = values[1]; + errors.push(htmlEntities.decode(value)); + }); + if (errors.length) { + error('In-page, server-side Marko error(s) were encountered!', errors); + process.exit(0); + } + + // if not in-body errors, ensure page rendered. const found = /.*<\/head>.*<\/body>.*<\/html>.*/is.test(html); if (!found) { error('Unable to find closing HTML tags!'); process.exit(1); - return; } - // now check for any server errors - // if (/data-marko-error="true"/g.test(html)) { - // error('An in-page server-side Marko error was encountered!'); - // process.exit(1); - // return; - // } log('Integration tests passed!'); process.exit(0); } diff --git a/packages/marko-web/package.json b/packages/marko-web/package.json index cfa7bb083..dfa3f79ad 100644 --- a/packages/marko-web/package.json +++ b/packages/marko-web/package.json @@ -28,6 +28,7 @@ "@parameter1/base-cms-embedded-media": "^4.0.2", "@parameter1/base-cms-express-apollo": "^4.0.2", "@parameter1/base-cms-graphql-fragment-types": "^4.0.2", + "@parameter1/base-cms-html": "^4.0.2", "@parameter1/base-cms-image": "^4.0.2", "@parameter1/base-cms-inflector": "^4.0.2", "@parameter1/base-cms-marko-express": "^4.0.2", diff --git a/services/example-website/package.json b/services/example-website/package.json index 12accb0fa..59b86ae46 100644 --- a/services/example-website/package.json +++ b/services/example-website/package.json @@ -9,7 +9,7 @@ "private": true, "scripts": { "lint:fix": "yarn lint --fix", - "dev": "basecms-website dev --compile-dir ../../packages --watch-dir ../../packages", + "dev": "basecms-website dev --compile-dir ../../packages --watch-dir ../../packages --watch-ignore ../../packages/marko-web/integration --watch-ignore ../../packages/web-cli", "build": "basecms-website build --compile-dir ../../packages", "build:css": "basecms-website build:css", "build:js": "basecms-website build:js",