From 3ad95abe1e6868322924edc1a68639299b0d7969 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Tue, 15 Nov 2022 16:31:32 +0100 Subject: [PATCH 01/14] Create initial html file --- .gitignore | 3 ++- package-lock.json | 6 +++++ package.json | 1 + performance/generate-html.mjs | 43 +++++++++++++++++++++++++++++++++++ src/runtime/index.js | 4 +++- 5 files changed, 55 insertions(+), 2 deletions(-) create mode 100644 performance/generate-html.mjs diff --git a/.gitignore b/.gitignore index b7dab5e9..2bf8bbf0 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules -build \ No newline at end of file +build +test.html \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index d70f9c5a..b4e23058 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1350,6 +1350,12 @@ } } }, + "@faker-js/faker": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-7.6.0.tgz", + "integrity": "sha512-XK6BTq1NDMo9Xqw/YkYyGjSsg44fbNwYRx7QK2CuoQgyy+f1rrTDHoExVM5PsyXCtfl2vs2vVJ0MN0yN6LppRw==", + "dev": true + }, "@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", diff --git a/package.json b/package.json index d0c60e63..70b11c76 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "devDependencies": { "@babel/core": "^7.17.10", "@babel/preset-env": "^7.17.10", + "@faker-js/faker": "^7.6.0", "@prettier/plugin-php": "^0.18.9", "@types/jest": "^27.5.1", "@wordpress/env": "^4.4.0", diff --git a/performance/generate-html.mjs b/performance/generate-html.mjs new file mode 100644 index 00000000..d549faee --- /dev/null +++ b/performance/generate-html.mjs @@ -0,0 +1,43 @@ +import { faker } from '@faker-js/faker'; +import { format } from 'prettier'; +import { writeFileSync } from 'fs'; + +const createDivs = (maxDepth) => { + let div = ''; + + for (let i = 0; i < maxDepth; i++) { + div += `

${faker.lorem.word(10)}

+

${faker.lorem.paragraph(10)}

+

${faker.lorem.paragraph(20)}

+ ${i % 5 === 0 ? `` : ''}`; + } + + for (let i = 0; i < maxDepth; i++) { + div += `
`; + } + return div; +}; + +let html = ` + + + Performance Test + + `; + +for (let i = 0; i < 100; i++) { + html += createDivs(20); +} + +const end = ` + + + + +`; + +html += end; + +writeFileSync('performance/test.html', format(html, { parser: 'html' })); diff --git a/src/runtime/index.js b/src/runtime/index.js index e89ac9d4..b9fa9ba5 100644 --- a/src/runtime/index.js +++ b/src/runtime/index.js @@ -6,8 +6,10 @@ import { init } from './router'; * Initialize the initial vDOM. */ document.addEventListener('DOMContentLoaded', async () => { + const t0 = performance.now(); registerDirectives(); registerComponents(); await init(); - console.log('hydrated!'); + const t1 = performance.now(); + console.log(`hydrated in ${t1 - t0} ms`); }); From 41f86366a6a29b165608fbe303f562c91aa97d6b Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Wed, 16 Nov 2022 18:10:51 +0100 Subject: [PATCH 02/14] Add TreeWalker and perf comparisons --- package-lock.json | 5 +++ package.json | 1 + performance/generate-html.mjs | 7 ++-- src/runtime/index.js | 3 -- src/runtime/router.js | 42 ++++++++++++++++++++--- src/runtime/vdom.js | 63 ++++++++++++++++++++++++++++++++--- 6 files changed, 105 insertions(+), 16 deletions(-) diff --git a/package-lock.json b/package-lock.json index b4e23058..8d1048db 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6141,6 +6141,11 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "deep-object-diff": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/deep-object-diff/-/deep-object-diff-1.1.9.tgz", + "integrity": "sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA==" + }, "deepmerge": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", diff --git a/package.json b/package.json index 70b11c76..343d274a 100644 --- a/package.json +++ b/package.json @@ -39,6 +39,7 @@ }, "dependencies": { "@preact/signals": "^1.1.2", + "deep-object-diff": "^1.1.9", "hpq": "^1.3.0", "preact": "^10.10.6" } diff --git a/performance/generate-html.mjs b/performance/generate-html.mjs index d549faee..490b60b2 100644 --- a/performance/generate-html.mjs +++ b/performance/generate-html.mjs @@ -21,19 +21,20 @@ const createDivs = (maxDepth) => { }; let html = ` + Performance Test + + `; for (let i = 0; i < 100; i++) { - html += createDivs(20); + html += createDivs(10); } const end = ` - - `; diff --git a/src/runtime/index.js b/src/runtime/index.js index b9fa9ba5..fec5b815 100644 --- a/src/runtime/index.js +++ b/src/runtime/index.js @@ -6,10 +6,7 @@ import { init } from './router'; * Initialize the initial vDOM. */ document.addEventListener('DOMContentLoaded', async () => { - const t0 = performance.now(); registerDirectives(); registerComponents(); await init(); - const t1 = performance.now(); - console.log(`hydrated in ${t1 - t0} ms`); }); diff --git a/src/runtime/router.js b/src/runtime/router.js index 94c6f659..409d54e6 100644 --- a/src/runtime/router.js +++ b/src/runtime/router.js @@ -1,6 +1,7 @@ import { hydrate, render } from 'preact'; -import toVdom from './vdom'; +import { toVdomArray, toVdomTreeWalker } from './vdom'; import { createRootFragment } from './utils'; +import { diff } from 'deep-object-diff'; // The root to render the vdom (document.body). let rootFragment; @@ -94,13 +95,44 @@ window.addEventListener('popstate', async () => { // Initialize the router with the initial DOM. export const init = async () => { - // Create the root fragment to hydrate everything. + // Number of nodes. + const nodeIterator = document.createNodeIterator( + document.body, + NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT + ); + let node = nodeIterator.referenceNode; + let count = 0; + while (node) { + count++; + node = nodeIterator.nextNode(); + } + console.log(`Number of DOM nodes: ${count}`); + + // toVdom + const t0 = performance.now(); + const vdom1 = toVdomArray(document.body); + const t1 = performance.now(); + console.log(`vdom using array created in ${t1 - t0} ms`); + + // treeWalker + const t2 = performance.now(); + const vdom2 = toVdomTreeWalker(document.body); + const t3 = performance.now(); + console.log(`vdom using treeWalker created in ${t3 - t2} ms`); + + // console.log(`Diff:`, diff(vdom1, vdom2)); + rootFragment = createRootFragment(document.documentElement, document.body); - const body = toVdom(document.body); - hydrate(body, rootFragment); + const t4 = performance.now(); + hydrate(vdom2, rootFragment); + const t5 = performance.now(); + console.log(`hydrated in ${t5 - t4} ms`); if (hasClientSideTransitions(document.head)) { const head = await fetchHead(document.head); - pages.set(cleanUrl(window.location), Promise.resolve({ body, head })); + pages.set( + cleanUrl(window.location), + Promise.resolve({ body: vdom1, head }) + ); } }; diff --git a/src/runtime/vdom.js b/src/runtime/vdom.js index 18849cfc..03fe9313 100644 --- a/src/runtime/vdom.js +++ b/src/runtime/vdom.js @@ -1,14 +1,15 @@ import { h } from 'preact'; // Recursive function that transfoms a DOM tree into vDOM. -export default function toVdom(node) { +export function toVdomArray(node) { + if (node.nodeType === 3) return node.data; + const props = {}; const { attributes, childNodes } = node; + const children = []; const wpDirectives = {}; let hasWpDirectives = false; - if (node.nodeType === 3) return node.data; - for (let i = 0; i < attributes.length; i++) { const name = attributes[i].name; if (name.startsWith('wp-')) { @@ -27,16 +28,68 @@ export default function toVdom(node) { if (hasWpDirectives) props.wp = wpDirectives; - const children = []; for (let i = 0; i < childNodes.length; i++) { const child = childNodes[i]; if (child.nodeType === 8) { child.remove(); i--; } else { - children.push(toVdom(child)); + children.push(toVdomArray(child)); } } return h(node.localName, props, children); } + +export function toVdomTreeWalker(node) { + const treeWalker = document.createTreeWalker( + node, + NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT + NodeFilter.SHOW_COMMENT + ); + + function walk(node) { + if (node.nodeType === 3) return node.data; + if (node.nodeType === 8) { + node.remove(); + return null; + } + + const props = {}; + const attributes = node.attributes; + const children = []; + const wpDirectives = {}; + let hasWpDirectives = false; + + for (let i = 0; i < attributes.length; i++) { + const name = attributes[i].name; + if (name.startsWith('wp-')) { + hasWpDirectives = true; + let val = attributes[i].value; + try { + val = JSON.parse(val); + } catch (e) {} + const [, prefix, suffix] = /wp-([^:]+):?(.*)$/.exec(name); + wpDirectives[prefix] = wpDirectives[prefix] || {}; + wpDirectives[prefix][suffix || 'default'] = val; + } else { + props[name] = attributes[i].value; + } + } + + if (hasWpDirectives) props.wp = wpDirectives; + + let child = treeWalker.firstChild(); + if (child) { + while (child) { + const vnode = walk(child); + if (vnode) children.push(vnode); + child = treeWalker.nextSibling(); + } + treeWalker.parentNode(); + } + + return h(node.localName, props, children); + } + + return walk(treeWalker.currentNode); +} From b2b71476ec6fcd01fc947751037e3f9413090ee4 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Thu, 19 Jan 2023 18:26:02 +0100 Subject: [PATCH 03/14] Remove deep-diff --- package-lock.json | 5 ----- package.json | 1 - 2 files changed, 6 deletions(-) diff --git a/package-lock.json b/package-lock.json index 7a219c7b..4669246c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6159,11 +6159,6 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, - "deep-object-diff": { - "version": "1.1.9", - "resolved": "https://registry.npmjs.org/deep-object-diff/-/deep-object-diff-1.1.9.tgz", - "integrity": "sha512-Rn+RuwkmkDwCi2/oXOFS9Gsr5lJZu/yTGpK7wAaAIE75CC+LCGEZHpY6VQJa/RoJcrmaA/docWJZvYohlNkWPA==" - }, "deepmerge": { "version": "4.2.2", "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.2.2.tgz", diff --git a/package.json b/package.json index 0a4c5748..bb7fe451 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,6 @@ "@wordpress/env": "^4.4.0", "@wordpress/scripts": "^24.3.0", "babel-jest": "^28.1.0", - "deep-object-diff": "^1.1.9", "jest": "^28.1.0", "prettier": "^2.7.1" }, From 933d65a6b8c66cc09a0b03d6f1da0184badb75f2 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Thu, 19 Jan 2023 18:26:11 +0100 Subject: [PATCH 04/14] Remove old toVdom --- src/runtime/router.js | 43 +--------------- src/runtime/vdom.js | 117 +++++++++++++++--------------------------- 2 files changed, 43 insertions(+), 117 deletions(-) diff --git a/src/runtime/router.js b/src/runtime/router.js index 360752b2..39852809 100644 --- a/src/runtime/router.js +++ b/src/runtime/router.js @@ -1,7 +1,6 @@ import { hydrate, render } from 'preact'; -import { toVdomArray, toVdomTreeWalker, hydratedIslands } from './vdom'; +import { toVdom, hydratedIslands } from './vdom'; import { createRootFragment } from './utils'; -import { diff } from 'deep-object-diff'; // The root to render the vdom (document.body). let rootFragment; @@ -95,54 +94,16 @@ window.addEventListener('popstate', async () => { // Initialize the router with the initial DOM. export const init = async () => { - // Number of nodes. - const nodeIterator = document.createNodeIterator( - document.body, - NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT - ); - let node = nodeIterator.referenceNode; - let count = 0; - while (node) { - count++; - node = nodeIterator.nextNode(); - } - console.log(`Number of DOM nodes: ${count}`); - - // toVdom - const t0 = performance.now(); - const vdom1 = toVdomArray(document.body); - const t1 = performance.now(); - console.log(`vdom using array created in ${t1 - t0} ms`); - - // treeWalker - const t2 = performance.now(); - const vdom2 = toVdomTreeWalker(document.body); - const t3 = performance.now(); - console.log(`vdom using treeWalker created in ${t3 - t2} ms`); - - // console.log(`Diff:`, diff(vdom1, vdom2)); - - rootFragment = createRootFragment(document.documentElement, document.body); - const t4 = performance.now(); - hydrate(vdom2, rootFragment); - const t5 = performance.now(); - console.log(`hydrated in ${t5 - t4} ms`); - if (hasClientSideTransitions(document.head)) { // Create the root fragment to hydrate everything. rootFragment = createRootFragment( document.documentElement, document.body ); - const body = toVdom(document.body); hydrate(body, rootFragment); - const head = await fetchHead(document.head); - pages.set( - cleanUrl(window.location), - Promise.resolve({ body: vdom1, head }) - ); + pages.set(cleanUrl(window.location), Promise.resolve({ body, head })); } else { document.querySelectorAll('[wp-island]').forEach((node) => { if (!hydratedIslands.has(node)) { diff --git a/src/runtime/vdom.js b/src/runtime/vdom.js index 1ddf0979..3ef080d7 100644 --- a/src/runtime/vdom.js +++ b/src/runtime/vdom.js @@ -3,101 +3,66 @@ import { h } from 'preact'; export const hydratedIslands = new WeakSet(); // Recursive function that transfoms a DOM tree into vDOM. -export function toVdomArray(node) { - const props = {}; - const { attributes, childNodes } = node; - const children = []; - const wpDirectives = {}; - let hasWpDirectives = false; - let ignore = false; - let island = false; - - if (node.nodeType === 3) return node.data; - if (node.nodeType === 4) { - node.replaceWith(new Text(node.nodeValue)); - return node.nodeValue; - } - - for (let i = 0; i < attributes.length; i++) { - const n = attributes[i].name; - if (n[0] === 'w' && n[1] === 'p' && n[2] === '-' && n[3]) { - if (n === 'wp-ignore') { - ignore = true; - } else if (n === 'wp-island') { - island = true; - } else { - hasWpDirectives = true; - let val = attributes[i].value; - try { - val = JSON.parse(val); - } catch (e) {} - const [, prefix, suffix] = /wp-([^:]+):?(.*)$/.exec(n); - wpDirectives[prefix] = wpDirectives[prefix] || {}; - wpDirectives[prefix][suffix || 'default'] = val; - } - } else if (n === 'ref') { - continue; - } else { - props[n] = attributes[i].value; - } - } - - if (ignore && !island) - return h(node.localName, { - dangerouslySetInnerHTML: { __html: node.innerHTML }, - }); - if (island) hydratedIslands.add(node); - - if (hasWpDirectives) props.wp = wpDirectives; - - for (let i = 0; i < childNodes.length; i++) { - const child = childNodes[i]; - if (child.nodeType === 8 || child.nodeType === 7) { - child.remove(); - i--; - } else { - children.push(toVdomArray(child)); - } - } - - return h(node.localName, props, children); -} - -export function toVdomTreeWalker(node) { +export function toVdom(node) { const treeWalker = document.createTreeWalker( node, - NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT + NodeFilter.SHOW_COMMENT + NodeFilter.SHOW_ELEMENT + + NodeFilter.SHOW_TEXT + + NodeFilter.SHOW_COMMENT + + NodeFilter.SHOW_CDATA_SECTION + + NodeFilter.SHOW_PROCESSING_INSTRUCTION ); function walk(node) { - if (node.nodeType === 3) return node.data; - if (node.nodeType === 8) { + const { attributes, nodeType } = node; + + if (nodeType === 3) return node.data; + if (nodeType === 4) { + node.replaceWith(new Text(node.nodeValue)); + return node.nodeValue; + } + if (nodeType === 8 || nodeType === 7) { node.remove(); return null; } const props = {}; - const attributes = node.attributes; const children = []; const wpDirectives = {}; let hasWpDirectives = false; + let ignore = false; + let island = false; for (let i = 0; i < attributes.length; i++) { - const name = attributes[i].name; - if (name.startsWith('wp-')) { - hasWpDirectives = true; - let val = attributes[i].value; - try { - val = JSON.parse(val); - } catch (e) {} - const [, prefix, suffix] = /wp-([^:]+):?(.*)$/.exec(name); - wpDirectives[prefix] = wpDirectives[prefix] || {}; - wpDirectives[prefix][suffix || 'default'] = val; + const n = attributes[i].name; + if (n[0] === 'w' && n[1] === 'p' && n[2] === '-' && n[3]) { + if (n === 'wp-ignore') { + ignore = true; + } else if (n === 'wp-island') { + island = true; + } else { + hasWpDirectives = true; + let val = attributes[i].value; + try { + val = JSON.parse(val); + } catch (e) {} + const [, prefix, suffix] = /wp-([^:]+):?(.*)$/.exec(n); + wpDirectives[prefix] = wpDirectives[prefix] || {}; + wpDirectives[prefix][suffix || 'default'] = val; + } + } else if (n === 'ref') { + continue; } else { - props[name] = attributes[i].value; + props[n] = attributes[i].value; } } + if (ignore && !island) + return h(node.localName, { + dangerouslySetInnerHTML: { __html: node.innerHTML }, + }); + if (island) hydratedIslands.add(node); + if (hasWpDirectives) props.wp = wpDirectives; let child = treeWalker.firstChild(); From ba3c0aa8ba01f63a2a32716d97c768b3d3fd9b80 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Mon, 23 Jan 2023 15:47:25 +0100 Subject: [PATCH 05/14] HTML for comments, cdata and processing instruction tests --- e2e/tovdom.html | 62 +++++++++++++++++++++++++++++++++++++++++++++ e2e/tovdom.spec.ts | 15 +++++++++++ src/runtime/vdom.js | 1 + 3 files changed, 78 insertions(+) create mode 100644 e2e/tovdom.html create mode 100644 e2e/tovdom.spec.ts diff --git a/e2e/tovdom.html b/e2e/tovdom.html new file mode 100644 index 00000000..fce4eebb --- /dev/null +++ b/e2e/tovdom.html @@ -0,0 +1,62 @@ + + + + toVdom + + +
+ +
+ +
+
+ +
+
+
+ +
+
+
+ + + + + + + + + + diff --git a/e2e/tovdom.spec.ts b/e2e/tovdom.spec.ts new file mode 100644 index 00000000..6b4c7020 --- /dev/null +++ b/e2e/tovdom.spec.ts @@ -0,0 +1,15 @@ +import { join } from 'path'; +import { test, expect } from '@playwright/test'; + +test.describe('toVdom', () => { + test.beforeEach(async ({ page }) => { + await page.goto('file://' + join(__dirname, 'tovdom.html')); + }); + + test('it should delete comments', async ({ page }) => { + const el = page.getByTestId('it should delete comments'); + const c = await el.innerHTML(); + await expect(el.innerHTML()).toContain('##1##'); + await expect(el.innerHTML()).toContain('##2##'); + }); +}); diff --git a/src/runtime/vdom.js b/src/runtime/vdom.js index 3ef080d7..5ceffec4 100644 --- a/src/runtime/vdom.js +++ b/src/runtime/vdom.js @@ -6,6 +6,7 @@ export const hydratedIslands = new WeakSet(); export function toVdom(node) { const treeWalker = document.createTreeWalker( node, + // 205 NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT + NodeFilter.SHOW_COMMENT + From 5055dacd4956fee32355f077a993f6b6cb875ece Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Wed, 1 Feb 2023 18:31:31 +0100 Subject: [PATCH 06/14] Add e2e tests with old algorithm first (wip) --- e2e/tovdom.html | 60 ++++++++++++---------- e2e/tovdom.spec.ts | 19 ++++++- src/runtime/vdom-ctw.js | 83 ++++++++++++++++++++++++++++++ src/runtime/vdom.js | 111 +++++++++++++++++----------------------- 4 files changed, 178 insertions(+), 95 deletions(-) create mode 100644 src/runtime/vdom-ctw.js diff --git a/e2e/tovdom.html b/e2e/tovdom.html index fce4eebb..ed9c14c7 100644 --- a/e2e/tovdom.html +++ b/e2e/tovdom.html @@ -2,59 +2,63 @@ toVdom + +
-
+
+ Comments inner node
-
+
-
-
-
- - - + + + + diff --git a/e2e/tovdom.spec.ts b/e2e/tovdom.spec.ts index 6b4c7020..fc5cc41d 100644 --- a/e2e/tovdom.spec.ts +++ b/e2e/tovdom.spec.ts @@ -9,7 +9,22 @@ test.describe('toVdom', () => { test('it should delete comments', async ({ page }) => { const el = page.getByTestId('it should delete comments'); const c = await el.innerHTML(); - await expect(el.innerHTML()).toContain('##1##'); - await expect(el.innerHTML()).toContain('##2##'); + expect(c).not.toContain('##1##'); + expect(c).not.toContain('##2##'); + const el2 = page.getByTestId( + 'it should keep this node between comments' + ); + await expect(el2).toBeVisible(); + }); + + test('it should delete processing instructions', async ({ page }) => { + const el = page.getByTestId('it should delete processing instructions'); + const c = await el.innerHTML(); + expect(c).not.toContain('##1##'); + expect(c).not.toContain('##2##'); + const el2 = page.getByTestId( + 'it should keep this node between processing instructions' + ); + await expect(el2).toBeVisible(); }); }); diff --git a/src/runtime/vdom-ctw.js b/src/runtime/vdom-ctw.js new file mode 100644 index 00000000..5ceffec4 --- /dev/null +++ b/src/runtime/vdom-ctw.js @@ -0,0 +1,83 @@ +import { h } from 'preact'; + +export const hydratedIslands = new WeakSet(); + +// Recursive function that transfoms a DOM tree into vDOM. +export function toVdom(node) { + const treeWalker = document.createTreeWalker( + node, + // 205 + NodeFilter.SHOW_ELEMENT + + NodeFilter.SHOW_TEXT + + NodeFilter.SHOW_COMMENT + + NodeFilter.SHOW_CDATA_SECTION + + NodeFilter.SHOW_PROCESSING_INSTRUCTION + ); + + function walk(node) { + const { attributes, nodeType } = node; + + if (nodeType === 3) return node.data; + if (nodeType === 4) { + node.replaceWith(new Text(node.nodeValue)); + return node.nodeValue; + } + if (nodeType === 8 || nodeType === 7) { + node.remove(); + return null; + } + + const props = {}; + const children = []; + const wpDirectives = {}; + let hasWpDirectives = false; + let ignore = false; + let island = false; + + for (let i = 0; i < attributes.length; i++) { + const n = attributes[i].name; + if (n[0] === 'w' && n[1] === 'p' && n[2] === '-' && n[3]) { + if (n === 'wp-ignore') { + ignore = true; + } else if (n === 'wp-island') { + island = true; + } else { + hasWpDirectives = true; + let val = attributes[i].value; + try { + val = JSON.parse(val); + } catch (e) {} + const [, prefix, suffix] = /wp-([^:]+):?(.*)$/.exec(n); + wpDirectives[prefix] = wpDirectives[prefix] || {}; + wpDirectives[prefix][suffix || 'default'] = val; + } + } else if (n === 'ref') { + continue; + } else { + props[n] = attributes[i].value; + } + } + + if (ignore && !island) + return h(node.localName, { + dangerouslySetInnerHTML: { __html: node.innerHTML }, + }); + if (island) hydratedIslands.add(node); + + if (hasWpDirectives) props.wp = wpDirectives; + + let child = treeWalker.firstChild(); + if (child) { + while (child) { + const vnode = walk(child); + if (vnode) children.push(vnode); + child = treeWalker.nextSibling(); + } + treeWalker.parentNode(); + } + + return h(node.localName, props, children); + } + + return walk(treeWalker.currentNode); +} diff --git a/src/runtime/vdom.js b/src/runtime/vdom.js index 5ceffec4..754146ce 100644 --- a/src/runtime/vdom.js +++ b/src/runtime/vdom.js @@ -4,80 +4,61 @@ export const hydratedIslands = new WeakSet(); // Recursive function that transfoms a DOM tree into vDOM. export function toVdom(node) { - const treeWalker = document.createTreeWalker( - node, - // 205 - NodeFilter.SHOW_ELEMENT + - NodeFilter.SHOW_TEXT + - NodeFilter.SHOW_COMMENT + - NodeFilter.SHOW_CDATA_SECTION + - NodeFilter.SHOW_PROCESSING_INSTRUCTION - ); + const props = {}; + const { attributes, childNodes } = node; + const wpDirectives = {}; + let hasWpDirectives = false; + let ignore = false; + let island = false; - function walk(node) { - const { attributes, nodeType } = node; - - if (nodeType === 3) return node.data; - if (nodeType === 4) { - node.replaceWith(new Text(node.nodeValue)); - return node.nodeValue; - } - if (nodeType === 8 || nodeType === 7) { - node.remove(); - return null; - } - - const props = {}; - const children = []; - const wpDirectives = {}; - let hasWpDirectives = false; - let ignore = false; - let island = false; + if (node.nodeType === 3) return node.data; + if (node.nodeType === 4) { + node.replaceWith(new Text(node.nodeValue)); + return node.nodeValue; + } - for (let i = 0; i < attributes.length; i++) { - const n = attributes[i].name; - if (n[0] === 'w' && n[1] === 'p' && n[2] === '-' && n[3]) { - if (n === 'wp-ignore') { - ignore = true; - } else if (n === 'wp-island') { - island = true; - } else { - hasWpDirectives = true; - let val = attributes[i].value; - try { - val = JSON.parse(val); - } catch (e) {} - const [, prefix, suffix] = /wp-([^:]+):?(.*)$/.exec(n); - wpDirectives[prefix] = wpDirectives[prefix] || {}; - wpDirectives[prefix][suffix || 'default'] = val; - } - } else if (n === 'ref') { - continue; + for (let i = 0; i < attributes.length; i++) { + const n = attributes[i].name; + if (n[0] === 'w' && n[1] === 'p' && n[2] === '-' && n[3]) { + if (n === 'wp-ignore') { + ignore = true; + } else if (n === 'wp-island') { + island = true; } else { - props[n] = attributes[i].value; + hasWpDirectives = true; + let val = attributes[i].value; + try { + val = JSON.parse(val); + } catch (e) {} + const [, prefix, suffix] = /wp-([^:]+):?(.*)$/.exec(n); + wpDirectives[prefix] = wpDirectives[prefix] || {}; + wpDirectives[prefix][suffix || 'default'] = val; } + } else if (n === 'ref') { + continue; + } else { + props[n] = attributes[i].value; } + } - if (ignore && !island) - return h(node.localName, { - dangerouslySetInnerHTML: { __html: node.innerHTML }, - }); - if (island) hydratedIslands.add(node); + if (ignore && !island) + return h(node.localName, { + dangerouslySetInnerHTML: { __html: node.innerHTML }, + }); + if (island) hydratedIslands.add(node); - if (hasWpDirectives) props.wp = wpDirectives; + if (hasWpDirectives) props.wp = wpDirectives; - let child = treeWalker.firstChild(); - if (child) { - while (child) { - const vnode = walk(child); - if (vnode) children.push(vnode); - child = treeWalker.nextSibling(); - } - treeWalker.parentNode(); + const children = []; + for (let i = 0; i < childNodes.length; i++) { + const child = childNodes[i]; + if (child.nodeType === 8 || child.nodeType === 7) { + child.remove(); + i--; + } else { + children.push(toVdom(child)); } - - return h(node.localName, props, children); } - return walk(treeWalker.currentNode); + return h(node.localName, props, children); } From dde5ea1f6229e01e6e16ad4c5edc3b5794a8b5e1 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Tue, 18 Apr 2023 15:44:18 +0200 Subject: [PATCH 07/14] Update e2e tests and files --- e2e/html/directive-bind.html | 2 +- e2e/{ => html}/tovdom.html | 8 +++----- e2e/{html => js}/directive-bind.js | 1 - e2e/js/tovdom.js | 3 +++ e2e/{ => specs}/tovdom.spec.ts | 7 +++---- src/runtime/index.js | 1 + webpack.config.js | 3 ++- 7 files changed, 13 insertions(+), 12 deletions(-) rename e2e/{ => html}/tovdom.html (87%) rename e2e/{html => js}/directive-bind.js (85%) create mode 100644 e2e/js/tovdom.js rename e2e/{ => specs}/tovdom.spec.ts (81%) diff --git a/e2e/html/directive-bind.html b/e2e/html/directive-bind.html index 98dc7025..09f4734f 100644 --- a/e2e/html/directive-bind.html +++ b/e2e/html/directive-bind.html @@ -33,7 +33,7 @@ Update - + diff --git a/e2e/tovdom.html b/e2e/html/tovdom.html similarity index 87% rename from e2e/tovdom.html rename to e2e/html/tovdom.html index ed9c14c7..b51e554c 100644 --- a/e2e/tovdom.html +++ b/e2e/html/tovdom.html @@ -2,10 +2,9 @@ toVdom - - +
@@ -59,8 +58,7 @@ .replaceWith(cdataElement); --> - - - + + diff --git a/e2e/html/directive-bind.js b/e2e/js/directive-bind.js similarity index 85% rename from e2e/html/directive-bind.js rename to e2e/js/directive-bind.js index ec68a2c8..e872452b 100644 --- a/e2e/html/directive-bind.js +++ b/e2e/js/directive-bind.js @@ -1,6 +1,5 @@ import { store } from '../../src/runtime/store'; -// State for the store hydration tests. store({ state: { url: '/some-url', diff --git a/e2e/js/tovdom.js b/e2e/js/tovdom.js new file mode 100644 index 00000000..5420171a --- /dev/null +++ b/e2e/js/tovdom.js @@ -0,0 +1,3 @@ +import { store } from '../../src/runtime/store'; + +store({}); diff --git a/e2e/tovdom.spec.ts b/e2e/specs/tovdom.spec.ts similarity index 81% rename from e2e/tovdom.spec.ts rename to e2e/specs/tovdom.spec.ts index fc5cc41d..5bc47294 100644 --- a/e2e/tovdom.spec.ts +++ b/e2e/specs/tovdom.spec.ts @@ -1,9 +1,8 @@ -import { join } from 'path'; -import { test, expect } from '@playwright/test'; +import { test, expect } from '../tests'; test.describe('toVdom', () => { - test.beforeEach(async ({ page }) => { - await page.goto('file://' + join(__dirname, 'tovdom.html')); + test.beforeEach(async ({ goToFile }) => { + await goToFile('tovdom.html'); }); test('it should delete comments', async ({ page }) => { diff --git a/src/runtime/index.js b/src/runtime/index.js index 58caa14b..683f1a16 100644 --- a/src/runtime/index.js +++ b/src/runtime/index.js @@ -11,4 +11,5 @@ document.addEventListener('DOMContentLoaded', async () => { registerDirectives(); registerComponents(); await init(); + console.log('Interactivity API started'); }); diff --git a/webpack.config.js b/webpack.config.js index 0747f183..0658c1cb 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -10,7 +10,8 @@ module.exports = [ runtime: './src/runtime', 'e2e/page-1': './e2e/page-1', 'e2e/page-2': './e2e/page-2', - 'e2e/html/directive-bind': './e2e/html/directive-bind', + 'e2e/directive-bind': './e2e/js/directive-bind', + 'e2e/tovdom': './e2e/js/tovdom', }, output: { filename: '[name].js', From 4dea135c8bb9f9d5322afa35a6ce88b72c3a0326 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Tue, 18 Apr 2023 15:56:16 +0200 Subject: [PATCH 08/14] Add CDATA e2e test --- e2e/html/tovdom.html | 8 ++++---- e2e/specs/tovdom.spec.ts | 9 +++++++++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/e2e/html/tovdom.html b/e2e/html/tovdom.html index b51e554c..dfdb7cf2 100644 --- a/e2e/html/tovdom.html +++ b/e2e/html/tovdom.html @@ -36,11 +36,11 @@ .replaceWith(processingInstructionsElement); - +
- + diff --git a/e2e/specs/tovdom.spec.ts b/e2e/specs/tovdom.spec.ts index 5bc47294..4322eea2 100644 --- a/e2e/specs/tovdom.spec.ts +++ b/e2e/specs/tovdom.spec.ts @@ -26,4 +26,13 @@ test.describe('toVdom', () => { ); await expect(el2).toBeVisible(); }); + + test('it should replace CDATA with text nodes', async ({ page }) => { + const el = page.getByTestId('it should replace CDATA with text nodes'); + const c = await el.innerHTML(); + expect(c).toContain('##1##'); + expect(c).toContain('##2##'); + const el2 = page.getByTestId('it should keep this node between CDATA'); + await expect(el2).toBeVisible(); + }); }); From b4898eace9b8c43b273895fed94e8458c31dd80c Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Tue, 18 Apr 2023 17:15:25 +0200 Subject: [PATCH 09/14] All tests but CDATA --- src/runtime/vdom-ctw.js | 40 ++++++++++++++++++++++++++-------------- 1 file changed, 26 insertions(+), 14 deletions(-) diff --git a/src/runtime/vdom-ctw.js b/src/runtime/vdom-ctw.js index 5ceffec4..9ef19163 100644 --- a/src/runtime/vdom-ctw.js +++ b/src/runtime/vdom-ctw.js @@ -1,4 +1,9 @@ import { h } from 'preact'; +import { directivePrefix as p } from './constants'; + +const ignoreAttr = `${p}ignore`; +const islandAttr = `${p}island`; +const directiveParser = new RegExp(`${p}([^.]+)\.?(.*)$`); export const hydratedIslands = new WeakSet(); @@ -23,33 +28,32 @@ export function toVdom(node) { return node.nodeValue; } if (nodeType === 8 || nodeType === 7) { - node.remove(); return null; } const props = {}; const children = []; - const wpDirectives = {}; - let hasWpDirectives = false; + const directives = {}; + let hasDirectives = false; let ignore = false; let island = false; for (let i = 0; i < attributes.length; i++) { const n = attributes[i].name; - if (n[0] === 'w' && n[1] === 'p' && n[2] === '-' && n[3]) { - if (n === 'wp-ignore') { + if (n[p.length] && n.slice(0, p.length) === p) { + if (n === ignoreAttr) { ignore = true; - } else if (n === 'wp-island') { + } else if (n === islandAttr) { island = true; } else { - hasWpDirectives = true; + hasDirectives = true; let val = attributes[i].value; try { val = JSON.parse(val); } catch (e) {} - const [, prefix, suffix] = /wp-([^:]+):?(.*)$/.exec(n); - wpDirectives[prefix] = wpDirectives[prefix] || {}; - wpDirectives[prefix][suffix || 'default'] = val; + const [, prefix, suffix] = directiveParser.exec(n); + directives[prefix] = directives[prefix] || {}; + directives[prefix][suffix || 'default'] = val; } } else if (n === 'ref') { continue; @@ -60,18 +64,26 @@ export function toVdom(node) { if (ignore && !island) return h(node.localName, { - dangerouslySetInnerHTML: { __html: node.innerHTML }, + ...props, + innerHTML: node.innerHTML, + directives: { ignore: true }, }); if (island) hydratedIslands.add(node); - if (hasWpDirectives) props.wp = wpDirectives; + if (hasDirectives) props.directives = directives; let child = treeWalker.firstChild(); if (child) { while (child) { const vnode = walk(child); - if (vnode) children.push(vnode); - child = treeWalker.nextSibling(); + if (vnode) { + children.push(vnode); + child = treeWalker.nextSibling(); + } else { + const prevChild = child; + child = treeWalker.nextSibling(); + prevChild.remove(); + } } treeWalker.parentNode(); } From 000f562cbda56545fc8d325c233338d19a45a669 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Tue, 18 Apr 2023 17:30:13 +0200 Subject: [PATCH 10/14] Fix last test --- src/runtime/vdom-ctw.js | 39 +++++++++++++++++++-------------------- 1 file changed, 19 insertions(+), 20 deletions(-) diff --git a/src/runtime/vdom-ctw.js b/src/runtime/vdom-ctw.js index 9ef19163..10fbcd30 100644 --- a/src/runtime/vdom-ctw.js +++ b/src/runtime/vdom-ctw.js @@ -8,9 +8,9 @@ const directiveParser = new RegExp(`${p}([^.]+)\.?(.*)$`); export const hydratedIslands = new WeakSet(); // Recursive function that transfoms a DOM tree into vDOM. -export function toVdom(node) { +export function toVdom(root) { const treeWalker = document.createTreeWalker( - node, + root, // 205 NodeFilter.SHOW_ELEMENT + NodeFilter.SHOW_TEXT + @@ -22,13 +22,16 @@ export function toVdom(node) { function walk(node) { const { attributes, nodeType } = node; - if (nodeType === 3) return node.data; + if (nodeType === 3) return [node.data]; if (nodeType === 4) { + const next = treeWalker.nextSibling(); node.replaceWith(new Text(node.nodeValue)); - return node.nodeValue; + return [node.nodeValue, next]; } if (nodeType === 8 || nodeType === 7) { - return null; + const next = treeWalker.nextSibling(); + node.remove(); + return [null, next]; } const props = {}; @@ -63,11 +66,13 @@ export function toVdom(node) { } if (ignore && !island) - return h(node.localName, { - ...props, - innerHTML: node.innerHTML, - directives: { ignore: true }, - }); + return [ + h(node.localName, { + ...props, + innerHTML: node.innerHTML, + directives: { ignore: true }, + }), + ]; if (island) hydratedIslands.add(node); if (hasDirectives) props.directives = directives; @@ -75,20 +80,14 @@ export function toVdom(node) { let child = treeWalker.firstChild(); if (child) { while (child) { - const vnode = walk(child); - if (vnode) { - children.push(vnode); - child = treeWalker.nextSibling(); - } else { - const prevChild = child; - child = treeWalker.nextSibling(); - prevChild.remove(); - } + const [vnode, nextChild] = walk(child); + if (vnode) children.push(vnode); + child = nextChild || treeWalker.nextSibling(); } treeWalker.parentNode(); } - return h(node.localName, props, children); + return [h(node.localName, props, children)]; } return walk(treeWalker.currentNode); From 04f8acaaa8ffdcf3ea79a0ea810462b0da4c90e4 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Tue, 18 Apr 2023 17:31:16 +0200 Subject: [PATCH 11/14] Rename vdom files and remove the old one --- src/runtime/vdom-ctw.js | 94 ------------------------------- src/runtime/vdom.js | 121 ++++++++++++++++++++++++---------------- 2 files changed, 72 insertions(+), 143 deletions(-) delete mode 100644 src/runtime/vdom-ctw.js diff --git a/src/runtime/vdom-ctw.js b/src/runtime/vdom-ctw.js deleted file mode 100644 index 10fbcd30..00000000 --- a/src/runtime/vdom-ctw.js +++ /dev/null @@ -1,94 +0,0 @@ -import { h } from 'preact'; -import { directivePrefix as p } from './constants'; - -const ignoreAttr = `${p}ignore`; -const islandAttr = `${p}island`; -const directiveParser = new RegExp(`${p}([^.]+)\.?(.*)$`); - -export const hydratedIslands = new WeakSet(); - -// Recursive function that transfoms a DOM tree into vDOM. -export function toVdom(root) { - const treeWalker = document.createTreeWalker( - root, - // 205 - NodeFilter.SHOW_ELEMENT + - NodeFilter.SHOW_TEXT + - NodeFilter.SHOW_COMMENT + - NodeFilter.SHOW_CDATA_SECTION + - NodeFilter.SHOW_PROCESSING_INSTRUCTION - ); - - function walk(node) { - const { attributes, nodeType } = node; - - if (nodeType === 3) return [node.data]; - if (nodeType === 4) { - const next = treeWalker.nextSibling(); - node.replaceWith(new Text(node.nodeValue)); - return [node.nodeValue, next]; - } - if (nodeType === 8 || nodeType === 7) { - const next = treeWalker.nextSibling(); - node.remove(); - return [null, next]; - } - - const props = {}; - const children = []; - const directives = {}; - let hasDirectives = false; - let ignore = false; - let island = false; - - for (let i = 0; i < attributes.length; i++) { - const n = attributes[i].name; - if (n[p.length] && n.slice(0, p.length) === p) { - if (n === ignoreAttr) { - ignore = true; - } else if (n === islandAttr) { - island = true; - } else { - hasDirectives = true; - let val = attributes[i].value; - try { - val = JSON.parse(val); - } catch (e) {} - const [, prefix, suffix] = directiveParser.exec(n); - directives[prefix] = directives[prefix] || {}; - directives[prefix][suffix || 'default'] = val; - } - } else if (n === 'ref') { - continue; - } else { - props[n] = attributes[i].value; - } - } - - if (ignore && !island) - return [ - h(node.localName, { - ...props, - innerHTML: node.innerHTML, - directives: { ignore: true }, - }), - ]; - if (island) hydratedIslands.add(node); - - if (hasDirectives) props.directives = directives; - - let child = treeWalker.firstChild(); - if (child) { - while (child) { - const [vnode, nextChild] = walk(child); - if (vnode) children.push(vnode); - child = nextChild || treeWalker.nextSibling(); - } - treeWalker.parentNode(); - } - - return [h(node.localName, props, children)]; - } - - return walk(treeWalker.currentNode); -} diff --git a/src/runtime/vdom.js b/src/runtime/vdom.js index f1cd5442..10fbcd30 100644 --- a/src/runtime/vdom.js +++ b/src/runtime/vdom.js @@ -8,64 +8,87 @@ const directiveParser = new RegExp(`${p}([^.]+)\.?(.*)$`); export const hydratedIslands = new WeakSet(); // Recursive function that transfoms a DOM tree into vDOM. -export function toVdom(node) { - const props = {}; - const { attributes, childNodes } = node; - const directives = {}; - let hasDirectives = false; - let ignore = false; - let island = false; +export function toVdom(root) { + const treeWalker = document.createTreeWalker( + root, + // 205 + NodeFilter.SHOW_ELEMENT + + NodeFilter.SHOW_TEXT + + NodeFilter.SHOW_COMMENT + + NodeFilter.SHOW_CDATA_SECTION + + NodeFilter.SHOW_PROCESSING_INSTRUCTION + ); - if (node.nodeType === 3) return node.data; - if (node.nodeType === 4) { - node.replaceWith(new Text(node.nodeValue)); - return node.nodeValue; - } + function walk(node) { + const { attributes, nodeType } = node; + + if (nodeType === 3) return [node.data]; + if (nodeType === 4) { + const next = treeWalker.nextSibling(); + node.replaceWith(new Text(node.nodeValue)); + return [node.nodeValue, next]; + } + if (nodeType === 8 || nodeType === 7) { + const next = treeWalker.nextSibling(); + node.remove(); + return [null, next]; + } - for (let i = 0; i < attributes.length; i++) { - const n = attributes[i].name; - if (n[p.length] && n.slice(0, p.length) === p) { - if (n === ignoreAttr) { - ignore = true; - } else if (n === islandAttr) { - island = true; + const props = {}; + const children = []; + const directives = {}; + let hasDirectives = false; + let ignore = false; + let island = false; + + for (let i = 0; i < attributes.length; i++) { + const n = attributes[i].name; + if (n[p.length] && n.slice(0, p.length) === p) { + if (n === ignoreAttr) { + ignore = true; + } else if (n === islandAttr) { + island = true; + } else { + hasDirectives = true; + let val = attributes[i].value; + try { + val = JSON.parse(val); + } catch (e) {} + const [, prefix, suffix] = directiveParser.exec(n); + directives[prefix] = directives[prefix] || {}; + directives[prefix][suffix || 'default'] = val; + } + } else if (n === 'ref') { + continue; } else { - hasDirectives = true; - let val = attributes[i].value; - try { - val = JSON.parse(val); - } catch (e) {} - const [, prefix, suffix] = directiveParser.exec(n); - directives[prefix] = directives[prefix] || {}; - directives[prefix][suffix || 'default'] = val; + props[n] = attributes[i].value; } - } else if (n === 'ref') { - continue; - } else { - props[n] = attributes[i].value; } - } - if (ignore && !island) - return h(node.localName, { - ...props, - innerHTML: node.innerHTML, - directives: { ignore: true }, - }); - if (island) hydratedIslands.add(node); + if (ignore && !island) + return [ + h(node.localName, { + ...props, + innerHTML: node.innerHTML, + directives: { ignore: true }, + }), + ]; + if (island) hydratedIslands.add(node); - if (hasDirectives) props.directives = directives; + if (hasDirectives) props.directives = directives; - const children = []; - for (let i = 0; i < childNodes.length; i++) { - const child = childNodes[i]; - if (child.nodeType === 8 || child.nodeType === 7) { - child.remove(); - i--; - } else { - children.push(toVdom(child)); + let child = treeWalker.firstChild(); + if (child) { + while (child) { + const [vnode, nextChild] = walk(child); + if (vnode) children.push(vnode); + child = nextChild || treeWalker.nextSibling(); + } + treeWalker.parentNode(); } + + return [h(node.localName, props, children)]; } - return h(node.localName, props, children); + return walk(treeWalker.currentNode); } From 64d8922f303846b587afb87303abe65315960b33 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Tue, 18 Apr 2023 17:45:17 +0200 Subject: [PATCH 12/14] Remove performance related files --- package-lock.json | 6 ----- package.json | 1 - performance/generate-html.mjs | 44 ----------------------------------- 3 files changed, 51 deletions(-) delete mode 100644 performance/generate-html.mjs diff --git a/package-lock.json b/package-lock.json index 328699a8..7ab294ee 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1350,12 +1350,6 @@ } } }, - "@faker-js/faker": { - "version": "7.6.0", - "resolved": "https://registry.npmjs.org/@faker-js/faker/-/faker-7.6.0.tgz", - "integrity": "sha512-XK6BTq1NDMo9Xqw/YkYyGjSsg44fbNwYRx7QK2CuoQgyy+f1rrTDHoExVM5PsyXCtfl2vs2vVJ0MN0yN6LppRw==", - "dev": true - }, "@hapi/hoek": { "version": "9.3.0", "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", diff --git a/package.json b/package.json index 95c3b68d..27411dba 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,6 @@ "devDependencies": { "@babel/core": "^7.17.10", "@babel/preset-env": "^7.17.10", - "@faker-js/faker": "^7.6.0", "@playwright/test": "^1.29.0", "@types/jest": "^27.5.1", "@wordpress/env": "^5.8.0", diff --git a/performance/generate-html.mjs b/performance/generate-html.mjs deleted file mode 100644 index 490b60b2..00000000 --- a/performance/generate-html.mjs +++ /dev/null @@ -1,44 +0,0 @@ -import { faker } from '@faker-js/faker'; -import { format } from 'prettier'; -import { writeFileSync } from 'fs'; - -const createDivs = (maxDepth) => { - let div = ''; - - for (let i = 0; i < maxDepth; i++) { - div += `

${faker.lorem.word(10)}

-

${faker.lorem.paragraph(10)}

-

${faker.lorem.paragraph(20)}

- ${i % 5 === 0 ? `` : ''}`; - } - - for (let i = 0; i < maxDepth; i++) { - div += `
`; - } - return div; -}; - -let html = ` - - - - Performance Test - - - - `; - -for (let i = 0; i < 100; i++) { - html += createDivs(10); -} - -const end = ` - - -`; - -html += end; - -writeFileSync('performance/test.html', format(html, { parser: 'html' })); From ddf8ae2196c31e7689c37f1b0c864f9003dcfc26 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Tue, 18 Apr 2023 17:45:51 +0200 Subject: [PATCH 13/14] Remove unnecessary gitignore file --- .gitignore | 1 - 1 file changed, 1 deletion(-) diff --git a/.gitignore b/.gitignore index 42cb636c..64186685 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,6 @@ .DS_Store node_modules build -test.html vendor composer.lock /test-results/ From 065bdb7f8671b2cbfd08305776536615dc4acb09 Mon Sep 17 00:00:00 2001 From: Luis Herranz Date: Tue, 18 Apr 2023 18:03:13 +0200 Subject: [PATCH 14/14] Small final adjustments --- e2e/js/tovdom.js | 3 --- src/runtime/index.js | 2 +- src/runtime/vdom.js | 7 +------ webpack.config.js | 1 - 4 files changed, 2 insertions(+), 11 deletions(-) delete mode 100644 e2e/js/tovdom.js diff --git a/e2e/js/tovdom.js b/e2e/js/tovdom.js deleted file mode 100644 index 5420171a..00000000 --- a/e2e/js/tovdom.js +++ /dev/null @@ -1,3 +0,0 @@ -import { store } from '../../src/runtime/store'; - -store({}); diff --git a/src/runtime/index.js b/src/runtime/index.js index 683f1a16..e32495dc 100644 --- a/src/runtime/index.js +++ b/src/runtime/index.js @@ -5,7 +5,7 @@ export { store } from './store'; export { navigate } from './router'; /** - * Initialize the initial vDOM. + * Initialize the Interactivity API. */ document.addEventListener('DOMContentLoaded', async () => { registerDirectives(); diff --git a/src/runtime/vdom.js b/src/runtime/vdom.js index 10fbcd30..69a13f77 100644 --- a/src/runtime/vdom.js +++ b/src/runtime/vdom.js @@ -11,12 +11,7 @@ export const hydratedIslands = new WeakSet(); export function toVdom(root) { const treeWalker = document.createTreeWalker( root, - // 205 - NodeFilter.SHOW_ELEMENT + - NodeFilter.SHOW_TEXT + - NodeFilter.SHOW_COMMENT + - NodeFilter.SHOW_CDATA_SECTION + - NodeFilter.SHOW_PROCESSING_INSTRUCTION + 205 // ELEMENT + TEXT + COMMENT + CDATA_SECTION + PROCESSING_INSTRUCTION ); function walk(node) { diff --git a/webpack.config.js b/webpack.config.js index 0658c1cb..d3b84f2e 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -11,7 +11,6 @@ module.exports = [ 'e2e/page-1': './e2e/page-1', 'e2e/page-2': './e2e/page-2', 'e2e/directive-bind': './e2e/js/directive-bind', - 'e2e/tovdom': './e2e/js/tovdom', }, output: { filename: '[name].js',