Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

rfc/issue 955 layouts and pages #1212

Merged
merged 24 commits into from
Jun 22, 2024
Merged
Changes from 1 commit
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
e8c2daf
feature/discussion 1117 Isolation Mode (v1) (#1206)
thescientist13 Mar 10, 2024
a7b464f
enhancement/Issue-1118: Single File Bundles for SSR and API routes (#…
DevLab2425 Mar 10, 2024
0a863c1
v0.30.0-alpha.1
thescientist13 Mar 16, 2024
ae44511
feature/issue 923 native import attributes for CSS and JSON (#1215)
thescientist13 Apr 29, 2024
8b9ed0c
first pass on resource tracking and bundling refactor with lit polyfi…
thescientist13 Dec 26, 2023
2a69b1e
interim work around to solve double rendering and undefined WCC bugs
thescientist13 Dec 27, 2023
cc92114
refactor frontmatter for graph and standard html plugin for SSR
thescientist13 Dec 27, 2023
50ce060
rename templates directory to layouts
thescientist13 Dec 29, 2023
9c04d37
refactor over bundling of static script assets in bundleSsrPages
thescientist13 Dec 31, 2023
c1f7a5d
handle bundling styles within bundleSsrPages
thescientist13 Dec 31, 2023
116e650
post rebase tweaks
thescientist13 Mar 16, 2024
5600d70
custom elements as layouts
thescientist13 May 19, 2024
712f60f
post rebase tweaks
thescientist13 May 19, 2024
a316173
WCC patched support for TS pages
thescientist13 Jun 15, 2024
123ce94
support and tests for API routes as a custom dynamic format
thescientist13 Jun 15, 2024
dd7b9a2
restore TS tests and make servePage default
thescientist13 Jun 16, 2024
84b4bfd
document custom page format support
thescientist13 Jun 16, 2024
335900f
fix lint
thescientist13 Jun 16, 2024
4ae525d
patch latest WCC TypeScript changes
thescientist13 Jun 18, 2024
de67e52
cleanup default app layout content
thescientist13 Jun 20, 2024
1be3fe1
handle rollup circular dependency warnings for API routes
thescientist13 Jun 20, 2024
dc05943
rename test cases from templates to layout
thescientist13 Jun 21, 2024
b997e7d
collapse API routes directory into pages directory
thescientist13 Jun 22, 2024
1b8bbd5
bump to wc-compiler 0.14.0
thescientist13 Jun 22, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
first pass on resource tracking and bundling refactor with lit polyfi…
…lls removal from CLI
  • Loading branch information
thescientist13 committed Jun 2, 2024
commit 8b9ed0cc1998b8a1710cb29d14bf31b70fe9e8fc
64 changes: 1 addition & 63 deletions packages/cli/src/commands/build.js
Original file line number Diff line number Diff line change
@@ -1,70 +1,10 @@
import { bundleCompilation } from '../lifecycles/bundle.js';
import { checkResourceExists, trackResourcesForRoute } from '../lib/resource-utils.js';
import { checkResourceExists } from '../lib/resource-utils.js';
import { copyAssets } from '../lifecycles/copy.js';
import fs from 'fs/promises';
import { preRenderCompilationWorker, preRenderCompilationCustom, staticRenderCompilation } from '../lifecycles/prerender.js';
import { ServerInterface } from '../lib/server-interface.js';

// TODO a lot of these are duplicated in the prerender lifecycle too
// would be good to refactor
async function servePage(url, request, plugins) {
let response = new Response('');

for (const plugin of plugins) {
if (plugin.shouldServe && await plugin.shouldServe(url, request)) {
response = await plugin.serve(url, request);
break;
}
}

return response;
}

async function interceptPage(url, request, plugins, body) {
let response = new Response(body, {
headers: new Headers({ 'Content-Type': 'text/html' })
});

for (const plugin of plugins) {
if (plugin.shouldPreIntercept && await plugin.shouldPreIntercept(url, request, response)) {
response = await plugin.preIntercept(url, request, response);
}

if (plugin.shouldIntercept && await plugin.shouldIntercept(url, request, response)) {
response = await plugin.intercept(url, request, response);
}
}

return response;
}

function getPluginInstances (compilation) {
return [...compilation.config.plugins]
.filter(plugin => plugin.type === 'resource' && plugin.name !== 'plugin-node-modules:resource')
.map((plugin) => {
return plugin.provider(compilation);
});
}

// TODO does this make more sense in bundle lifecycle?
// https://github.com/ProjectEvergreen/greenwood/issues/970
// or could this be done sooner (like in appTemplate building in html resource plugin)?
// Or do we need to ensure userland code / plugins have gone first
async function trackResourcesForRoutes(compilation) {
const plugins = getPluginInstances(compilation);

for (const page of compilation.graph) {
const { route } = page;
const url = new URL(`http://localhost:${compilation.config.port}${route}`);
const request = new Request(url);

let body = await (await servePage(url, request, plugins)).text();
body = await (await interceptPage(url, request, plugins, body)).text();

await trackResourcesForRoute(body, compilation, route);
}
}

const runProductionBuild = async (compilation) => {

return new Promise(async (resolve, reject) => {
@@ -106,13 +46,11 @@ const runProductionBuild = async (compilation) => {
}));

if (prerenderPlugin.executeModuleUrl) {
await trackResourcesForRoutes(compilation);
await preRenderCompilationWorker(compilation, prerenderPlugin);
} else {
await preRenderCompilationCustom(compilation, prerenderPlugin);
}
} else {
await trackResourcesForRoutes(compilation);
await staticRenderCompilation(compilation);
}

14 changes: 12 additions & 2 deletions packages/cli/src/lifecycles/bundle.js
Original file line number Diff line number Diff line change
@@ -3,7 +3,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 { hashString } from '../lib/hashing-utils.js';
import { checkResourceExists, mergeResponse, normalizePathnameForWindows } from '../lib/resource-utils.js';
import { checkResourceExists, mergeResponse, normalizePathnameForWindows, trackResourcesForRoute } from '../lib/resource-utils.js';
import path from 'path';
import { rollup } from 'rollup';

@@ -229,7 +229,6 @@ async function bundleSsrPages(compilation) {
const input = [];

if (!compilation.config.prerender && hasSSRPages) {
const htmlOptimizer = compilation.config.plugins.find(plugin => plugin.name === 'plugin-standard-html').provider(compilation);
const { executeModuleUrl } = compilation.config.plugins.find(plugin => plugin.type === 'renderer').provider();
const { executeRouteModule } = await import(executeModuleUrl);
const { pagesDir, scratchDir } = compilation.context;
@@ -254,6 +253,16 @@ async function bundleSsrPages(compilation) {
staticHtml = await getAppTemplate(staticHtml, compilation.context, imports, [], false, title);
staticHtml = await getUserScripts(staticHtml, compilation);
staticHtml = await (await interceptPage(new URL(`http://localhost:8080${route}`), new Request(new URL(`http://localhost:8080${route}`)), getPluginInstances(compilation), staticHtml)).text();

// track resources first before optimizing, so compilation is correctly set
await trackResourcesForRoute(staticHtml, compilation, route);
// TODO is there a way to avoid running this twice?
// first time we call this, we haven't tracked the resources for SSR pages yet
// so we have to do it again before optimizing
await bundleScriptResources(compilation);

const htmlOptimizer = compilation.config.plugins.find(plugin => plugin.name === 'plugin-standard-html').provider(compilation);

staticHtml = await (await htmlOptimizer.optimize(new URL(`http://localhost:8080${route}`), new Response(staticHtml))).text();
staticHtml = staticHtml.replace(/[`\\$]/g, '\\$&'); // https://stackoverflow.com/a/75688937/417806

@@ -295,6 +304,7 @@ async function bundleSsrPages(compilation) {
const ssrConfigs = await getRollupConfigForSsr(compilation, input);

if (ssrConfigs.length > 0 && ssrConfigs[0].input !== '') {
console.info('bundling dynamic pages...');
for (const configIndex in ssrConfigs) {
const rollupConfig = ssrConfigs[configIndex];
const bundle = await rollup(rollupConfig);
7 changes: 3 additions & 4 deletions packages/cli/src/lifecycles/prerender.js
Original file line number Diff line number Diff line change
@@ -3,8 +3,6 @@ import { checkResourceExists, trackResourcesForRoute } from '../lib/resource-uti
import os from 'os';
import { WorkerPool } from '../lib/threadpool.js';

// TODO a lot of these are duplicated in the build lifecycle too
// would be good to refactor
async function createOutputDirectory(route, outputDir) {
if (!route.endsWith('/404/') && !await checkResourceExists(outputDir)) {
await fs.mkdir(outputDir, {
@@ -62,18 +60,18 @@ async function preRenderCompilationWorker(compilation, 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;
const { route, outputPath } = page;
const outputPathUrl = new URL(`.${outputPath}`, scratchDir);
const url = new URL(`http://localhost:${compilation.config.port}${route}`);
const request = new Request(url);

let body = await (await servePage(url, request, plugins)).text();
body = await (await interceptPage(url, request, plugins, body)).text();

const resources = await trackResourcesForRoute(body, compilation, route);
await createOutputDirectory(route, new URL(outputPathUrl.href.replace('index.html', '')));

const scripts = resources
.map(resource => compilation.resources.get(resource))
.filter(resource => resource.type === 'script')
.map(resource => resource.sourcePathURL.href);

@@ -144,6 +142,7 @@ async function staticRenderCompilation(compilation) {
let body = await (await servePage(url, request, plugins)).text();
body = await (await interceptPage(url, request, plugins, body)).text();

await trackResourcesForRoute(body, compilation, route);
await createOutputDirectory(route, new URL(outputPathUrl.href.replace('index.html', '')));
await fs.writeFile(outputPathUrl, body);

4 changes: 0 additions & 4 deletions packages/cli/src/plugins/resource/plugin-standard-html.js
Original file line number Diff line number Diff line change
@@ -291,10 +291,6 @@ class StandardHtmlResource extends ResourceInterface {
}
}

// TODO clean up lit-polyfill
// https://github.com/ProjectEvergreen/greenwood/issues/728
body = body.replace(/<script src="(.*lit\/polyfill-support.js)"><\/script>/, '');

return new Response(body);
}
}
Original file line number Diff line number Diff line change
@@ -175,7 +175,7 @@ describe('Serve Greenwood With: ', function() {
expect(styles.length).to.equal(1);
});

it('should have four script tags', function() {
it('should have the expected number of script tags', function() {
const scripts = Array.from(dom.window.document.querySelectorAll('head script')).filter(tag => !tag.getAttribute('data-gwd'));

expect(scripts.length).to.equal(3);