wc-compiler 0.4.1 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +2 -2
- package/dist/wcc.dist.cjs +33 -31
- package/package.json +2 -3
- package/src/wcc.js +34 -32
package/README.md
CHANGED
|
@@ -86,6 +86,6 @@ See our [website](https://merry-caramel-524e61.netlify.app/) for API docs and ex
|
|
|
86
86
|
|
|
87
87
|
## Motivation
|
|
88
88
|
|
|
89
|
-
**WCC** is not a static site generator, framework or bundler. It is focused on producing raw HTML from Web Components with the intent of being easily integrated into a site generator or framework, like [**Greenwood**](https://github.com/ProjectEvergreen/greenwood/), the original motivation for creating [this project](https://github.com/ProjectEvergreen/greenwood/issues/935).
|
|
89
|
+
**WCC** is not a static site generator, framework or bundler. It is focused on producing raw HTML from Web Components with the intent of being easily integrated into a site generator or framework, like [**Greenwood**](https://github.com/ProjectEvergreen/greenwood/) or [**Eleventy**](https://github.com/ProjectEvergreen/eleventy-plugin-wcc/), the original motivation for creating [this project](https://github.com/ProjectEvergreen/greenwood/issues/935).
|
|
90
90
|
|
|
91
|
-
In addition, **WCC** hopes to provide a surface area to explore patterns around [streaming](https://github.com/ProjectEvergreen/wcc/issues/5) and serverless rendering, as well as acting as a test bed for the [Web Components Community Groups](https://github.com/webcomponents-cg) discussions around community protocols, like [hydration](https://github.com/ProjectEvergreen/wcc/issues/3).
|
|
91
|
+
In addition, **WCC** hopes to provide a surface area to explore patterns around [streaming](https://github.com/ProjectEvergreen/wcc/issues/5) and serverless rendering, as well as acting as a test bed for the [Web Components Community Groups](https://github.com/webcomponents-cg) discussions around community protocols, like [hydration](https://github.com/ProjectEvergreen/wcc/issues/3).
|
package/dist/wcc.dist.cjs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
var fs = require('fs
|
|
5
|
+
var fs = require('fs');
|
|
6
6
|
|
|
7
7
|
function _interopDefaultLegacy (e) { return e && typeof e === 'object' && 'default' in e ? e : { 'default': e }; }
|
|
8
8
|
|
|
@@ -13957,8 +13957,6 @@ var serialize = function(node, options) {
|
|
|
13957
13957
|
|
|
13958
13958
|
// this must come first
|
|
13959
13959
|
|
|
13960
|
-
let definitions;
|
|
13961
|
-
|
|
13962
13960
|
function getParse(html) {
|
|
13963
13961
|
return html.indexOf('<html>') >= 0 || html.indexOf('<body>') >= 0 || html.indexOf('<head>') >= 0
|
|
13964
13962
|
? parse
|
|
@@ -13973,53 +13971,58 @@ function isCustomElementDefinitionNode(node) {
|
|
|
13973
13971
|
&& expression.callee.property.name === 'define';
|
|
13974
13972
|
}
|
|
13975
13973
|
|
|
13976
|
-
async function renderComponentRoots(tree) {
|
|
13974
|
+
async function renderComponentRoots(tree, definitions) {
|
|
13977
13975
|
for (const node of tree.childNodes) {
|
|
13978
13976
|
if (node.tagName && node.tagName.indexOf('-') > 0) {
|
|
13979
13977
|
const { tagName } = node;
|
|
13980
|
-
const { moduleURL } = definitions[tagName];
|
|
13981
|
-
const elementInstance = await initializeCustomElement(moduleURL, tagName, node.attrs);
|
|
13982
|
-
const elementHtml = elementInstance.shadowRoot
|
|
13983
|
-
? elementInstance.getInnerHTML({ includeShadowRoots: true })
|
|
13984
|
-
: elementInstance.innerHTML;
|
|
13985
|
-
const elementTree = parseFragment(elementHtml);
|
|
13986
13978
|
|
|
13987
|
-
|
|
13988
|
-
|
|
13989
|
-
|
|
13979
|
+
if (definitions[tagName]) {
|
|
13980
|
+
const { moduleURL } = definitions[tagName];
|
|
13981
|
+
const elementInstance = await initializeCustomElement(moduleURL, tagName, node.attrs, definitions);
|
|
13982
|
+
const elementHtml = elementInstance.shadowRoot
|
|
13983
|
+
? elementInstance.getInnerHTML({ includeShadowRoots: true })
|
|
13984
|
+
: elementInstance.innerHTML;
|
|
13985
|
+
const elementTree = parseFragment(elementHtml);
|
|
13986
|
+
|
|
13987
|
+
node.childNodes = node.childNodes.length === 0
|
|
13988
|
+
? elementTree.childNodes
|
|
13989
|
+
: [...elementTree.childNodes, ...node.childNodes];
|
|
13990
|
+
} else {
|
|
13991
|
+
console.warn(`WARNING: customElement <${tagName}> is not defined. You may not have imported it yet.`);
|
|
13992
|
+
}
|
|
13990
13993
|
}
|
|
13991
13994
|
|
|
13992
13995
|
if (node.childNodes && node.childNodes.length > 0) {
|
|
13993
|
-
await renderComponentRoots(node);
|
|
13996
|
+
await renderComponentRoots(node, definitions);
|
|
13994
13997
|
}
|
|
13995
13998
|
|
|
13996
13999
|
// does this only apply to `<template>` tags?
|
|
13997
14000
|
if (node.content && node.content.childNodes && node.content.childNodes.length > 0) {
|
|
13998
|
-
await renderComponentRoots(node.content);
|
|
14001
|
+
await renderComponentRoots(node.content, definitions);
|
|
13999
14002
|
}
|
|
14000
14003
|
}
|
|
14001
14004
|
|
|
14002
14005
|
return tree;
|
|
14003
14006
|
}
|
|
14004
14007
|
|
|
14005
|
-
|
|
14006
|
-
const moduleContents =
|
|
14008
|
+
function registerDependencies(moduleURL, definitions) {
|
|
14009
|
+
const moduleContents = fs__default["default"].readFileSync(moduleURL, 'utf-8');
|
|
14007
14010
|
|
|
14008
14011
|
simple(parse$1(moduleContents, {
|
|
14009
14012
|
ecmaVersion: 'latest',
|
|
14010
14013
|
sourceType: 'module'
|
|
14011
14014
|
}), {
|
|
14012
|
-
|
|
14015
|
+
ImportDeclaration(node) {
|
|
14013
14016
|
const specifier = node.source.value;
|
|
14014
14017
|
const isBareSpecifier = specifier.indexOf('.') !== 0 && specifier.indexOf('/') !== 0;
|
|
14015
14018
|
|
|
14016
14019
|
if (!isBareSpecifier) {
|
|
14017
14020
|
const dependencyModuleURL = new URL(node.source.value, moduleURL);
|
|
14018
14021
|
|
|
14019
|
-
|
|
14022
|
+
registerDependencies(dependencyModuleURL, definitions);
|
|
14020
14023
|
}
|
|
14021
14024
|
},
|
|
14022
|
-
|
|
14025
|
+
ExpressionStatement(node) {
|
|
14023
14026
|
if (isCustomElementDefinitionNode(node)) {
|
|
14024
14027
|
const { arguments: args } = node.expression;
|
|
14025
14028
|
const tagName = args[0].value;
|
|
@@ -14034,14 +14037,14 @@ async function registerDependencies(moduleURL) {
|
|
|
14034
14037
|
}
|
|
14035
14038
|
|
|
14036
14039
|
async function getTagName(moduleURL) {
|
|
14037
|
-
const moduleContents = await fs__default["default"].readFile(moduleURL, 'utf-8');
|
|
14040
|
+
const moduleContents = await fs__default["default"].promises.readFile(moduleURL, 'utf-8');
|
|
14038
14041
|
let tagName;
|
|
14039
14042
|
|
|
14040
14043
|
simple(parse$1(moduleContents, {
|
|
14041
14044
|
ecmaVersion: 'latest',
|
|
14042
14045
|
sourceType: 'module'
|
|
14043
14046
|
}), {
|
|
14044
|
-
|
|
14047
|
+
ExpressionStatement(node) {
|
|
14045
14048
|
if (isCustomElementDefinitionNode(node)) {
|
|
14046
14049
|
|
|
14047
14050
|
tagName = node.expression.arguments[0].value;
|
|
@@ -14052,8 +14055,8 @@ async function getTagName(moduleURL) {
|
|
|
14052
14055
|
return tagName;
|
|
14053
14056
|
}
|
|
14054
14057
|
|
|
14055
|
-
async function initializeCustomElement(elementURL, tagName, attrs = []) {
|
|
14056
|
-
|
|
14058
|
+
async function initializeCustomElement(elementURL, tagName, attrs = [], definitions = []) {
|
|
14059
|
+
registerDependencies(elementURL, definitions);
|
|
14057
14060
|
|
|
14058
14061
|
// https://github.com/ProjectEvergreen/wcc/pull/67/files#r902061804
|
|
14059
14062
|
const { pathname } = elementURL;
|
|
@@ -14078,16 +14081,15 @@ async function initializeCustomElement(elementURL, tagName, attrs = []) {
|
|
|
14078
14081
|
}
|
|
14079
14082
|
|
|
14080
14083
|
async function renderToString(elementURL) {
|
|
14081
|
-
definitions = [];
|
|
14082
|
-
|
|
14084
|
+
const definitions = [];
|
|
14083
14085
|
const elementTagName = await getTagName(elementURL);
|
|
14084
|
-
const elementInstance = await initializeCustomElement(elementURL);
|
|
14086
|
+
const elementInstance = await initializeCustomElement(elementURL, undefined, undefined, definitions);
|
|
14085
14087
|
|
|
14086
14088
|
const elementHtml = elementInstance.shadowRoot
|
|
14087
14089
|
? elementInstance.getInnerHTML({ includeShadowRoots: true })
|
|
14088
14090
|
: elementInstance.innerHTML;
|
|
14089
14091
|
const elementTree = getParse(elementHtml)(elementHtml);
|
|
14090
|
-
const finalTree = await renderComponentRoots(elementTree);
|
|
14092
|
+
const finalTree = await renderComponentRoots(elementTree, definitions);
|
|
14091
14093
|
const html = elementTagName ? `
|
|
14092
14094
|
<${elementTagName}>
|
|
14093
14095
|
${serialize(finalTree)}
|
|
@@ -14102,14 +14104,14 @@ async function renderToString(elementURL) {
|
|
|
14102
14104
|
}
|
|
14103
14105
|
|
|
14104
14106
|
async function renderFromHTML(html, elements = []) {
|
|
14105
|
-
definitions = [];
|
|
14107
|
+
const definitions = [];
|
|
14106
14108
|
|
|
14107
14109
|
for (const url of elements) {
|
|
14108
|
-
await initializeCustomElement(url);
|
|
14110
|
+
await initializeCustomElement(url, undefined, undefined, definitions);
|
|
14109
14111
|
}
|
|
14110
14112
|
|
|
14111
14113
|
const elementTree = getParse(html)(html);
|
|
14112
|
-
const finalTree = await renderComponentRoots(elementTree);
|
|
14114
|
+
const finalTree = await renderComponentRoots(elementTree, definitions);
|
|
14113
14115
|
|
|
14114
14116
|
return {
|
|
14115
14117
|
html: serialize(finalTree),
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "wc-compiler",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.5.0",
|
|
4
4
|
"description": "Experimental native Web Components compiler.",
|
|
5
5
|
"main": "src/wcc.js",
|
|
6
6
|
"type": "module",
|
|
@@ -22,8 +22,6 @@
|
|
|
22
22
|
"develop": "concurrently \"nodemon --watch src --watch docs -e js,md,css,html ./build.js\" \"http-server ./dist --open\"",
|
|
23
23
|
"build": "node ./build.js",
|
|
24
24
|
"serve": "node ./build.js && http-server ./dist --open",
|
|
25
|
-
"example:ssg": "node ./examples/ssg.js",
|
|
26
|
-
"example:ssr": "node ./examples/ssr.js",
|
|
27
25
|
"start": "npm run develop",
|
|
28
26
|
"test": "c8 mocha --parallel",
|
|
29
27
|
"test:tdd": "npm run test --watch",
|
|
@@ -46,6 +44,7 @@
|
|
|
46
44
|
"http-server": "^14.1.0",
|
|
47
45
|
"jsdom": "^19.0.0",
|
|
48
46
|
"mocha": "^9.2.2",
|
|
47
|
+
"node-fetch": "^3.2.6",
|
|
49
48
|
"nodemon": "^2.0.15",
|
|
50
49
|
"prismjs": "^1.28.0",
|
|
51
50
|
"rehype-autolink-headings": "^6.1.1",
|
package/src/wcc.js
CHANGED
|
@@ -4,9 +4,7 @@ import './dom-shim.js';
|
|
|
4
4
|
import * as acorn from 'acorn';
|
|
5
5
|
import * as walk from 'acorn-walk';
|
|
6
6
|
import { parse, parseFragment, serialize } from 'parse5';
|
|
7
|
-
import fs from 'fs
|
|
8
|
-
|
|
9
|
-
let definitions;
|
|
7
|
+
import fs from 'fs';
|
|
10
8
|
|
|
11
9
|
function getParse(html) {
|
|
12
10
|
return html.indexOf('<html>') >= 0 || html.indexOf('<body>') >= 0 || html.indexOf('<head>') >= 0
|
|
@@ -22,53 +20,58 @@ function isCustomElementDefinitionNode(node) {
|
|
|
22
20
|
&& expression.callee.property.name === 'define';
|
|
23
21
|
}
|
|
24
22
|
|
|
25
|
-
async function renderComponentRoots(tree) {
|
|
23
|
+
async function renderComponentRoots(tree, definitions) {
|
|
26
24
|
for (const node of tree.childNodes) {
|
|
27
25
|
if (node.tagName && node.tagName.indexOf('-') > 0) {
|
|
28
26
|
const { tagName } = node;
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
27
|
+
|
|
28
|
+
if (definitions[tagName]) {
|
|
29
|
+
const { moduleURL } = definitions[tagName];
|
|
30
|
+
const elementInstance = await initializeCustomElement(moduleURL, tagName, node.attrs, definitions);
|
|
31
|
+
const elementHtml = elementInstance.shadowRoot
|
|
32
|
+
? elementInstance.getInnerHTML({ includeShadowRoots: true })
|
|
33
|
+
: elementInstance.innerHTML;
|
|
34
|
+
const elementTree = parseFragment(elementHtml);
|
|
35
|
+
|
|
36
|
+
node.childNodes = node.childNodes.length === 0
|
|
37
|
+
? elementTree.childNodes
|
|
38
|
+
: [...elementTree.childNodes, ...node.childNodes];
|
|
39
|
+
} else {
|
|
40
|
+
console.warn(`WARNING: customElement <${tagName}> is not defined. You may not have imported it yet.`);
|
|
41
|
+
}
|
|
39
42
|
}
|
|
40
43
|
|
|
41
44
|
if (node.childNodes && node.childNodes.length > 0) {
|
|
42
|
-
await renderComponentRoots(node);
|
|
45
|
+
await renderComponentRoots(node, definitions);
|
|
43
46
|
}
|
|
44
47
|
|
|
45
48
|
// does this only apply to `<template>` tags?
|
|
46
49
|
if (node.content && node.content.childNodes && node.content.childNodes.length > 0) {
|
|
47
|
-
await renderComponentRoots(node.content);
|
|
50
|
+
await renderComponentRoots(node.content, definitions);
|
|
48
51
|
}
|
|
49
52
|
}
|
|
50
53
|
|
|
51
54
|
return tree;
|
|
52
55
|
}
|
|
53
56
|
|
|
54
|
-
|
|
55
|
-
const moduleContents =
|
|
57
|
+
function registerDependencies(moduleURL, definitions) {
|
|
58
|
+
const moduleContents = fs.readFileSync(moduleURL, 'utf-8');
|
|
56
59
|
|
|
57
60
|
walk.simple(acorn.parse(moduleContents, {
|
|
58
61
|
ecmaVersion: 'latest',
|
|
59
62
|
sourceType: 'module'
|
|
60
63
|
}), {
|
|
61
|
-
|
|
64
|
+
ImportDeclaration(node) {
|
|
62
65
|
const specifier = node.source.value;
|
|
63
66
|
const isBareSpecifier = specifier.indexOf('.') !== 0 && specifier.indexOf('/') !== 0;
|
|
64
67
|
|
|
65
68
|
if (!isBareSpecifier) {
|
|
66
69
|
const dependencyModuleURL = new URL(node.source.value, moduleURL);
|
|
67
70
|
|
|
68
|
-
|
|
71
|
+
registerDependencies(dependencyModuleURL, definitions);
|
|
69
72
|
}
|
|
70
73
|
},
|
|
71
|
-
|
|
74
|
+
ExpressionStatement(node) {
|
|
72
75
|
if (isCustomElementDefinitionNode(node)) {
|
|
73
76
|
const { arguments: args } = node.expression;
|
|
74
77
|
const tagName = args[0].value;
|
|
@@ -83,14 +86,14 @@ async function registerDependencies(moduleURL) {
|
|
|
83
86
|
}
|
|
84
87
|
|
|
85
88
|
async function getTagName(moduleURL) {
|
|
86
|
-
const moduleContents = await fs.readFile(moduleURL, 'utf-8');
|
|
89
|
+
const moduleContents = await fs.promises.readFile(moduleURL, 'utf-8');
|
|
87
90
|
let tagName;
|
|
88
91
|
|
|
89
92
|
walk.simple(acorn.parse(moduleContents, {
|
|
90
93
|
ecmaVersion: 'latest',
|
|
91
94
|
sourceType: 'module'
|
|
92
95
|
}), {
|
|
93
|
-
|
|
96
|
+
ExpressionStatement(node) {
|
|
94
97
|
if (isCustomElementDefinitionNode(node)) {
|
|
95
98
|
|
|
96
99
|
tagName = node.expression.arguments[0].value;
|
|
@@ -101,8 +104,8 @@ async function getTagName(moduleURL) {
|
|
|
101
104
|
return tagName;
|
|
102
105
|
}
|
|
103
106
|
|
|
104
|
-
async function initializeCustomElement(elementURL, tagName, attrs = []) {
|
|
105
|
-
|
|
107
|
+
async function initializeCustomElement(elementURL, tagName, attrs = [], definitions = []) {
|
|
108
|
+
registerDependencies(elementURL, definitions);
|
|
106
109
|
|
|
107
110
|
// https://github.com/ProjectEvergreen/wcc/pull/67/files#r902061804
|
|
108
111
|
const { pathname } = elementURL;
|
|
@@ -127,16 +130,15 @@ async function initializeCustomElement(elementURL, tagName, attrs = []) {
|
|
|
127
130
|
}
|
|
128
131
|
|
|
129
132
|
async function renderToString(elementURL) {
|
|
130
|
-
definitions = [];
|
|
131
|
-
|
|
133
|
+
const definitions = [];
|
|
132
134
|
const elementTagName = await getTagName(elementURL);
|
|
133
|
-
const elementInstance = await initializeCustomElement(elementURL);
|
|
135
|
+
const elementInstance = await initializeCustomElement(elementURL, undefined, undefined, definitions);
|
|
134
136
|
|
|
135
137
|
const elementHtml = elementInstance.shadowRoot
|
|
136
138
|
? elementInstance.getInnerHTML({ includeShadowRoots: true })
|
|
137
139
|
: elementInstance.innerHTML;
|
|
138
140
|
const elementTree = getParse(elementHtml)(elementHtml);
|
|
139
|
-
const finalTree = await renderComponentRoots(elementTree);
|
|
141
|
+
const finalTree = await renderComponentRoots(elementTree, definitions);
|
|
140
142
|
const html = elementTagName ? `
|
|
141
143
|
<${elementTagName}>
|
|
142
144
|
${serialize(finalTree)}
|
|
@@ -151,14 +153,14 @@ async function renderToString(elementURL) {
|
|
|
151
153
|
}
|
|
152
154
|
|
|
153
155
|
async function renderFromHTML(html, elements = []) {
|
|
154
|
-
definitions = [];
|
|
156
|
+
const definitions = [];
|
|
155
157
|
|
|
156
158
|
for (const url of elements) {
|
|
157
|
-
await initializeCustomElement(url);
|
|
159
|
+
await initializeCustomElement(url, undefined, undefined, definitions);
|
|
158
160
|
}
|
|
159
161
|
|
|
160
162
|
const elementTree = getParse(html)(html);
|
|
161
|
-
const finalTree = await renderComponentRoots(elementTree);
|
|
163
|
+
const finalTree = await renderComponentRoots(elementTree, definitions);
|
|
162
164
|
|
|
163
165
|
return {
|
|
164
166
|
html: serialize(finalTree),
|