Skip to content

Commit 9b471be

Browse files
committed
[refactor] rewrite to Async Rendering inspired by Crank.js
1 parent 0d30a1b commit 9b471be

18 files changed

+558
-252
lines changed

ReadMe.md

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# DOM Renderer
2+
3+
DOM Renderer with [Async Generator][1] support (inspired by [Crank.js][2]), which is based on [TSX][3] & **DOM-compatible virtual DOM**.
4+
5+
[1]: https://tc39.es/ecma262/#sec-asyncgeneratorfunction-objects
6+
[2]: https://crank.js.org/
7+
[3]: https://www.typescriptlang.org/docs/handbook/jsx.html

package.json

Lines changed: 23 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,18 @@
11
{
22
"name": "dom-renderer",
3-
"version": "2.0.0-alpha.0",
3+
"version": "3.0.0-alpha.0",
44
"license": "LGPL-3.0",
55
"author": "shiy2008@gmail.com",
6-
"description": "DOM Renderer based on TSX & DOM-compatible virtual DOM",
6+
"description": "DOM Renderer with Async Generator support (inspired by Crank.js), which is based on TSX & DOM-compatible virtual DOM.",
77
"keywords": [
88
"DOM",
99
"render",
10+
"async",
11+
"generator",
1012
"TypeScript",
1113
"JSX",
12-
"vDOM"
14+
"vDOM",
15+
"crank"
1316
],
1417
"homepage": "https://web-cell.dev/DOM-Renderer/",
1518
"repository": {
@@ -20,41 +23,39 @@
2023
"url": "https://github.com/EasyWebApp/DOM-Renderer/issues"
2124
},
2225
"source": "source/index.ts",
26+
"dependencies": {
27+
"web-utility": "1.5.0"
28+
},
2329
"devDependencies": {
24-
"@types/core-js": "^2.5.3",
25-
"@types/jest": "^25.1.4",
26-
"@types/jsdom": "^16.1.0",
27-
"core-js": "^3.6.4",
28-
"husky": "^4.2.3",
29-
"jest": "^25.1.0",
30-
"jsdom": "^16.2.1",
31-
"lint-staged": "^10.0.8",
32-
"prettier": "^1.19.1",
33-
"ts-jest": "^25.2.1",
34-
"typescript": "^3.8.3"
30+
"@types/jest": "^25.2.3",
31+
"husky": "^4.2.5",
32+
"jest": "^26.0.1",
33+
"lint-staged": "^10.2.7",
34+
"prettier": "^2.0.5",
35+
"ts-jest": "^26.1.0",
36+
"typescript": "^3.9.3"
3537
},
3638
"prettier": {
3739
"singleQuote": true,
40+
"trailingComma": "none",
41+
"arrowParens": "avoid",
3842
"tabWidth": 4
3943
},
4044
"lint-staged": {
41-
"*.{json,ts,tsx}": [
45+
"*.{md,json,yml,ts,tsx}": [
4246
"prettier --write"
4347
]
4448
},
4549
"jest": {
4650
"preset": "ts-jest",
47-
"testEnvironment": "node",
48-
"globals": {
49-
"ts-jest": {
50-
"tsConfig": "test/tsconfig.json"
51-
}
52-
}
51+
"transformIgnorePatterns": []
5352
},
5453
"scripts": {
5554
"test": "lint-staged && jest"
5655
},
5756
"husky": {
58-
"pre-commit": "npm test"
57+
"hooks": {
58+
"pre-commit": "npm test"
59+
}
5960
}
6061
}

source/AsyncComponent.ts

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
import { Props, GeneratorNode, AsyncGeneratorNode, VChild } from './creator';
2+
import { isEmpty } from 'web-utility/source/data';
3+
import { clearList } from './utility';
4+
5+
export class AsyncComponent {
6+
function: Function;
7+
props: Props;
8+
generator: GeneratorNode | AsyncGeneratorNode;
9+
10+
lastNodes: VChild[] = [];
11+
realNodes: HTMLElement[] = [];
12+
13+
constructor(func: Function, props: Props) {
14+
this.function = func;
15+
this.props = props;
16+
this.generator = func.call(this, props);
17+
}
18+
19+
*[Symbol.iterator]() {
20+
while (true) yield this.props;
21+
}
22+
23+
async *[Symbol.asyncIterator]() {
24+
while (true) yield this.props;
25+
}
26+
27+
async render() {
28+
const { realNodes } = this;
29+
30+
const { value } = await this.generator.next(
31+
realNodes[1] ? realNodes : realNodes[0]
32+
);
33+
if (!isEmpty(value)) this.lastNodes = value;
34+
35+
return clearList(this.lastNodes);
36+
}
37+
}

source/creator.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import { HTMLProps } from 'web-utility/source/DOM-type';
2+
import { clearList } from './utility';
3+
import { AsyncComponent } from './AsyncComponent';
4+
5+
export interface VElement {
6+
tagName: string;
7+
childNodes: VChildNode[];
8+
[key: string]: any;
9+
}
10+
export type VChild = string | number | boolean | VElement;
11+
export type VChildNode = VChild | AsyncComponent;
12+
export type VChildren = VChildNode | VChildNode[];
13+
14+
export type GeneratorNode = Generator<VChildren, any, Node | Node[]>;
15+
export type AsyncGeneratorNode = AsyncGenerator<VChildren, any, Node | Node[]>;
16+
17+
export type AsyncNode = Promise<VChildren> | GeneratorNode | AsyncGeneratorNode;
18+
19+
export type RenderNode = VChildren | AsyncNode;
20+
21+
export interface Props extends HTMLProps {
22+
children?: VChildren;
23+
[key: string]: any;
24+
}
25+
26+
export type FunctionComponent = (props: Props) => RenderNode;
27+
28+
export type Component = string | FunctionComponent;
29+
30+
declare global {
31+
namespace JSX {
32+
interface IntrinsicElements {
33+
[tagName: string]: Props;
34+
}
35+
interface ElementChildrenAttribute {
36+
children: VChildren;
37+
}
38+
}
39+
}
40+
41+
export function createElement(
42+
tagName: Component,
43+
props: Props | null,
44+
...childNodes: VChildNode[]
45+
) {
46+
childNodes = clearList(childNodes);
47+
48+
if (typeof tagName === 'string')
49+
return {
50+
...props,
51+
tagName: tagName as string,
52+
childNodes
53+
};
54+
55+
props = { ...props, children: childNodes };
56+
57+
const result = tagName(props);
58+
59+
if (typeof (result as Promise<any>).then === 'function')
60+
return new AsyncComponent(async function* () {
61+
yield await (result as Promise<any>);
62+
}, props);
63+
64+
if (typeof (result as Generator).next === 'function')
65+
return new AsyncComponent(tagName, props);
66+
67+
return result;
68+
}
69+
70+
export function Fragment({ children }: Props) {
71+
return children;
72+
}

source/factory.ts

Lines changed: 0 additions & 32 deletions
This file was deleted.

source/global.d.ts

Lines changed: 0 additions & 5 deletions
This file was deleted.

source/index.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1-
export * from './type';
2-
export * from './renderer';
3-
export * from './factory';
1+
export * from './utility';
2+
export * from './creator';
3+
export * from './AsyncComponent';
4+
export * from './renderer';
5+
export * from './updater';

0 commit comments

Comments
 (0)