Skip to content

Commit

Permalink
feature/issue 1197 Lit v3 upgrade and SSR fixes and enhancements (#1201)
Browse files Browse the repository at this point in the history
* initial upgrade for test cases

* upgrade CLI and www to Lit v3

* revert static router test case change

* all tests passing

* patch escodegen for better ESM support

* test for lit element hydration script

* refactor rollup config

* update Lit renderer README and apply conditional Lit script hydration

* comments and TODOs cleanup

* minor rebase patches

* WCC v0.12.0 upgrade and removing patches directory

* hydration default documentation and testing for Lit renderer plugin
  • Loading branch information
thescientist13 committed Mar 10, 2024
1 parent 55f36b7 commit 82460ea
Show file tree
Hide file tree
Showing 50 changed files with 578 additions and 280 deletions.
4 changes: 3 additions & 1 deletion greenwood.config.js
Expand Up @@ -14,7 +14,9 @@ export default {
interpolateFrontmatter: true,
plugins: [
greenwoodPluginGraphQL(),
greenwoodPluginPolyfills(),
greenwoodPluginPolyfills({
lit: true
}),
greenwoodPluginPostCss(),
greenwoodPluginImportJson(),
greenwoodPluginImportCss(),
Expand Down
2 changes: 1 addition & 1 deletion package.json
Expand Up @@ -30,7 +30,7 @@
"lint": "ls-lint && yarn lint:js && yarn lint:ts && yarn lint:css"
},
"resolutions": {
"lit": "^2.1.1"
"lit": "^3.1.0"
},
"devDependencies": {
"@ls-lint/ls-lint": "^1.10.0",
Expand Down
4 changes: 2 additions & 2 deletions packages/cli/package.json
Expand Up @@ -52,7 +52,7 @@
"remark-rehype": "^7.0.0",
"rollup": "^3.29.4",
"unified": "^9.2.0",
"wc-compiler": "~0.11.0"
"wc-compiler": "~0.12.0"
},
"devDependencies": {
"@babel/runtime": "^7.10.4",
Expand All @@ -62,7 +62,7 @@
"@material/mwc-button": "^0.25.2",
"@stencil/core": "^2.12.0",
"@types/trusted-types": "^2.0.2",
"lit": "^2.0.0",
"lit": "^3.1.0",
"lit-redux-router": "~0.20.0",
"lodash-es": "^4.17.20",
"postcss-nested": "^4.1.2",
Expand Down
36 changes: 11 additions & 25 deletions packages/cli/src/config/rollup.config.js
Expand Up @@ -6,30 +6,11 @@ import commonjs from '@rollup/plugin-commonjs';
import * as walk from 'acorn-walk';

// https://github.com/rollup/rollup/issues/2121
// would be nice to get rid of this
function cleanRollupId(id) {
return id.replace('\x00', '');
}

// specifically to handle escodegen and other node modules
// using require for package.json or other json files
// https://github.com/estools/escodegen/issues/455
function greenwoodJsonLoader() {
return {
name: 'greenwood-json-loader',
async load(id) {
const idUrl = new URL(`file://${cleanRollupId(id)}`);
const extension = idUrl.pathname.split('.').pop();

if (extension === 'json') {
const json = JSON.parse(await fs.promises.readFile(idUrl, 'utf-8'));
const contents = `export default ${JSON.stringify(json)}`;

return contents;
}
}
};
}

function greenwoodResourceLoader (compilation) {
const resourcePlugins = compilation.config.plugins.filter((plugin) => {
return plugin.type === 'resource';
Expand Down Expand Up @@ -373,9 +354,14 @@ const getRollupConfigForApis = async (compilation) => {
chunkFileNames: '[name].[hash].js'
},
plugins: [
greenwoodJsonLoader(),
greenwoodResourceLoader(compilation),
nodeResolve(),
// support node export conditions for API routes
// https://github.com/ProjectEvergreen/greenwood/issues/1118
// https://github.com/rollup/plugins/issues/362#issuecomment-873448461
nodeResolve({
exportConditions: ['node'],
preferBuiltins: true
}),
commonjs(),
greenwoodImportMetaUrl(compilation)
]
Expand All @@ -395,12 +381,12 @@ const getRollupConfigForSsr = async (compilation, input) => {
chunkFileNames: '[name].[hash].js'
},
plugins: [
greenwoodJsonLoader(),
greenwoodResourceLoader(compilation),
// TODO let this through for lit to enable nodeResolve({ preferBuiltins: true })
// https://github.com/lit/lit/issues/449
// support node export conditions for SSR pages
// https://github.com/ProjectEvergreen/greenwood/issues/1118
// https://github.com/rollup/plugins/issues/362#issuecomment-873448461
nodeResolve({
exportConditions: ['node'],
preferBuiltins: true
}),
commonjs(),
Expand Down
3 changes: 2 additions & 1 deletion packages/cli/src/lib/resource-utils.js
Expand Up @@ -124,7 +124,8 @@ async function trackResourcesForRoute(html, compilation, route) {
const scripts = await Promise.all(root.querySelectorAll('script')
.filter(script => (
isLocalLink(script.getAttribute('src')) || script.rawText)
&& script.rawAttrs.indexOf('importmap') < 0)
&& script.rawAttrs.indexOf('importmap') < 0
&& script.getAttribute('type') !== 'application/json')
.map(async(script) => {
const src = script.getAttribute('src');
const optimizationAttr = script.getAttribute('data-gwd-opt');
Expand Down
19 changes: 1 addition & 18 deletions packages/cli/src/lib/templating-utils.js
@@ -1,7 +1,6 @@
import fs from 'fs/promises';
import htmlparser from 'node-html-parser';
import { checkResourceExists } from './resource-utils.js';
import { getPackageJson } from './node-modules-utils.js';

async function getCustomPageTemplatesFromPlugins(contextPlugins, templateName) {
const customTemplateLocations = [];
Expand Down Expand Up @@ -177,7 +176,7 @@ async function getAppTemplate(pageTemplateContents, context, customImports = [],
}

async function getUserScripts (contents, compilation) {
const { context, config } = compilation;
const { config } = compilation;

contents = contents.replace('<head>', `
<head>
Expand All @@ -186,22 +185,6 @@ async function getUserScripts (contents, compilation) {
</script>
`);

// 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);
const dependencies = userPackageJson?.dependencies || {};
const litPolyfill = dependencies && dependencies.lit
? '<script src="/node_modules/lit/polyfill-support.js"></script>\n'
: '';

contents = contents.replace('<head>', `
<head>
${litPolyfill}
`);
}

return contents;
}

Expand Down
23 changes: 23 additions & 0 deletions packages/cli/src/lifecycles/bundle.js
Expand Up @@ -7,6 +7,28 @@ import { checkResourceExists, mergeResponse, normalizePathnameForWindows } from
import path from 'path';
import { rollup } from 'rollup';

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.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);
});
}

async function emitResources(compilation) {
const { outputDir } = compilation.context;
const { resources, graph } = compilation;
Expand Down Expand Up @@ -202,6 +224,7 @@ async function bundleSsrPages(compilation) {
staticHtml = data.template ? data.template : await getPageTemplate(staticHtml, compilation.context, template, []);
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();
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

Expand Down
10 changes: 7 additions & 3 deletions packages/cli/src/lifecycles/graph.js
Expand Up @@ -51,6 +51,7 @@ const generateGraph = async (compilation) => {
let filePath;
let prerender = true;
let isolation = false;
let hydration = false;

/*
* check if additional nested directories exist to correctly determine route (minus filename)
Expand Down Expand Up @@ -132,8 +133,9 @@ const generateGraph = async (compilation) => {
const request = await requestAsObject(new Request(filenameUrl));

worker.on('message', async (result) => {
prerender = result.prerender;
prerender = result.prerender ?? false;
isolation = result.isolation ?? isolation;
hydration = result.hydration ?? hydration;

if (result.frontmatter) {
result.frontmatter.imports = result.frontmatter.imports || [];
Expand Down Expand Up @@ -203,8 +205,9 @@ const generateGraph = async (compilation) => {
* template: page template to use as a base for a generated component
* title: a default value that can be used for <title></title>
* isSSR: if this is a server side route
* prerednder: if this should be statically exported
* prerender: if this should be statically exported
* isolation: if this should be run in isolated mode
* hydration: if this page needs hydration support
*/
pages.push({
data: customData || {},
Expand All @@ -225,7 +228,8 @@ const generateGraph = async (compilation) => {
title,
isSSR: !isStatic,
prerender,
isolation
isolation,
hydration
});
}
}
Expand Down
1 change: 1 addition & 0 deletions packages/cli/src/plugins/resource/plugin-standard-html.js
Expand Up @@ -115,6 +115,7 @@ class StandardHtmlResource extends ResourceInterface {
if (result.template) {
ssrTemplate = result.template;
}

if (result.body) {
ssrBody = result.body;
}
Expand Down
Expand Up @@ -217,9 +217,8 @@ describe('Build Greenwood With: ', function() {
expect(mainScriptTags.length).to.be.equal(1);
});

// TODO clean up lit-polyfill as part of https://github.com/ProjectEvergreen/greenwood/issues/728
it('should have the total expected number of .js file in the output directory', async function() {
expect(await glob.promise(path.join(this.context.publicDir, '*.js'))).to.have.lengthOf(4);
expect(await glob.promise(path.join(this.context.publicDir, '*.js'))).to.have.lengthOf(3);
});

it('should have the expected main.js file in the output directory', async function() {
Expand All @@ -242,7 +241,7 @@ describe('Build Greenwood With: ', function() {
const inlineScriptTag = Array.from(dom.window.document.querySelectorAll('head > script:not([src])')).filter(tag => !tag.getAttribute('data-gwd'))[0];

expect(inlineScriptTag.textContent.replace(/\n/g, '')).to
.equal('import"/116321042.262925e6.js";import"/lit-html.71ac31d8.js";//# sourceMappingURL=116321042.f667a8c7.js.map');
.equal('import"/116321042.4f3171e3.js";import"/lit-html.31ea57aa.js";//# sourceMappingURL=116321042.69f46fc1.js.map');
});
});

Expand Down
Expand Up @@ -2,7 +2,7 @@
"name": "test-import-node-modules",
"type": "module",
"dependencies": {
"lit": "^2.0.0",
"lit": "^3.1.0",
"lodash-es": "^4.17.20",
"prismjs": "^1.21.0",
"pwa-helpers": "^0.9.1",
Expand Down
Expand Up @@ -235,8 +235,7 @@ describe('Build Greenwood With: ', function() {
// one for the footer.js
// one for index.js
// one for lit element bundle
// TODO clean up lit-polyfill as part of https://github.com/ProjectEvergreen/greenwood/issues/728
expect(jsFiles.length).to.be.equal(6);
expect(jsFiles.length).to.be.equal(5);
});

it('should have custom <title> tag in the <head>', function() {
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/test/cases/build.default.spa/package.json
@@ -1,7 +1,7 @@
{
"type": "module",
"dependencies": {
"lit": "^2.0.0",
"lit": "^3.1.0",
"lit-redux-router": "~0.20.0",
"pwa-helpers": "^0.9.1",
"redux": "^4.0.5",
Expand Down
Expand Up @@ -147,11 +147,10 @@ describe('Build Greenwood With: ', function() {
expect(styles.length).to.equal(1);
});

// TODO clean up lit-polyfill as part of https://github.com/ProjectEvergreen/greenwood/issues/728
it('should have four script tags', function() {
const scripts = Array.from(dom.window.document.querySelectorAll('head > script')).filter(tag => !tag.getAttribute('data-gwd'));

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

it('should have expected SSR content from the non module script tag', function() {
Expand Down
@@ -1,6 +1,6 @@
{
"type": "module",
"dependencies": {
"lit": "^2.0.0"
"lit": "^3.1.0"
}
}
Expand Up @@ -101,6 +101,10 @@ describe('Develop Greenwood With: ', function() {
`${process.cwd()}/node_modules/lit/package.json`,
`${outputPath}/node_modules/lit/`
);
const litSsrPackageJson = await getDependencyFiles(
`${process.cwd()}/node_modules/@lit-labs/ssr-dom-shim/package.json`,
`${outputPath}/node_modules/@lit-labs/ssr-dom-shim/`
);
const litElement = await getDependencyFiles(
`${process.cwd()}/node_modules/lit-element/*.js`,
`${outputPath}/node_modules/lit-element/`
Expand Down Expand Up @@ -379,6 +383,7 @@ describe('Develop Greenwood With: ', function() {
...getSetupFiles(outputPath),
...lit,
...litPackageJson,
...litSsrPackageJson,
...litDirectives,
...litDecorators,
...litElementPackageJson,
Expand Down
Expand Up @@ -235,10 +235,6 @@
"lit-html/directives/unsafe-svg.js": "/node_modules/lit-html/directives/unsafe-svg.js",
"lit/directives/unsafe-svg.js": "/node_modules/lit/directives/unsafe-svg.js",
"lit-html/directives/until.js": "/node_modules/lit-html/directives/until.js",
"lit-element/experimental-hydrate-support.js": "/node_modules/lit-element/experimental-hydrate-support.js",
"lit/experimental-hydrate-support.js": "/node_modules/lit/experimental-hydrate-support.js",
"lit-html/experimental-hydrate.js": "/node_modules/lit-html/experimental-hydrate.js",
"lit/experimental-hydrate.js": "/node_modules/lit/experimental-hydrate.js",
"lit/html.js": "/node_modules/lit/html.js",
"lit/polyfill-support.js": "/node_modules/lit/polyfill-support.js",
"lit-html/static.js": "/node_modules/lit-html/static.js",
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/test/cases/develop.default/package.json
Expand Up @@ -8,6 +8,6 @@
"@material/mwc-button": "^0.25.2",
"@stencil/core": "^2.12.0",
"@types/trusted-types": "^2.0.2",
"lit": "^2.0.0"
"lit": "^3.1.0"
}
}
5 changes: 5 additions & 0 deletions packages/cli/test/cases/develop.ssr/develop.ssr.spec.js
Expand Up @@ -64,6 +64,10 @@ describe('Develop Greenwood With: ', function() {
`${process.cwd()}/node_modules/lit/package.json`,
`${outputPath}/node_modules/lit/`
);
const litSsrPackageJson = await getDependencyFiles(
`${process.cwd()}/node_modules/@lit-labs/ssr-dom-shim/package.json`,
`${outputPath}/node_modules/@lit-labs/ssr-dom-shim/`
);
const litElement = await getDependencyFiles(
`${process.cwd()}/node_modules/lit-element/*.js`,
`${outputPath}/node_modules/lit-element/`
Expand Down Expand Up @@ -111,6 +115,7 @@ describe('Develop Greenwood With: ', function() {
...getSetupFiles(outputPath),
...lit,
...litPackageJson,
...litSsrPackageJson,
...litDirectives,
...litDecorators,
...litElementPackageJson,
Expand Down
2 changes: 1 addition & 1 deletion packages/cli/test/cases/develop.ssr/package.json
@@ -1,6 +1,6 @@
{
"type": "module",
"dependencies": {
"lit": "^2.0.0"
"lit": "^3.1.0"
}
}
@@ -1,6 +1,6 @@
{
"type": "module",
"dependencies": {
"lit": "^2.0.0"
"lit": "^3.1.0"
}
}
Expand Up @@ -175,11 +175,10 @@ describe('Serve Greenwood With: ', function() {
expect(styles.length).to.equal(1);
});

// TODO clean up lit-polyfill as part of https://github.com/ProjectEvergreen/greenwood/issues/728
it('should have four script tags', function() {
const scripts = Array.from(dom.window.document.querySelectorAll('head script')).filter(tag => !tag.getAttribute('data-gwd'));

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

it('should have expected SSR content from the non module script tag', function() {
Expand Down

0 comments on commit 82460ea

Please sign in to comment.