Skip to content

Commit 2a12ad3

Browse files
Merge pull request #328 from preactjs/shared-renderer
2 parents d9ba339 + 0bd0098 commit 2a12ad3

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

61 files changed

+3060
-1687
lines changed

.github/workflows/nodejs.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,6 @@ jobs:
2121
yarn
2222
yarn lint
2323
yarn test
24-
yarn test-e2e --repeat-flaky 3
24+
PREACT_VERSION=10 yarn test-e2e --repeat-flaky 3
2525
env:
2626
CI: true

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,3 +78,6 @@ test-e2e/fixtures/extension
7878
# Browser profiles
7979
profiles/firefox/*
8080
profiles/chrome/*
81+
82+
# macOS
83+
.DS_Store

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
"lint": "eslint 'src/**/*.{ts,tsx}' 'test-e2e/**/*.ts'",
1818
"test": "mochette -c tsconfig.cjs.json 'src/**/*.test.{ts,tsx}'",
1919
"test-e2e": "node tools/fetch-preact-versions.js && cross-env TS_NODE_PROJECT=tsconfig.cjs.json ts-node test-e2e/run.ts --default-timeout 5000",
20+
"test-e2e:10": "PREACT_VERSION=10 npm run test-e2e",
21+
"test-e2e:all": "npm run test-e2e && npm run test-e2e:10",
2022
"dev": "npm run dev:serve",
2123
"dev:serve": "vite test-e2e/fixtures --port 8100",
2224
"dev:legacy": "webpack-dev-server --inline",
@@ -84,7 +86,7 @@
8486
"ts-loader": "^8.0.4",
8587
"ts-node": "^9.0.0",
8688
"typescript": "^4.2.3",
87-
"vite": "^2.3.3",
89+
"vite": "^2.7.13",
8890
"web-ext": "^6.4.0",
8991
"webpack": "^5.4.0",
9092
"webpack-cli": "^4.2.0",

src/adapter/10/IdMapper.ts

Lines changed: 0 additions & 76 deletions
This file was deleted.
Lines changed: 89 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,12 @@
1-
import { RendererConfig10 } from "./renderer";
2-
import { HookType } from "../../constants";
3-
1+
import { HookType } from "../shared/hooks";
42
import type { Component, VNode } from "preact";
53
import type {
64
Component as IComponent,
75
VNode as IVNode,
86
} from "preact/src/internal";
9-
10-
// These hook types are declared in "preact/hooks/src/internal" but not very
11-
// complete, so for now loosely declare locally.
12-
type ComponentHooks = Record<string, any>;
13-
type HookState = Record<string, any>;
7+
import { ComponentHooks, HookState, PreactBindings } from "../shared/bindings";
8+
import { RendererConfig } from "../shared/renderer";
9+
import { getRenderReasonPost } from "./renderReason";
1410

1511
// Mangle accessors
1612

@@ -30,7 +26,7 @@ export function getVNodeParent(vnode: VNode): VNode | null {
3026
/**
3127
* Check if a `vnode` is the root of a tree
3228
*/
33-
export function isRoot(vnode: VNode, config: RendererConfig10): boolean {
29+
export function isRoot(vnode: VNode, config: RendererConfig): boolean {
3430
return getVNodeParent(vnode) == null && vnode.type === config.Fragment;
3531
}
3632

@@ -64,12 +60,14 @@ export function isSuspenseVNode(vnode: VNode): boolean {
6460
/**
6561
* Get the internal hooks state of a component
6662
*/
67-
export function getComponentHooks(c: Component): ComponentHooks | null {
63+
export function getComponentHooks(vnode: VNode): ComponentHooks | null {
64+
const c = getComponent(vnode);
65+
if (!c) return null;
6866
return (c as any).__hooks || (c as any).__H || null;
6967
}
7068

71-
export function getStatefulHooks(c: Component): HookState[] | null {
72-
const hooks = getComponentHooks(c);
69+
export function getStatefulHooks(vnode: VNode): HookState[] | null {
70+
const hooks = getComponentHooks(vnode);
7371
return hooks !== null
7472
? hooks._list ||
7573
hooks.__ ||
@@ -94,11 +92,14 @@ export function getStatefulHookValue(hookState: HookState): unknown {
9492
}
9593

9694
export function getHookState(
97-
c: Component,
95+
vnode: VNode,
9896
index: number,
9997
type?: HookType,
10098
): unknown {
101-
const list = getStatefulHooks(c);
99+
const c = getComponent(vnode);
100+
if (c === null) return null;
101+
102+
const list = getStatefulHooks(vnode);
102103
if (list && list[index]) {
103104
// useContext
104105
if (type === HookType.useContext) {
@@ -136,7 +137,7 @@ export function getActualChildren(
136137
/**
137138
* Get the root of a `vnode`
138139
*/
139-
export function findRoot(vnode: VNode, config: RendererConfig10): VNode {
140+
export function findRoot(vnode: VNode, config: RendererConfig): VNode {
140141
let next: VNode | null = vnode;
141142
while ((next = getVNodeParent(next)) != null) {
142143
if (isRoot(next, config)) {
@@ -162,7 +163,7 @@ export function getAncestor(vnode: VNode): VNode | null {
162163
/**
163164
* Get human readable name of the component/dom element
164165
*/
165-
export function getDisplayName(vnode: VNode, config: RendererConfig10): string {
166+
export function getDisplayName(vnode: VNode, config: RendererConfig): string {
166167
const { type } = vnode;
167168
if (type === config.Fragment) return "Fragment";
168169
else if (typeof type === "function") {
@@ -218,7 +219,7 @@ export function setNextState<S>(c: Component, value: S): S {
218219
return ((c as IComponent)._nextState = (c as any).__s = value);
219220
}
220221

221-
export function getSuspenseStateKey(c: Component<any, any>) {
222+
function getSuspenseStateKey(c: Component<any, any>) {
222223
if ("_suspended" in c.state) {
223224
return "_suspended";
224225
} else if ("__e" in c.state) {
@@ -235,6 +236,22 @@ export function getSuspenseStateKey(c: Component<any, any>) {
235236
return null;
236237
}
237238

239+
export function getSuspendedState(vnode: VNode) {
240+
const c = getComponent(vnode);
241+
if (c) {
242+
const key = getSuspenseStateKey(c);
243+
if (key) {
244+
return !!(c as any)._nextState[key];
245+
}
246+
}
247+
248+
return null;
249+
}
250+
251+
export function isTextVNode(vnode: VNode) {
252+
return vnode !== null && vnode.type === null;
253+
}
254+
238255
export function createSuspenseState(vnode: VNode, suspended: boolean) {
239256
const c = getComponent(vnode) as Component<any, any>;
240257
const key = getSuspenseStateKey(c);
@@ -244,3 +261,58 @@ export function createSuspenseState(vnode: VNode, suspended: boolean) {
244261

245262
return {};
246263
}
264+
265+
export function getInstance(vnode: VNode): any {
266+
// For components we use the instance to check refs, otherwise
267+
// we'll use a dom node
268+
if (typeof vnode.type === "function") {
269+
return getComponent(vnode);
270+
}
271+
272+
return getDom(vnode);
273+
}
274+
275+
export function isComponent(vnode: VNode) {
276+
return vnode !== null && typeof vnode.type === "function";
277+
}
278+
279+
export function isVNode(x: any): x is VNode {
280+
return x != null && x.type !== undefined && hasDom(x);
281+
}
282+
283+
export function isElement(vnode: VNode): boolean {
284+
return typeof vnode.type === "string";
285+
}
286+
287+
// eslint-disable-next-line @typescript-eslint/no-unused-vars
288+
export function isPortal(vnode: VNode) {
289+
// TODO: Find a way to detect portals
290+
return false;
291+
}
292+
293+
export const bindingsV10: PreactBindings<VNode> = {
294+
isRoot,
295+
getDisplayName,
296+
getPropsVNodeDisplayName: getDisplayName,
297+
getActualChildren,
298+
getAncestor,
299+
getDom,
300+
isTextVNode,
301+
getInstance,
302+
createSuspenseState,
303+
getComponent,
304+
getComponentHooks,
305+
getHookState,
306+
getVNodeParent,
307+
isComponent,
308+
isElement,
309+
isSuspenseVNode,
310+
getSuspendedState,
311+
isVNode,
312+
setNextState,
313+
isPortal,
314+
getStatefulHookValue,
315+
getStatefulHooks,
316+
isUseReducerOrState,
317+
getRenderReasonPost,
318+
};

src/adapter/10/filter.ts

Lines changed: 0 additions & 52 deletions
This file was deleted.
Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,16 @@
1-
import { getDisplayName, getComponent } from "../vnode";
2-
import { ID } from "../../../view/store/types";
3-
import { IdMappingState, getVNodeById } from "../IdMapper";
4-
import { RendererConfig10 } from "../renderer";
1+
import { getDisplayName, getComponent } from "./bindings";
2+
import { ID } from "../../view/store/types";
3+
import { getVNodeById, IdMappingState } from "../shared/idMapper";
4+
import { SharedVNode } from "../shared/bindings";
5+
import { RendererConfig } from "../shared/renderer";
56

67
/**
78
* Pretty print a `VNode` to the browser console. This can be triggered
89
* by clicking a button in the devtools ui.
910
*/
10-
export function logVNode(
11-
ids: IdMappingState,
12-
config: RendererConfig10,
11+
export function logVNode<T extends SharedVNode>(
12+
ids: IdMappingState<T>,
13+
config: RendererConfig,
1314
id: ID,
1415
children: ID[],
1516
) {

0 commit comments

Comments
 (0)