Skip to content

Commit

Permalink
patch support for HTML web components with test case
Browse files Browse the repository at this point in the history
  • Loading branch information
thescientist13 committed Sep 28, 2024
1 parent 76ff3a1 commit 05aacd7
Show file tree
Hide file tree
Showing 9 changed files with 415 additions and 3 deletions.
4 changes: 3 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@
"lint:js": "eslint \"*.js\" \"./packages/**/**/*.js\" \"./test/*.js\" \"./www/**/**/*.js\"",
"lint:ts": "eslint \"./packages/**/**/*.ts\"",
"lint:css": "stylelint \"./www/**/*.js\", \"./www/**/*.css\"",
"lint": "ls-lint && yarn lint:js && yarn lint:css"
"lint": "ls-lint && yarn lint:js && yarn lint:css",
"postinstall": "patch-package"
},
"resolutions": {
"lit": "^3.1.0"
Expand All @@ -50,6 +51,7 @@
"jsdom": "^16.5.0",
"lerna": "^3.16.4",
"mocha": "^9.1.3",
"patch-package": "^8.0.0",
"rimraf": "^2.6.3",
"stylelint": "^13.8.0",
"stylelint-a11y": "^1.2.3",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export default {
prerender: true
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
/*
* Use Case
* Run Greenwood and correctly prerender "HTML" Web Components.
*
* User Result
* Should generate a static Greenwood build with the expected prerender "HTML" Web Components content.
*
* User Command
* greenwood build
*
* User Config
*
* {
* prerender: true,
* }
*
* User Workspace
* src/
* components/
* picture-frame.js
* index.html
*/
import chai from 'chai';
import fs from 'fs';

Check failure on line 24 in packages/cli/test/cases/loaders-build.html-web-components/loaders-html-webcomponents.spec.js

View workflow job for this annotation

GitHub Actions / build (18)

'fs' is defined but never used

Check failure on line 24 in packages/cli/test/cases/loaders-build.html-web-components/loaders-html-webcomponents.spec.js

View workflow job for this annotation

GitHub Actions / build (18)

'fs' is defined but never used
import glob from 'glob-promise';

Check failure on line 25 in packages/cli/test/cases/loaders-build.html-web-components/loaders-html-webcomponents.spec.js

View workflow job for this annotation

GitHub Actions / build (18)

'glob' is defined but never used

Check failure on line 25 in packages/cli/test/cases/loaders-build.html-web-components/loaders-html-webcomponents.spec.js

View workflow job for this annotation

GitHub Actions / build (18)

'glob' is defined but never used
import { JSDOM } from 'jsdom';
import path from 'path';
import { runSmokeTest } from '../../../../../test/smoke-test.js';
import { getSetupFiles, getOutputTeardownFiles } from '../../../../../test/utils.js';
import { Runner } from 'gallinago';
import { fileURLToPath, URL } from 'url';

const expect = chai.expect;

describe('Build Greenwood With: ', function() {
const LABEL = 'Prerendering with HTML Web Components';
const cliPath = path.join(process.cwd(), 'packages/cli/src/index.js');
const outputPath = fileURLToPath(new URL('.', import.meta.url));
let runner;

before(function() {
this.context = {
publicDir: path.join(outputPath, 'public')
};
runner = new Runner(false, true);
});

describe(LABEL, function() {
before(function() {
runner.setup(outputPath, getSetupFiles(outputPath));
runner.runCommand(cliPath, 'build');
});

runSmokeTest(['public'], LABEL);

describe('Prerender HTML Web Component', function() {
let dom;
let pictureFrame;

before(async function() {
dom = await JSDOM.fromFile(path.resolve(this.context.publicDir, './index.html'));
pictureFrame = dom.window.document.querySelectorAll('app-picture-frame');
});

it('should not have any <template> tags within the document', function() {
expect(dom.window.document.querySelectorAll('template').length).to.equal(0);
});

Check failure on line 68 in packages/cli/test/cases/loaders-build.html-web-components/loaders-html-webcomponents.spec.js

View workflow job for this annotation

GitHub Actions / build (18)

Trailing spaces not allowed

Check failure on line 68 in packages/cli/test/cases/loaders-build.html-web-components/loaders-html-webcomponents.spec.js

View workflow job for this annotation

GitHub Actions / build (18)

Trailing spaces not allowed
it('should only have one <app-picture-frame> tag', function() {
expect(pictureFrame.length).to.equal(1);
});

Check failure on line 72 in packages/cli/test/cases/loaders-build.html-web-components/loaders-html-webcomponents.spec.js

View workflow job for this annotation

GitHub Actions / build (18)

Trailing spaces not allowed

Check failure on line 72 in packages/cli/test/cases/loaders-build.html-web-components/loaders-html-webcomponents.spec.js

View workflow job for this annotation

GitHub Actions / build (18)

Trailing spaces not allowed
it('should have the expected title attribute content in the heading of HTML', () => {
const heading = pictureFrame[0].querySelectorAll('.picture-frame .heading');

Check failure on line 75 in packages/cli/test/cases/loaders-build.html-web-components/loaders-html-webcomponents.spec.js

View workflow job for this annotation

GitHub Actions / build (18)

Trailing spaces not allowed

Check failure on line 75 in packages/cli/test/cases/loaders-build.html-web-components/loaders-html-webcomponents.spec.js

View workflow job for this annotation

GitHub Actions / build (18)

Trailing spaces not allowed
expect(heading.length).to.equal(1);
expect(heading[0].textContent).to.equal('Greenwood');
});

Check failure on line 79 in packages/cli/test/cases/loaders-build.html-web-components/loaders-html-webcomponents.spec.js

View workflow job for this annotation

GitHub Actions / build (18)

Trailing spaces not allowed

Check failure on line 79 in packages/cli/test/cases/loaders-build.html-web-components/loaders-html-webcomponents.spec.js

View workflow job for this annotation

GitHub Actions / build (18)

Trailing spaces not allowed
it('should have the expected image from userland in the HTML', () => {
const img = pictureFrame[0].querySelectorAll('.picture-frame img');

Check failure on line 82 in packages/cli/test/cases/loaders-build.html-web-components/loaders-html-webcomponents.spec.js

View workflow job for this annotation

GitHub Actions / build (18)

Trailing spaces not allowed

Check failure on line 82 in packages/cli/test/cases/loaders-build.html-web-components/loaders-html-webcomponents.spec.js

View workflow job for this annotation

GitHub Actions / build (18)

Trailing spaces not allowed
expect(img.length).to.equal(1);
expect(img[0].getAttribute('alt')).to.equal('Greenwood logo');
expect(img[0].getAttribute('src')).to.equal('/assets/greenwood.png');
});
});
});

after(function() {
runner.teardown(getOutputTeardownFiles(outputPath));
});

});
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"type": "module"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
export default class PictureFrame extends HTMLElement {
connectedCallback() {
const title = this.getAttribute('title');

this.innerHTML = `
<div class="picture-frame">
<h6 class="heading">${title}</h6>
${this.innerHTML}
</div>
`;
}
}

customElements.define('app-picture-frame', PictureFrame);
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<!DOCTYPE html>
<html lang="en" prefix="og:http://ogp.me/ns#">

<head>
<script type="module" src="./components/picture-frame.js"></script>
</head>

<body>
<app-picture-frame title="Greenwood">
<img src="/assets/greenwood.png" alt="Greenwood logo" />
</app-picture-frame>
</body>

</html>
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
* greenwood build
*
* User Config
* import { greenwoodPluginImportCss } from '@greenwood/plugin-import-css';
*
* {
* prerender: true,
Expand Down
90 changes: 90 additions & 0 deletions patches/wc-compiler+0.14.0.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
diff --git a/node_modules/wc-compiler/src/wcc.js b/node_modules/wc-compiler/src/wcc.js
index 35884d4..e37a4a4 100644
--- a/node_modules/wc-compiler/src/wcc.js
+++ b/node_modules/wc-compiler/src/wcc.js
@@ -32,16 +32,27 @@ async function renderComponentRoots(tree, definitions) {
const { tagName } = node;

if (definitions[tagName]) {
+ console.log('renderComponentRoots', { tagName });
const { moduleURL } = definitions[tagName];
- const elementInstance = await initializeCustomElement(moduleURL, tagName, node.attrs, definitions);
- const elementHtml = elementInstance.shadowRoot
+ console.log({ node });
+ const elementInstance = await initializeCustomElement(moduleURL, tagName, node, definitions);
+ const hasShadow = elementInstance.shadowRoot;
+ const elementHtml = hasShadow
? elementInstance.getInnerHTML({ includeShadowRoots: true })
: elementInstance.innerHTML;
const elementTree = parseFragment(elementHtml);
+ const hasLight = elementTree.childNodes > 0;

- node.childNodes = node.childNodes.length === 0
+ console.log('elementHtml', { elementHtml });
+ console.log('elementTree', { elementTree });
+ console.log('elementTree.childNodes', elementTree.childNodes);
+ console.log('node.childNodes', node.childNodes);
+
+ node.childNodes = node.childNodes.length === 0 && hasLight > 0 && !hasShadow
? elementTree.childNodes
- : [...elementTree.childNodes, ...node.childNodes];
+ : hasShadow
+ ? [...elementTree.childNodes, ...node.childNodes]
+ : elementTree.childNodes;
} else {
console.warn(`WARNING: customElement <${tagName}> is not defined. You may not have imported it yet.`);
}
@@ -138,7 +149,10 @@ async function getTagName(moduleURL) {
return tagName;
}

-async function initializeCustomElement(elementURL, tagName, attrs = [], definitions = [], isEntry, props = {}) {
+async function initializeCustomElement(elementURL, tagName, node = {}, definitions = [], isEntry, props = {}) {
+ const { attrs = [], childNodes = [] } = node;
+ console.log('initializeCustomElement', { node });
+
if (!tagName) {
const depth = isEntry ? 1 : 0;
registerDependencies(elementURL, definitions, depth);
@@ -157,6 +171,41 @@ async function initializeCustomElement(elementURL, tagName, attrs = [], definiti

if (element) {
const elementInstance = new element(data); // eslint-disable-line new-cap
+ let innerHTML = elementInstance.innerHTML || '';
+
+ // TODO
+ // 1. Needs to be recursive
+ // 2. ~~Needs to handle attributes~~
+ // 3. Needs to handle duplicate content
+ // 4. Needs to handle self closing tags
+ // 5. handle all node types
+ childNodes.forEach((child) => {
+ const { nodeName, attrs = [] } = child;
+
+ if (nodeName !== '#text') {
+ innerHTML += `<${nodeName}`;
+
+ if (attrs.length > 0) {
+ attrs.forEach(attr => {
+ innerHTML += ` ${attr.name}="${attr.value}"`;
+ });
+ }
+
+ innerHTML += '>';
+
+ child.childNodes.forEach((c) => {
+ if (c.nodeName === '#text') {
+ innerHTML += c.value;
+ }
+ });
+
+ innerHTML += `</${nodeName}>`;
+ }
+ });
+
+ console.log({ innerHTML });
+ elementInstance.innerHTML = innerHTML;
+ console.log('=================');

attrs.forEach((attr) => {
elementInstance.setAttribute(attr.name, attr.value);
Loading

0 comments on commit 05aacd7

Please sign in to comment.