From 814695d6446be1912ee35163132d3ad3f9ffc180 Mon Sep 17 00:00:00 2001 From: Owen Buckley Date: Sat, 13 May 2023 12:00:46 -0400 Subject: [PATCH 01/14] production SSR workers refactor WIP --- packages/cli/src/lifecycles/bundle.js | 185 ++++++++++++++++---------- 1 file changed, 114 insertions(+), 71 deletions(-) diff --git a/packages/cli/src/lifecycles/bundle.js b/packages/cli/src/lifecycles/bundle.js index 974619223..a59795724 100644 --- a/packages/cli/src/lifecycles/bundle.js +++ b/packages/cli/src/lifecycles/bundle.js @@ -1,6 +1,7 @@ /* eslint-disable max-depth, max-len */ import fs from 'fs/promises'; import { getRollupConfigForApis, getRollupConfigForScriptResources, getRollupConfigForSsr } from '../config/rollup.config.js'; +import { getAppTemplate, getPageTemplate, getUserScripts } from '../lib/templating-utils.js'; import { hashString } from '../lib/hashing-utils.js'; import { checkResourceExists, mergeResponse, normalizePathnameForWindows } from '../lib/resource-utils.js'; import path from 'path'; @@ -173,6 +174,8 @@ async function bundleApiRoutes(compilation) { } async function bundleSsrPages(compilation) { + // TODO better way to do this? + await import('wc-compiler'); // https://rollupjs.org/guide/en/#differences-to-the-javascript-api const { outputDir, pagesDir } = compilation.context; // TODO context plugins for SSR ? @@ -188,87 +191,127 @@ async function bundleSsrPages(compilation) { if (!compilation.config.prerender) { for (const page of compilation.graph) { if (page.isSSR && !page.data.static) { - const { filename, path: pagePath } = page; - const scratchUrl = new URL(`./${filename}`, outputDir); + console.log({ page }); + const { filename, imports, route, template, title } = page; + const outputUrl = new URL(`./${filename}`, outputDir); + const { getTemplate = null, getBody = null } = await import(new URL(`./${filename}`, pagesDir)); + + let body = getBody ? await getBody(compilation, route) : null; + let html = ''; + + html = getTemplate ? await getTemplate(compilation, route) : await getPageTemplate('', compilation.context, template, []); + html = await getAppTemplate(html, compilation.context, imports, [], false, title); + html = await getUserScripts(html, compilation.context); + // html = html.replace(\/\(.*)<\\/content-outlet>\/s, body); + // html = await (await htmlOptimizer.optimize(new URL(request.url), new Response(html))).text(); + + // return new Response(html); + // const staticHtml = ''; + + // TODO need to handle body as a string + // TODO have to do this "manually" until import.meta.url is supported? + await fs.writeFile(outputUrl, ` + // import { renderToString } from 'wc-compiler'; + import 'wc-compiler/src/dom-shim.js'; + import Page from './_${filename}'; + + export async function handler(request) { + console.log('${JSON.stringify(page)}'); + + let initBody = ${body}; + let initHtml = \`${html}\`; + + if (!initBody) { + const page = new Page(); + await page.connectedCallback(); + // const { html } = await renderToString(new URL(request.url), false); + + initHtml = initHtml.replace(\/\(.*)<\\/content-outlet>\/s, page.innerHTML); + } - // better way to write out inline code like this? - await fs.writeFile(scratchUrl, ` - import { Worker } from 'worker_threads'; - import { getAppTemplate, getPageTemplate, getUserScripts } from '@greenwood/cli/src/lib/templating-utils.js'; - - export async function handler(request, compilation) { - const routeModuleLocationUrl = new URL('./_${filename}', '${outputDir}'); - const routeWorkerUrl = '${compilation.config.plugins.find(plugin => plugin.type === 'renderer').provider().workerUrl}'; - const htmlOptimizer = compilation.config.plugins.find(plugin => plugin.name === 'plugin-standard-html').provider(compilation); - let body = ''; - let html = ''; - let frontmatter; - let template; - let templateType = 'page'; - let title = ''; - let imports = []; - - await new Promise((resolve, reject) => { - const worker = new Worker(new URL(routeWorkerUrl)); - - worker.on('message', (result) => { - if (result.body) { - body = result.body; - } - - if (result.template) { - template = result.template; - } - - if (result.frontmatter) { - frontmatter = result.frontmatter; - - if (frontmatter.title) { - title = frontmatter.title; - } - - if (frontmatter.template) { - templateType = frontmatter.template; - } - - if (frontmatter.imports) { - imports = imports.concat(frontmatter.imports); - } - } - - resolve(); - }); - - worker.on('error', reject); - worker.on('exit', (code) => { - if (code !== 0) { - reject(new Error(\`Worker stopped with exit code \${code}\`)); - } - }); - - worker.postMessage({ - moduleUrl: routeModuleLocationUrl.href, - compilation: \`${JSON.stringify(compilation)}\`, - route: '${pagePath}' - }); - }); - - html = template ? template : await getPageTemplate('', compilation.context, templateType, []); - html = await getAppTemplate(html, compilation.context, imports, [], false, title); - html = await getUserScripts(html, compilation.context); - html = html.replace(\/\(.*)<\\/content-outlet>\/s, body); - html = await (await htmlOptimizer.optimize(new URL(request.url), new Response(html))).text(); - - return new Response(html); + return new Response(initHtml); } `); + // better way to write out inline code like this? + // await fs.writeFile(scratchUrl, ` + // import { Worker } from 'worker_threads'; + // import { getAppTemplate, getPageTemplate, getUserScripts } from '@greenwood/cli/src/lib/templating-utils.js'; + + // export async function handler(request, compilation) { + // const routeModuleLocationUrl = new URL('./_${filename}', '${outputDir}'); + // const routeWorkerUrl = '${compilation.config.plugins.find(plugin => plugin.type === 'renderer').provider().workerUrl}'; + // const htmlOptimizer = compilation.config.plugins.find(plugin => plugin.name === 'plugin-standard-html').provider(compilation); + // let body = ''; + // let html = ''; + // let frontmatter; + // let template; + // let templateType = 'page'; + // let title = ''; + // let imports = []; + + // await new Promise((resolve, reject) => { + // const worker = new Worker(new URL(routeWorkerUrl)); + + // worker.on('message', (result) => { + // if (result.body) { + // body = result.body; + // } + + // if (result.template) { + // template = result.template; + // } + + // if (result.frontmatter) { + // frontmatter = result.frontmatter; + + // if (frontmatter.title) { + // title = frontmatter.title; + // } + + // if (frontmatter.template) { + // templateType = frontmatter.template; + // } + + // if (frontmatter.imports) { + // imports = imports.concat(frontmatter.imports); + // } + // } + + // resolve(); + // }); + + // worker.on('error', reject); + // worker.on('exit', (code) => { + // if (code !== 0) { + // reject(new Error(\`Worker stopped with exit code \${code}\`)); + // } + // }); + + // worker.postMessage({ + // moduleUrl: routeModuleLocationUrl.href, + // compilation: \`${JSON.stringify(compilation)}\`, + // route: '${pagePath}' + // }); + // }); + + // html = template ? template : await getPageTemplate('', compilation.context, templateType, []); + // html = await getAppTemplate(html, compilation.context, imports, [], false, title); + // html = await getUserScripts(html, compilation.context); + // html = html.replace(\/\(.*)<\\/content-outlet>\/s, body); + // html = await (await htmlOptimizer.optimize(new URL(request.url), new Response(html))).text(); + + // return new Response(html); + // } + // `); + input.push(normalizePathnameForWindows(new URL(`./${filename}`, pagesDir))); } } const [rollupConfig] = await getRollupConfigForSsr(compilation, input); + // TODO do we need templates anymore? if (rollupConfig.input.length > 0) { const { userTemplatesDir, outputDir } = compilation.context; From acec24b0a140214bd8981fce2cb577e1f4e19a89 Mon Sep 17 00:00:00 2001 From: Owen Buckley Date: Mon, 15 May 2023 21:26:26 -0400 Subject: [PATCH 02/14] initial draft refactoring for no Workers as part of serving SSR builds --- packages/cli/src/lifecycles/bundle.js | 37 +++++++++++++++++++++------ 1 file changed, 29 insertions(+), 8 deletions(-) diff --git a/packages/cli/src/lifecycles/bundle.js b/packages/cli/src/lifecycles/bundle.js index a59795724..bd87e783b 100644 --- a/packages/cli/src/lifecycles/bundle.js +++ b/packages/cli/src/lifecycles/bundle.js @@ -210,23 +210,44 @@ async function bundleSsrPages(compilation) { // TODO need to handle body as a string // TODO have to do this "manually" until import.meta.url is supported? + // await fs.writeFile(outputUrl, ` + // // import { renderToString } from 'wc-compiler'; + // import 'wc-compiler/src/dom-shim.js'; + // import Page from './_${filename}'; + + // export async function handler(request) { + // console.log('${JSON.stringify(page)}'); + + // let initBody = ${body}; + // let initHtml = \`${html}\`; + + // if (!initBody) { + // const page = new Page(); + // await page.connectedCallback(); + // // const { html } = await renderToString(new URL(request.url), false); + + // initHtml = initHtml.replace(\/\(.*)<\\/content-outlet>\/s, page.innerHTML); + // } + + // return new Response(initHtml); + // } + // `); + await fs.writeFile(outputUrl, ` - // import { renderToString } from 'wc-compiler'; - import 'wc-compiler/src/dom-shim.js'; - import Page from './_${filename}'; + import { renderToString } from 'wc-compiler'; export async function handler(request) { - console.log('${JSON.stringify(page)}'); + console.log('${JSON.stringify(page)}'); + console.log({ request }); let initBody = ${body}; let initHtml = \`${html}\`; if (!initBody) { - const page = new Page(); - await page.connectedCallback(); - // const { html } = await renderToString(new URL(request.url), false); + console.log('serve', new URL(\`./${filename}\`, import.meta.url)); + const { html } = await renderToString(new URL(\`./_${filename}\`, import.meta.url), false); - initHtml = initHtml.replace(\/\(.*)<\\/content-outlet>\/s, page.innerHTML); + initHtml = initHtml.replace(\/\(.*)<\\/content-outlet>\/s, html); } return new Response(initHtml); From c4335ad6f4f37d1f113aaaf6b4cb570fbfbd3565 Mon Sep 17 00:00:00 2001 From: Owen Buckley Date: Sat, 3 Jun 2023 14:40:31 -0400 Subject: [PATCH 03/14] decouple SSR module execution from Workers implementation --- packages/cli/src/lib/execute-route-module.js | 45 ++++++++++++++++++++ packages/cli/src/lib/ssr-route-worker.js | 42 ++---------------- 2 files changed, 49 insertions(+), 38 deletions(-) create mode 100644 packages/cli/src/lib/execute-route-module.js diff --git a/packages/cli/src/lib/execute-route-module.js b/packages/cli/src/lib/execute-route-module.js new file mode 100644 index 000000000..0f84a6833 --- /dev/null +++ b/packages/cli/src/lib/execute-route-module.js @@ -0,0 +1,45 @@ +import { renderToString, renderFromHTML } from 'wc-compiler'; + +// TODO simplify this API signature (lot of things could be combined) +// - route, label and id could just be the current page +// - scripts is already part of the compilation +async function executeRouteModule({ moduleUrl, compilation, route, label, id, prerender, htmlContents, scripts }) { + const data = { + template: null, + body: null, + frontmatter: null, + html: null + }; + + if (prerender) { + const scriptURLs = scripts.map(scriptFile => new URL(scriptFile)); + const { html } = await renderFromHTML(htmlContents, scriptURLs); + + data.html = html; + } else { + const module = await import(moduleUrl).then(module => module); + const { getTemplate = null, getBody = null, getFrontmatter = null } = module; + + if (module.default) { + const { html } = await renderToString(new URL(moduleUrl), false); + + data.body = html; + } else { + if (getBody) { + data.body = await getBody(compilation, route); + } + } + + if (getTemplate) { + data.template = await getTemplate(compilation, route); + } + + if (getFrontmatter) { + data.frontmatter = await getFrontmatter(compilation, route, label, id); + } + } + + return data; +} + +export { executeRouteModule }; \ No newline at end of file diff --git a/packages/cli/src/lib/ssr-route-worker.js b/packages/cli/src/lib/ssr-route-worker.js index 490624abe..d904c5d22 100644 --- a/packages/cli/src/lib/ssr-route-worker.js +++ b/packages/cli/src/lib/ssr-route-worker.js @@ -1,47 +1,13 @@ // https://github.com/nodejs/modules/issues/307#issuecomment-858729422 import { parentPort } from 'worker_threads'; -import { renderToString, renderFromHTML } from 'wc-compiler'; +import { executeRouteModule } from './execute-route-module.js'; -async function executeRouteModule({ moduleUrl, compilation, route, label, id, prerender, htmlContents, scripts }) { - const parsedCompilation = JSON.parse(compilation); - const data = { - template: null, - body: null, - frontmatter: null, - html: null - }; - - if (prerender) { - const scriptURLs = JSON.parse(scripts).map(scriptFile => new URL(scriptFile)); - const { html } = await renderFromHTML(htmlContents, scriptURLs); - - data.html = html; - } else { - const module = await import(moduleUrl).then(module => module); - const { getTemplate = null, getBody = null, getFrontmatter = null } = module; - - if (module.default) { - const { html } = await renderToString(new URL(moduleUrl), false); - - data.body = html; - } else { - if (getBody) { - data.body = await getBody(parsedCompilation, route); - } - } - - if (getTemplate) { - data.template = await getTemplate(parsedCompilation, route); - } - - if (getFrontmatter) { - data.frontmatter = await getFrontmatter(parsedCompilation, route, label, id); - } - } +async function executeModule({ moduleUrl, compilation, route, label, id, prerender, htmlContents, scripts = '[]' }) { + const data = await executeRouteModule({ moduleUrl, compilation: JSON.parse(compilation), route, label, id, prerender, htmlContents, scripts: JSON.parse(scripts) }); parentPort.postMessage(data); } parentPort.on('message', async (task) => { - await executeRouteModule(task); + await executeModule(task); }); \ No newline at end of file From 16aea702fb3a150da0f742c98b3dfe1cc1bf108b Mon Sep 17 00:00:00 2001 From: Owen Buckley Date: Sat, 3 Jun 2023 20:15:06 -0400 Subject: [PATCH 04/14] enable pre-compiled HTML for templates during SSR --- packages/cli/src/lifecycles/bundle.js | 164 ++++++-------------------- 1 file changed, 39 insertions(+), 125 deletions(-) diff --git a/packages/cli/src/lifecycles/bundle.js b/packages/cli/src/lifecycles/bundle.js index bd87e783b..3e769756d 100644 --- a/packages/cli/src/lifecycles/bundle.js +++ b/packages/cli/src/lifecycles/bundle.js @@ -2,6 +2,7 @@ import fs from 'fs/promises'; import { getRollupConfigForApis, getRollupConfigForScriptResources, getRollupConfigForSsr } from '../config/rollup.config.js'; import { getAppTemplate, getPageTemplate, getUserScripts } from '../lib/templating-utils.js'; +import { executeRouteModule } from '../lib/execute-route-module.js'; import { hashString } from '../lib/hashing-utils.js'; import { checkResourceExists, mergeResponse, normalizePathnameForWindows } from '../lib/resource-utils.js'; import path from 'path'; @@ -174,10 +175,7 @@ async function bundleApiRoutes(compilation) { } async function bundleSsrPages(compilation) { - // TODO better way to do this? - await import('wc-compiler'); // https://rollupjs.org/guide/en/#differences-to-the-javascript-api - const { outputDir, pagesDir } = compilation.context; // TODO context plugins for SSR ? // https://github.com/ProjectEvergreen/greenwood/issues/1008 // const contextPlugins = compilation.config.plugins.filter((plugin) => { @@ -189,142 +187,57 @@ async function bundleSsrPages(compilation) { const input = []; if (!compilation.config.prerender) { + const htmlOptimizer = compilation.config.plugins.find(plugin => plugin.name === 'plugin-standard-html').provider(compilation); + const { outputDir, pagesDir } = compilation.context; + for (const page of compilation.graph) { if (page.isSSR && !page.data.static) { - console.log({ page }); - const { filename, imports, route, template, title } = page; + const { filename, imports, route, id, label, template, title } = page; const outputUrl = new URL(`./${filename}`, outputDir); - const { getTemplate = null, getBody = null } = await import(new URL(`./${filename}`, pagesDir)); - - let body = getBody ? await getBody(compilation, route) : null; - let html = ''; - - html = getTemplate ? await getTemplate(compilation, route) : await getPageTemplate('', compilation.context, template, []); - html = await getAppTemplate(html, compilation.context, imports, [], false, title); - html = await getUserScripts(html, compilation.context); - // html = html.replace(\/\(.*)<\\/content-outlet>\/s, body); - // html = await (await htmlOptimizer.optimize(new URL(request.url), new Response(html))).text(); - - // return new Response(html); - // const staticHtml = ''; - - // TODO need to handle body as a string - // TODO have to do this "manually" until import.meta.url is supported? - // await fs.writeFile(outputUrl, ` - // // import { renderToString } from 'wc-compiler'; - // import 'wc-compiler/src/dom-shim.js'; - // import Page from './_${filename}'; - - // export async function handler(request) { - // console.log('${JSON.stringify(page)}'); + const moduleUrl = new URL(`./${filename}`, pagesDir); + // TODO getTemplate has to be static (for now?) + // const { getTemplate = null } = await import(new URL(`./${filename}`, pagesDir)); + const data = await executeRouteModule({ moduleUrl, compilation, route, label, id, prerender: false, htmlContents: null, scripts: [] }); + let staticHtml = ''; - // let initBody = ${body}; - // let initHtml = \`${html}\`; + staticHtml = data.template ? data.template : await getPageTemplate(staticHtml, compilation.context, template, []); + // console.log('+ page template', { staticHtml }); - // if (!initBody) { - // const page = new Page(); - // await page.connectedCallback(); - // // const { html } = await renderToString(new URL(request.url), false); + staticHtml = await getAppTemplate(staticHtml, compilation.context, imports, [], false, title); + // console.log('+ app template', { staticHtml }); - // initHtml = initHtml.replace(\/\(.*)<\\/content-outlet>\/s, page.innerHTML); - // } + staticHtml = await getUserScripts(staticHtml, compilation.context); + // console.log('+ user scripts', { staticHtml }); - // return new Response(initHtml); - // } - // `); + staticHtml = await (await htmlOptimizer.optimize(new URL(`http://localhost:8080${route}`), new Response(staticHtml))).text(); + // console.log('+ optimizer', { staticHtml }); + // better way to write out this inline code? + // TODO need to get executeRouteModule value from config await fs.writeFile(outputUrl, ` - import { renderToString } from 'wc-compiler'; + import { executeRouteModule } from '@greenwood/cli/src/lib/execute-route-module.js'; export async function handler(request) { - console.log('${JSON.stringify(page)}'); - console.log({ request }); - - let initBody = ${body}; - let initHtml = \`${html}\`; - - if (!initBody) { - console.log('serve', new URL(\`./${filename}\`, import.meta.url)); - const { html } = await renderToString(new URL(\`./_${filename}\`, import.meta.url), false); - - initHtml = initHtml.replace(\/\(.*)<\\/content-outlet>\/s, html); + const compilation = JSON.parse('${JSON.stringify(compilation)}'); + const page = JSON.parse('${JSON.stringify(page)}'); + const { route, label, id } = page; + let staticHtml = \`${staticHtml}\`; + const moduleUrl = new URL('./_${filename}', '${outputDir.href}'); + const data = await executeRouteModule({ moduleUrl, compilation, route, label, id, prerender: false, htmlContents: null, scripts: [] }); + + // console.log({ page }) + // console.log({ staticHtml }) + // console.log({ data }); + + if (data.body) { + staticHtml = staticHtml.replace(\/\(.*)<\\/content-outlet>\/s, data.body); } - return new Response(initHtml); + return new Response(staticHtml); } `); - // better way to write out inline code like this? - // await fs.writeFile(scratchUrl, ` - // import { Worker } from 'worker_threads'; - // import { getAppTemplate, getPageTemplate, getUserScripts } from '@greenwood/cli/src/lib/templating-utils.js'; - - // export async function handler(request, compilation) { - // const routeModuleLocationUrl = new URL('./_${filename}', '${outputDir}'); - // const routeWorkerUrl = '${compilation.config.plugins.find(plugin => plugin.type === 'renderer').provider().workerUrl}'; - // const htmlOptimizer = compilation.config.plugins.find(plugin => plugin.name === 'plugin-standard-html').provider(compilation); - // let body = ''; - // let html = ''; - // let frontmatter; - // let template; - // let templateType = 'page'; - // let title = ''; - // let imports = []; - - // await new Promise((resolve, reject) => { - // const worker = new Worker(new URL(routeWorkerUrl)); - - // worker.on('message', (result) => { - // if (result.body) { - // body = result.body; - // } - - // if (result.template) { - // template = result.template; - // } - - // if (result.frontmatter) { - // frontmatter = result.frontmatter; - - // if (frontmatter.title) { - // title = frontmatter.title; - // } - - // if (frontmatter.template) { - // templateType = frontmatter.template; - // } - - // if (frontmatter.imports) { - // imports = imports.concat(frontmatter.imports); - // } - // } - - // resolve(); - // }); - - // worker.on('error', reject); - // worker.on('exit', (code) => { - // if (code !== 0) { - // reject(new Error(\`Worker stopped with exit code \${code}\`)); - // } - // }); - - // worker.postMessage({ - // moduleUrl: routeModuleLocationUrl.href, - // compilation: \`${JSON.stringify(compilation)}\`, - // route: '${pagePath}' - // }); - // }); - - // html = template ? template : await getPageTemplate('', compilation.context, templateType, []); - // html = await getAppTemplate(html, compilation.context, imports, [], false, title); - // html = await getUserScripts(html, compilation.context); - // html = html.replace(\/\(.*)<\\/content-outlet>\/s, body); - // html = await (await htmlOptimizer.optimize(new URL(request.url), new Response(html))).text(); - - // return new Response(html); - // } - // `); + // console.log('========================='); input.push(normalizePathnameForWindows(new URL(`./${filename}`, pagesDir))); } @@ -373,13 +286,14 @@ const bundleCompilation = async (compilation) => { await Promise.all([ await bundleApiRoutes(compilation), - await bundleSsrPages(compilation), await bundleScriptResources(compilation), await bundleStyleResources(compilation, optimizeResourcePlugins) ]); - console.info('optimizing static pages....'); + // bundleSsrPages depends on bundleScriptResources having run first + await bundleSsrPages(compilation); + console.info('optimizing static pages....'); await optimizeStaticPages(compilation, optimizeResourcePlugins); await cleanUpResources(compilation); await emitResources(compilation); From 382919b885d2351a9f10ce393dbcac2822a6417c Mon Sep 17 00:00:00 2001 From: Owen Buckley Date: Sat, 3 Jun 2023 20:44:07 -0400 Subject: [PATCH 05/14] ammed static router spec for execute-route-module --- .../serve.config.static-router.spec.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/packages/cli/test/cases/serve.config.static-router/serve.config.static-router.spec.js b/packages/cli/test/cases/serve.config.static-router/serve.config.static-router.spec.js index 369ad63f6..4696b2f2c 100644 --- a/packages/cli/test/cases/serve.config.static-router/serve.config.static-router.spec.js +++ b/packages/cli/test/cases/serve.config.static-router/serve.config.static-router.spec.js @@ -52,7 +52,7 @@ describe('Serve Greenwood With: ', function() { 'hashing-utils', 'node-modules-utils', 'resource-utils', - 'templating-utils' + 'execute-route-module' ]; before(async function() { @@ -61,19 +61,19 @@ describe('Serve Greenwood With: ', function() { `${outputPath}/node_modules/@greenwood/cli/src/lib` ); /* - * there is an odd issue seemingly due to needed lib/router.js tha causes tests to think files are CommonJS + * there is an odd issue seemingly due to needing lib/router.js that causes tests to think files are CommonJS * ``` * file:///Users/owenbuckley/Workspace/project-evergreen/repos/greenwood/packages/cli/test/cases/serve.config.static-router/public/artists.js:3 - * import { getAppTemplate, getPageTemplate, getUserScripts } from '@greenwood/cli/src/lib/templating-utils.js'; + * import { executeRouteModule } from '@greenwood/cli/src/lib/execute-route-module.js'; * ^^^^^^^^^^^^^^ - * SyntaxError: Named export 'getAppTemplate' not found. The requested module '@greenwood/cli/src/lib/templating-utils.js' + * SyntaxError: Named export 'executeRouteModule' not found. The requested module '@greenwood/cli/src/lib/templating-utils.js' * is a CommonJS module, which may not support all module.exports as named exports. * CommonJS modules can always be imported via the default export, for example using: - * import pkg from '@greenwood/cli/src/lib/templating-utils.js'; - * const { getAppTemplate, getPageTemplate, getUserScripts } = pkg; + * import pkg from '@greenwood/cli/src/lib/execute-route-module.js'; + * const { executeRouteModule } = pkg; * ``` * - * however no other tests have this issue. so as terrible hack we need to + * however no other tests have this issue. so as a terrible hack we need to * - copy all lib files * - rename them to end in .mjs * - update references to these files in other imports From 6a1f596ae672b7404b78d9503f4912a815782538 Mon Sep 17 00:00:00 2001 From: Owen Buckley Date: Wed, 7 Jun 2023 08:43:32 -0400 Subject: [PATCH 06/14] get SSR execution module from config --- packages/cli/src/lib/ssr-route-worker.js | 4 ++-- packages/cli/src/lifecycles/bundle.js | 11 ++++++++--- packages/cli/src/lifecycles/graph.js | 5 +++-- .../src/plugins/renderer/plugin-renderer-default.js | 2 +- .../cli/src/plugins/resource/plugin-standard-html.js | 6 ++++-- 5 files changed, 18 insertions(+), 10 deletions(-) diff --git a/packages/cli/src/lib/ssr-route-worker.js b/packages/cli/src/lib/ssr-route-worker.js index d904c5d22..b6bbeb514 100644 --- a/packages/cli/src/lib/ssr-route-worker.js +++ b/packages/cli/src/lib/ssr-route-worker.js @@ -1,8 +1,8 @@ // https://github.com/nodejs/modules/issues/307#issuecomment-858729422 import { parentPort } from 'worker_threads'; -import { executeRouteModule } from './execute-route-module.js'; -async function executeModule({ moduleUrl, compilation, route, label, id, prerender, htmlContents, scripts = '[]' }) { +async function executeModule({ executeRouteModuleUrl, moduleUrl, compilation, route, label, id, prerender, htmlContents, scripts = '[]' }) { + const { executeRouteModule } = await import(executeRouteModuleUrl); const data = await executeRouteModule({ moduleUrl, compilation: JSON.parse(compilation), route, label, id, prerender, htmlContents, scripts: JSON.parse(scripts) }); parentPort.postMessage(data); diff --git a/packages/cli/src/lifecycles/bundle.js b/packages/cli/src/lifecycles/bundle.js index 3e769756d..1dc6bb2a1 100644 --- a/packages/cli/src/lifecycles/bundle.js +++ b/packages/cli/src/lifecycles/bundle.js @@ -2,7 +2,6 @@ import fs from 'fs/promises'; import { getRollupConfigForApis, getRollupConfigForScriptResources, getRollupConfigForSsr } from '../config/rollup.config.js'; import { getAppTemplate, getPageTemplate, getUserScripts } from '../lib/templating-utils.js'; -import { executeRouteModule } from '../lib/execute-route-module.js'; import { hashString } from '../lib/hashing-utils.js'; import { checkResourceExists, mergeResponse, normalizePathnameForWindows } from '../lib/resource-utils.js'; import path from 'path'; @@ -188,6 +187,8 @@ async function bundleSsrPages(compilation) { if (!compilation.config.prerender) { const htmlOptimizer = compilation.config.plugins.find(plugin => plugin.name === 'plugin-standard-html').provider(compilation); + const routeWorkerUrl = compilation.config.plugins.find(plugin => plugin.type === 'renderer').provider().executeRouteModuleUrl; + const { executeRouteModule } = await import(routeWorkerUrl); const { outputDir, pagesDir } = compilation.context; for (const page of compilation.graph) { @@ -209,15 +210,17 @@ async function bundleSsrPages(compilation) { staticHtml = await getUserScripts(staticHtml, compilation.context); // console.log('+ user scripts', { staticHtml }); + // TODO do we want to use http:// here for optimizer? staticHtml = await (await htmlOptimizer.optimize(new URL(`http://localhost:8080${route}`), new Response(staticHtml))).text(); // console.log('+ optimizer', { staticHtml }); // better way to write out this inline code? - // TODO need to get executeRouteModule value from config + // TODO does executeRouteModule need to get bundled? await fs.writeFile(outputUrl, ` - import { executeRouteModule } from '@greenwood/cli/src/lib/execute-route-module.js'; + // const { executeRouteModule } from '@greenwood/cli/src/lib/execute-route-module.js'; export async function handler(request) { + const { executeRouteModule } = await import('${routeWorkerUrl.href}'); const compilation = JSON.parse('${JSON.stringify(compilation)}'); const page = JSON.parse('${JSON.stringify(page)}'); const { route, label, id } = page; @@ -239,6 +242,7 @@ async function bundleSsrPages(compilation) { // console.log('========================='); + // TODO should we bundle entry points? input.push(normalizePathnameForWindows(new URL(`./${filename}`, pagesDir))); } } @@ -249,6 +253,7 @@ async function bundleSsrPages(compilation) { if (rollupConfig.input.length > 0) { const { userTemplatesDir, outputDir } = compilation.context; + // TODO can this be removed if (await checkResourceExists(userTemplatesDir)) { await fs.cp(userTemplatesDir, new URL('./_templates/', outputDir), { recursive: true }); } diff --git a/packages/cli/src/lifecycles/graph.js b/packages/cli/src/lifecycles/graph.js index 8c66ab3ae..6b33e372a 100644 --- a/packages/cli/src/lifecycles/graph.js +++ b/packages/cli/src/lifecycles/graph.js @@ -116,13 +116,13 @@ const generateGraph = async (compilation) => { } /* ---------End Menu Query-------------------- */ } else if (isDynamic) { - const routeWorkerUrl = compilation.config.plugins.filter(plugin => plugin.type === 'renderer')[0].provider(compilation).workerUrl; + const routeWorkerUrl = compilation.config.plugins.filter(plugin => plugin.type === 'renderer')[0].provider(compilation).executeRouteModuleUrl; let ssrFrontmatter; filePath = route; await new Promise((resolve, reject) => { - const worker = new Worker(routeWorkerUrl); + const worker = new Worker(new URL('../lib/ssr-route-worker.js', import.meta.url)); worker.on('message', async (result) => { if (result.frontmatter) { @@ -139,6 +139,7 @@ const generateGraph = async (compilation) => { }); worker.postMessage({ + executeRouteModuleUrl: routeWorkerUrl.href, moduleUrl: filenameUrl.href, compilation: JSON.stringify(compilation), route diff --git a/packages/cli/src/plugins/renderer/plugin-renderer-default.js b/packages/cli/src/plugins/renderer/plugin-renderer-default.js index 16203beb9..6be036ef4 100644 --- a/packages/cli/src/plugins/renderer/plugin-renderer-default.js +++ b/packages/cli/src/plugins/renderer/plugin-renderer-default.js @@ -3,7 +3,7 @@ const greenwoodPluginRendererDefault = { name: 'plugin-renderer-default', provider: () => { return { - workerUrl: new URL('../../lib/ssr-route-worker.js', import.meta.url) + executeRouteModuleUrl: new URL('../../lib/execute-route-module.js', import.meta.url) }; } }; diff --git a/packages/cli/src/plugins/resource/plugin-standard-html.js b/packages/cli/src/plugins/resource/plugin-standard-html.js index 52fbd8e47..e9816c52a 100644 --- a/packages/cli/src/plugins/resource/plugin-standard-html.js +++ b/packages/cli/src/plugins/resource/plugin-standard-html.js @@ -105,10 +105,10 @@ class StandardHtmlResource extends ResourceInterface { if (matchingRoute.isSSR) { const routeModuleLocationUrl = new URL(`./${matchingRoute.filename}`, pagesDir); - const routeWorkerUrl = this.compilation.config.plugins.find(plugin => plugin.type === 'renderer').provider().workerUrl; + const routeWorkerUrl = this.compilation.config.plugins.find(plugin => plugin.type === 'renderer').provider().executeRouteModuleUrl; await new Promise((resolve, reject) => { - const worker = new Worker(routeWorkerUrl); + const worker = new Worker(new URL('../../lib/ssr-route-worker.js', import.meta.url)); worker.on('message', (result) => { if (result.template) { @@ -143,6 +143,7 @@ class StandardHtmlResource extends ResourceInterface { }); worker.postMessage({ + executeRouteModuleUrl: routeWorkerUrl.href, moduleUrl: routeModuleLocationUrl.href, compilation: JSON.stringify(this.compilation), route: matchingRoute.path @@ -212,6 +213,7 @@ class StandardHtmlResource extends ResourceInterface { } async shouldOptimize(url, response) { + // TOOD should be .indexOf(this.contentType) === 0 return response.headers.get('Content-Type').indexOf(this.contentType) >= 0; } From 130698a06f8034cf7f0b8ca518f173e5bd0df94d Mon Sep 17 00:00:00 2001 From: Owen Buckley Date: Wed, 7 Jun 2023 21:44:11 -0400 Subject: [PATCH 07/14] refactor executeRouteModule signature and fix all specs --- packages/cli/src/commands/build.js | 2 +- packages/cli/src/lib/execute-route-module.js | 8 +-- packages/cli/src/lib/ssr-route-worker.js | 6 +- packages/cli/src/lifecycles/bundle.js | 22 +++---- packages/cli/src/lifecycles/graph.js | 15 ++++- packages/cli/src/lifecycles/prerender.js | 6 +- .../renderer/plugin-renderer-default.js | 2 +- .../plugins/resource/plugin-standard-html.js | 6 +- .../src/pages/artists.js | 2 +- .../cases/develop.ssr/src/pages/artists.js | 4 +- .../serve.config.static-router.spec.js | 61 +------------------ .../src/pages/artists.js | 2 +- .../serve.default.ssr/src/pages/artists.js | 4 +- .../cases/serve.default/src/pages/artists.js | 4 +- 14 files changed, 47 insertions(+), 97 deletions(-) diff --git a/packages/cli/src/commands/build.js b/packages/cli/src/commands/build.js index 1d4502195..6ea8d15e9 100644 --- a/packages/cli/src/commands/build.js +++ b/packages/cli/src/commands/build.js @@ -98,7 +98,7 @@ const runProductionBuild = async (compilation) => { return Promise.resolve(server); })); - if (prerenderPlugin.workerUrl) { + if (prerenderPlugin.executeModuleUrl) { await trackResourcesForRoutes(compilation); await preRenderCompilationWorker(compilation, prerenderPlugin); } else { diff --git a/packages/cli/src/lib/execute-route-module.js b/packages/cli/src/lib/execute-route-module.js index 0f84a6833..b1c1c63e2 100644 --- a/packages/cli/src/lib/execute-route-module.js +++ b/packages/cli/src/lib/execute-route-module.js @@ -3,7 +3,7 @@ import { renderToString, renderFromHTML } from 'wc-compiler'; // TODO simplify this API signature (lot of things could be combined) // - route, label and id could just be the current page // - scripts is already part of the compilation -async function executeRouteModule({ moduleUrl, compilation, route, label, id, prerender, htmlContents, scripts }) { +async function executeRouteModule({ moduleUrl, compilation, page = {}, prerender = false, htmlContents = null, scripts = [] }) { const data = { template: null, body: null, @@ -26,16 +26,16 @@ async function executeRouteModule({ moduleUrl, compilation, route, label, id, pr data.body = html; } else { if (getBody) { - data.body = await getBody(compilation, route); + data.body = await getBody(compilation, page); } } if (getTemplate) { - data.template = await getTemplate(compilation, route); + data.template = await getTemplate(compilation, page); } if (getFrontmatter) { - data.frontmatter = await getFrontmatter(compilation, route, label, id); + data.frontmatter = await getFrontmatter(compilation, page); } } diff --git a/packages/cli/src/lib/ssr-route-worker.js b/packages/cli/src/lib/ssr-route-worker.js index b6bbeb514..12eb71d88 100644 --- a/packages/cli/src/lib/ssr-route-worker.js +++ b/packages/cli/src/lib/ssr-route-worker.js @@ -1,9 +1,9 @@ // https://github.com/nodejs/modules/issues/307#issuecomment-858729422 import { parentPort } from 'worker_threads'; -async function executeModule({ executeRouteModuleUrl, moduleUrl, compilation, route, label, id, prerender, htmlContents, scripts = '[]' }) { - const { executeRouteModule } = await import(executeRouteModuleUrl); - const data = await executeRouteModule({ moduleUrl, compilation: JSON.parse(compilation), route, label, id, prerender, htmlContents, scripts: JSON.parse(scripts) }); +async function executeModule({ executeModuleUrl, moduleUrl, compilation, page, prerender = false, htmlContents = null, scripts = '[]' }) { + const { executeRouteModule } = await import(executeModuleUrl); + const data = await executeRouteModule({ moduleUrl, compilation: JSON.parse(compilation), page: JSON.parse(page), prerender, htmlContents, scripts: JSON.parse(scripts) }); parentPort.postMessage(data); } diff --git a/packages/cli/src/lifecycles/bundle.js b/packages/cli/src/lifecycles/bundle.js index 1dc6bb2a1..0ebbcf762 100644 --- a/packages/cli/src/lifecycles/bundle.js +++ b/packages/cli/src/lifecycles/bundle.js @@ -182,23 +182,23 @@ async function bundleSsrPages(compilation) { // }).map((plugin) => { // return plugin.provider(compilation); // }); - + const hasSSRPages = compilation.graph.filter(page => page.isSSR).length > 0; const input = []; - if (!compilation.config.prerender) { + if (!compilation.config.prerender && hasSSRPages) { const htmlOptimizer = compilation.config.plugins.find(plugin => plugin.name === 'plugin-standard-html').provider(compilation); - const routeWorkerUrl = compilation.config.plugins.find(plugin => plugin.type === 'renderer').provider().executeRouteModuleUrl; - const { executeRouteModule } = await import(routeWorkerUrl); + const { executeModuleUrl } = compilation.config.plugins.find(plugin => plugin.type === 'renderer').provider(); + const { executeRouteModule } = await import(executeModuleUrl); const { outputDir, pagesDir } = compilation.context; for (const page of compilation.graph) { if (page.isSSR && !page.data.static) { - const { filename, imports, route, id, label, template, title } = page; + const { filename, imports, route, template, title } = page; const outputUrl = new URL(`./${filename}`, outputDir); const moduleUrl = new URL(`./${filename}`, pagesDir); // TODO getTemplate has to be static (for now?) // const { getTemplate = null } = await import(new URL(`./${filename}`, pagesDir)); - const data = await executeRouteModule({ moduleUrl, compilation, route, label, id, prerender: false, htmlContents: null, scripts: [] }); + const data = await executeRouteModule({ moduleUrl, compilation, page, prerender: false, htmlContents: null, scripts: [] }); let staticHtml = ''; staticHtml = data.template ? data.template : await getPageTemplate(staticHtml, compilation.context, template, []); @@ -216,17 +216,15 @@ async function bundleSsrPages(compilation) { // better way to write out this inline code? // TODO does executeRouteModule need to get bundled? + // TODO do we need to bundle this too since we reference executeModuleUrl.href directly? await fs.writeFile(outputUrl, ` - // const { executeRouteModule } from '@greenwood/cli/src/lib/execute-route-module.js'; - export async function handler(request) { - const { executeRouteModule } = await import('${routeWorkerUrl.href}'); + const { executeRouteModule } = await import('${executeModuleUrl.href}'); const compilation = JSON.parse('${JSON.stringify(compilation)}'); const page = JSON.parse('${JSON.stringify(page)}'); - const { route, label, id } = page; - let staticHtml = \`${staticHtml}\`; const moduleUrl = new URL('./_${filename}', '${outputDir.href}'); - const data = await executeRouteModule({ moduleUrl, compilation, route, label, id, prerender: false, htmlContents: null, scripts: [] }); + const data = await executeRouteModule({ moduleUrl, compilation, page }); + let staticHtml = \`${staticHtml}\`; // console.log({ page }) // console.log({ staticHtml }) diff --git a/packages/cli/src/lifecycles/graph.js b/packages/cli/src/lifecycles/graph.js index 6b33e372a..486adb6d1 100644 --- a/packages/cli/src/lifecycles/graph.js +++ b/packages/cli/src/lifecycles/graph.js @@ -116,7 +116,7 @@ const generateGraph = async (compilation) => { } /* ---------End Menu Query-------------------- */ } else if (isDynamic) { - const routeWorkerUrl = compilation.config.plugins.filter(plugin => plugin.type === 'renderer')[0].provider(compilation).executeRouteModuleUrl; + const routeWorkerUrl = compilation.config.plugins.filter(plugin => plugin.type === 'renderer')[0].provider(compilation).executeModuleUrl; let ssrFrontmatter; filePath = route; @@ -139,10 +139,19 @@ const generateGraph = async (compilation) => { }); worker.postMessage({ - executeRouteModuleUrl: routeWorkerUrl.href, + executeModuleUrl: routeWorkerUrl.href, moduleUrl: filenameUrl.href, compilation: JSON.stringify(compilation), - route + // TODO need to get as many of these params as possible + // or ignore completely? + page: JSON.stringify({ + route, + id, + label: id.split('-') + .map((idPart) => { + return `${idPart.charAt(0).toUpperCase()}${idPart.substring(1)}`; + }).join(' ') + }) }); }); diff --git a/packages/cli/src/lifecycles/prerender.js b/packages/cli/src/lifecycles/prerender.js index 48f8e8fdd..b6479cd3e 100644 --- a/packages/cli/src/lifecycles/prerender.js +++ b/packages/cli/src/lifecycles/prerender.js @@ -55,7 +55,8 @@ async function preRenderCompilationWorker(compilation, workerPrerender) { console.info('pages to generate', `\n ${pages.map(page => page.route).join('\n ')}`); - const pool = new WorkerPool(os.cpus().length, workerPrerender.workerUrl); + console.log({ workerPrerender }); + const pool = new WorkerPool(os.cpus().length, new URL('../lib/ssr-route-worker.js', import.meta.url)); for (const page of pages) { const { route, outputPath, resources } = page; @@ -76,9 +77,10 @@ async function preRenderCompilationWorker(compilation, workerPrerender) { body = await new Promise((resolve, reject) => { pool.runTask({ + executeModuleUrl: workerPrerender.executeModuleUrl.href, modulePath: null, compilation: JSON.stringify(compilation), - route, + page: JSON.stringify(page), prerender: true, htmlContents: body, scripts: JSON.stringify(scripts) diff --git a/packages/cli/src/plugins/renderer/plugin-renderer-default.js b/packages/cli/src/plugins/renderer/plugin-renderer-default.js index 6be036ef4..534384f83 100644 --- a/packages/cli/src/plugins/renderer/plugin-renderer-default.js +++ b/packages/cli/src/plugins/renderer/plugin-renderer-default.js @@ -3,7 +3,7 @@ const greenwoodPluginRendererDefault = { name: 'plugin-renderer-default', provider: () => { return { - executeRouteModuleUrl: new URL('../../lib/execute-route-module.js', import.meta.url) + executeModuleUrl: new URL('../../lib/execute-route-module.js', import.meta.url) }; } }; diff --git a/packages/cli/src/plugins/resource/plugin-standard-html.js b/packages/cli/src/plugins/resource/plugin-standard-html.js index e9816c52a..11f81d1e6 100644 --- a/packages/cli/src/plugins/resource/plugin-standard-html.js +++ b/packages/cli/src/plugins/resource/plugin-standard-html.js @@ -105,7 +105,7 @@ class StandardHtmlResource extends ResourceInterface { if (matchingRoute.isSSR) { const routeModuleLocationUrl = new URL(`./${matchingRoute.filename}`, pagesDir); - const routeWorkerUrl = this.compilation.config.plugins.find(plugin => plugin.type === 'renderer').provider().executeRouteModuleUrl; + const routeWorkerUrl = this.compilation.config.plugins.find(plugin => plugin.type === 'renderer').provider().executeModuleUrl; await new Promise((resolve, reject) => { const worker = new Worker(new URL('../../lib/ssr-route-worker.js', import.meta.url)); @@ -143,10 +143,10 @@ class StandardHtmlResource extends ResourceInterface { }); worker.postMessage({ - executeRouteModuleUrl: routeWorkerUrl.href, + executeModuleUrl: routeWorkerUrl.href, moduleUrl: routeModuleLocationUrl.href, compilation: JSON.stringify(this.compilation), - route: matchingRoute.path + page: JSON.stringify(matchingRoute) }); }); } diff --git a/packages/cli/test/cases/build.default.ssr-static-export/src/pages/artists.js b/packages/cli/test/cases/build.default.ssr-static-export/src/pages/artists.js index 740a563a1..e0d3773e5 100644 --- a/packages/cli/test/cases/build.default.ssr-static-export/src/pages/artists.js +++ b/packages/cli/test/cases/build.default.ssr-static-export/src/pages/artists.js @@ -1,4 +1,4 @@ -async function getTemplate(compilation, route) { +async function getTemplate(compilation, { route }) { return ` diff --git a/packages/cli/test/cases/develop.ssr/src/pages/artists.js b/packages/cli/test/cases/develop.ssr/src/pages/artists.js index ba2af1e62..b035a91eb 100644 --- a/packages/cli/test/cases/develop.ssr/src/pages/artists.js +++ b/packages/cli/test/cases/develop.ssr/src/pages/artists.js @@ -1,4 +1,4 @@ -async function getTemplate(compilation, route) { +async function getTemplate(compilation, { route }) { return ` @@ -67,7 +67,7 @@ async function getBody(compilation) { `; } -async function getFrontmatter(compilation, route) { +async function getFrontmatter(compilation, { route }) { return { menu: 'navigation', index: 7, diff --git a/packages/cli/test/cases/serve.config.static-router/serve.config.static-router.spec.js b/packages/cli/test/cases/serve.config.static-router/serve.config.static-router.spec.js index 4696b2f2c..501b8129a 100644 --- a/packages/cli/test/cases/serve.config.static-router/serve.config.static-router.spec.js +++ b/packages/cli/test/cases/serve.config.static-router/serve.config.static-router.spec.js @@ -22,10 +22,8 @@ * index.md */ import chai from 'chai'; -import fs from 'fs/promises'; import path from 'path'; import { getSetupFiles, getDependencyFiles, getOutputTeardownFiles } from '../../../../../test/utils.js'; -import { normalizePathnameForWindows } from '../../../src/lib/resource-utils.js'; import request from 'request'; import { runSmokeTest } from '../../../../../test/smoke-test.js'; import { Runner } from 'gallinago'; @@ -48,79 +46,22 @@ describe('Serve Greenwood With: ', function() { }); describe(LABEL, function() { - const workaroundFiles = [ - 'hashing-utils', - 'node-modules-utils', - 'resource-utils', - 'execute-route-module' - ]; before(async function() { const greenwoodRouterLibs = await getDependencyFiles( `${process.cwd()}/packages/cli/src/lib/router.js`, `${outputPath}/node_modules/@greenwood/cli/src/lib` ); - /* - * there is an odd issue seemingly due to needing lib/router.js that causes tests to think files are CommonJS - * ``` - * file:///Users/owenbuckley/Workspace/project-evergreen/repos/greenwood/packages/cli/test/cases/serve.config.static-router/public/artists.js:3 - * import { executeRouteModule } from '@greenwood/cli/src/lib/execute-route-module.js'; - * ^^^^^^^^^^^^^^ - * SyntaxError: Named export 'executeRouteModule' not found. The requested module '@greenwood/cli/src/lib/templating-utils.js' - * is a CommonJS module, which may not support all module.exports as named exports. - * CommonJS modules can always be imported via the default export, for example using: - * import pkg from '@greenwood/cli/src/lib/execute-route-module.js'; - * const { executeRouteModule } = pkg; - * ``` - * - * however no other tests have this issue. so as a terrible hack we need to - * - copy all lib files - * - rename them to end in .mjs - * - update references to these files in other imports - * - * (unfortunately, trying to just add a package.json with type="module" did not seem to work :/) - */ - const greenwoodTemplatingLibs = await getDependencyFiles( - `${process.cwd()}/packages/cli/src/lib/*`, - `${outputPath}/node_modules/@greenwood/cli/src/lib` - ); - const greenwoodTemplates = await getDependencyFiles( - `${process.cwd()}/packages/cli/src/templates/*`, - `${outputPath}/node_modules/@greenwood/cli/src/templates` - ); await runner.setup(outputPath, [ ...getSetupFiles(outputPath), - ...greenwoodRouterLibs, - ...greenwoodTemplatingLibs, - ...greenwoodTemplates + ...greenwoodRouterLibs ]); - for (const f of workaroundFiles) { - const pathname = normalizePathnameForWindows(new URL(`./node_modules/@greenwood/cli/src/lib/${f}.js`, import.meta.url)); - let contents = await fs.readFile(pathname, 'utf-8'); - - workaroundFiles.forEach((wf) => { - contents = contents.replace(`${wf}.js`, `${wf}.mjs`); - }); - - await fs.writeFile(pathname.replace('.js', '.mjs'), contents); - } - await runner.runCommand(cliPath, 'build'); return new Promise(async (resolve) => { setTimeout(async () => { - // template out artists.js to use .mjs too - const pathname = normalizePathnameForWindows(new URL('./public/artists.js', import.meta.url)); - let ssrPageContents = await fs.readFile(pathname, 'utf-8'); - - for (const f of workaroundFiles) { - ssrPageContents = ssrPageContents.replace(`${f}.js`, `${f}.mjs`); - } - - await fs.writeFile(pathname, ssrPageContents); - resolve(); }, 10000); diff --git a/packages/cli/test/cases/serve.default.ssr-static-export/src/pages/artists.js b/packages/cli/test/cases/serve.default.ssr-static-export/src/pages/artists.js index 740a563a1..e0d3773e5 100644 --- a/packages/cli/test/cases/serve.default.ssr-static-export/src/pages/artists.js +++ b/packages/cli/test/cases/serve.default.ssr-static-export/src/pages/artists.js @@ -1,4 +1,4 @@ -async function getTemplate(compilation, route) { +async function getTemplate(compilation, { route }) { return ` diff --git a/packages/cli/test/cases/serve.default.ssr/src/pages/artists.js b/packages/cli/test/cases/serve.default.ssr/src/pages/artists.js index 46a4b4c4d..bc5c1d2a9 100644 --- a/packages/cli/test/cases/serve.default.ssr/src/pages/artists.js +++ b/packages/cli/test/cases/serve.default.ssr/src/pages/artists.js @@ -1,4 +1,4 @@ -async function getTemplate(compilation, route) { +async function getTemplate(compilation, { route }) { return ` @@ -68,7 +68,7 @@ async function getBody(compilation) { `; } -async function getFrontmatter(compilation, route) { +async function getFrontmatter(compilation, { route }) { return { menu: 'navigation', title: route, diff --git a/packages/plugin-renderer-lit/test/cases/serve.default/src/pages/artists.js b/packages/plugin-renderer-lit/test/cases/serve.default/src/pages/artists.js index 76ead4dc6..f6a90b6f2 100644 --- a/packages/plugin-renderer-lit/test/cases/serve.default/src/pages/artists.js +++ b/packages/plugin-renderer-lit/test/cases/serve.default/src/pages/artists.js @@ -3,7 +3,7 @@ import { html } from 'lit'; import { unsafeHTML } from 'lit-html/directives/unsafe-html.js'; import '../components/greeting.js'; -async function getTemplate(compilation, route) { +async function getTemplate(compilation, { route }) { return html` @@ -65,7 +65,7 @@ async function getBody() { `; } -async function getFrontmatter(compilation, route) { +async function getFrontmatter(compilation, { route }) { return { menu: 'navigation', index: 7, From d28f3932f9543cd5bbb247bb055c5fe51d46bcc7 Mon Sep 17 00:00:00 2001 From: Owen Buckley Date: Wed, 7 Jun 2023 22:07:44 -0400 Subject: [PATCH 08/14] update lit renderer per execute module refactoring --- packages/cli/src/lib/templating-utils.js | 2 ++ ...-worker-lit.js => execute-route-module.js} | 20 +++++++------------ packages/plugin-renderer-lit/src/index.js | 2 +- .../cases/serve.default/serve.default.spec.js | 7 +++++-- 4 files changed, 15 insertions(+), 16 deletions(-) rename packages/plugin-renderer-lit/src/{ssr-route-worker-lit.js => execute-route-module.js} (68%) diff --git a/packages/cli/src/lib/templating-utils.js b/packages/cli/src/lib/templating-utils.js index 39486a53e..9adbed1d1 100644 --- a/packages/cli/src/lib/templating-utils.js +++ b/packages/cli/src/lib/templating-utils.js @@ -177,6 +177,8 @@ async function getAppTemplate(pageTemplateContents, context, customImports = [], } async function getUserScripts (contents, context) { + // TODO get rid of lit polyfills in core + // https://github.com/ProjectEvergreen/greenwood/issues/728 // https://lit.dev/docs/tools/requirements/#polyfills if (process.env.__GWD_COMMAND__ === 'build') { // eslint-disable-line no-underscore-dangle const userPackageJson = await getPackageJson(context); diff --git a/packages/plugin-renderer-lit/src/ssr-route-worker-lit.js b/packages/plugin-renderer-lit/src/execute-route-module.js similarity index 68% rename from packages/plugin-renderer-lit/src/ssr-route-worker-lit.js rename to packages/plugin-renderer-lit/src/execute-route-module.js index 4d96c71fa..5e73f7505 100644 --- a/packages/plugin-renderer-lit/src/ssr-route-worker-lit.js +++ b/packages/plugin-renderer-lit/src/execute-route-module.js @@ -4,7 +4,6 @@ import { Buffer } from 'buffer'; import { html } from 'lit'; import { unsafeHTML } from 'lit-html/directives/unsafe-html.js'; import { Readable } from 'stream'; -import { parentPort } from 'worker_threads'; async function streamToString (stream) { const chunks = []; @@ -20,9 +19,7 @@ async function getTemplateResultString(template) { return await streamToString(Readable.from(render(template))); } -async function executeRouteModule({ moduleUrl, compilation, route, label, id, prerender, htmlContents, scripts }) { - const parsedCompilation = JSON.parse(compilation); - const parsedScripts = scripts ? JSON.parse(scripts) : []; +async function executeRouteModule({ moduleUrl, compilation, page, prerender, htmlContents, scripts }) { const data = { template: null, body: null, @@ -30,10 +27,9 @@ async function executeRouteModule({ moduleUrl, compilation, route, label, id, pr html: null }; - console.debug({ moduleUrl }); // prerender static content if (prerender) { - for (const script of parsedScripts) { + for (const script of scripts) { await import(script); } @@ -52,25 +48,23 @@ async function executeRouteModule({ moduleUrl, compilation, route, label, id, pr data.body = await getTemplateResultString(templateResult); } else if (getBody) { - const templateResult = await getBody(parsedCompilation, route); + const templateResult = await getBody(compilation, page); data.body = await getTemplateResultString(templateResult); } if (getTemplate) { - const templateResult = await getTemplate(parsedCompilation, route); + const templateResult = await getTemplate(compilation, page); data.template = await getTemplateResultString(templateResult); } if (getFrontmatter) { - data.frontmatter = await getFrontmatter(parsedCompilation, route, label, id); + data.frontmatter = await getFrontmatter(compilation, page); } } - parentPort.postMessage(data); + return data; } -parentPort.on('message', async (task) => { - await executeRouteModule(task); -}); \ No newline at end of file +export { executeRouteModule }; \ No newline at end of file diff --git a/packages/plugin-renderer-lit/src/index.js b/packages/plugin-renderer-lit/src/index.js index 4c06c0692..e4e190be0 100755 --- a/packages/plugin-renderer-lit/src/index.js +++ b/packages/plugin-renderer-lit/src/index.js @@ -4,7 +4,7 @@ const greenwoodPluginRendererLit = (options = {}) => { name: 'plugin-renderer-lit', provider: () => { return { - workerUrl: new URL('./ssr-route-worker-lit.js', import.meta.url), + executeModuleUrl: new URL('./execute-route-module.js', import.meta.url), prerender: options.prerender }; } diff --git a/packages/plugin-renderer-lit/test/cases/serve.default/serve.default.spec.js b/packages/plugin-renderer-lit/test/cases/serve.default/serve.default.spec.js index e317401de..9a975f336 100644 --- a/packages/plugin-renderer-lit/test/cases/serve.default/serve.default.spec.js +++ b/packages/plugin-renderer-lit/test/cases/serve.default/serve.default.spec.js @@ -203,10 +203,13 @@ describe('Serve Greenwood With: ', function() { expect(styles.length).to.equal(1); }); - it('should have no