Skip to content

Commit 20db668

Browse files
authored
Merge branch 'master' into update-imports
2 parents d9022c3 + 8b71c63 commit 20db668

File tree

169 files changed

+42855
-18436
lines changed

Some content is hidden

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

169 files changed

+42855
-18436
lines changed

README.md

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ This is a simple benchmark for several javascript frameworks. The benchmarks cre
66

77
## Security advice
88

9-
Currently there are 186 implemenations in this repository. It's of course impossible for me to make a security assessment
9+
Currently there are 186 implementations in this repository. It's of course impossible for me to make a security assessment
1010
for all those implementations. `npm ci` and `npm install` can execute arbitraty commands, so they should be executed only for packages you trust. Consequently I build on a dedicated virtual private linux server such that I don't have to install the packages for all those implemenations on my laptop. There's a prebuild build.zip for each chrome release you can download such that you can avoid installing the packages from all implementations.
1111
(I don't know of any (attempted) case for malicious packages in this repository, so please take it just as a general warning.)
1212

@@ -79,7 +79,7 @@ v20.9.0
7979
```
8080

8181
## 1.2 Downloading the pre-built binaries and starting the server
82-
building all frameworks can be challenging. There's a new way that allows to skip that and just run the benchmark without builiding all implementations.
82+
building all frameworks can be challenging. There's a new way that allows to skip that and just run the benchmark without building all implementations.
8383

8484

8585
Start with checking out a tagged release like that. Pick the release that you want (e.g. chrome 100):

broken-frameworks/keyed/butterfloat/.gitignore

Whitespace-only changes.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
{
2+
"semi": false,
3+
"singleQuote": true,
4+
"endOfLine": "auto"
5+
}
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
import { writeFile } from 'node:fs/promises'
2+
import { buildStamp, makeTestComponentContext, makeTestEvent } from 'butterfloat'
3+
import { build } from 'esbuild'
4+
import { JSDOM } from 'jsdom'
5+
import { NEVER } from 'rxjs'
6+
7+
await build({
8+
entryPoints: ['./app-vm.ts', './app.tsx', './data.ts', './row-vm.ts', './row.tsx'],
9+
bundle: false,
10+
format: 'esm',
11+
outdir: '.',
12+
})
13+
14+
await build({
15+
entryPoints: ['./main.ts'],
16+
bundle: true,
17+
format: 'esm',
18+
outdir: '.',
19+
})
20+
21+
const dom = new JSDOM(`
22+
<!DOCTYPE html>
23+
<html lang="en">
24+
<head>
25+
<meta charset="utf-8"/>
26+
<title>Butterfloat</title>
27+
<link href="/css/currentStyle.css" rel="stylesheet"/>
28+
<script type="module" src="./main.js"></script>
29+
</head>
30+
<body>
31+
<div id='main'>
32+
</div>
33+
<span class="preloadicon glyphicon glyphicon-remove" aria-hidden="true"></span>
34+
</body>
35+
</html>
36+
`)
37+
38+
const { window } = dom
39+
const { document } = window
40+
globalThis.document = document
41+
globalThis.window = window
42+
43+
const { App } = await import('./app.js')
44+
const { context: appContext } = makeTestComponentContext({
45+
run: makeTestEvent(NEVER),
46+
runlots: makeTestEvent(NEVER),
47+
add: makeTestEvent(NEVER),
48+
update: makeTestEvent(NEVER),
49+
clear: makeTestEvent(NEVER),
50+
swaprows: makeTestEvent(NEVER),
51+
})
52+
const appStamp = buildStamp(App({}, appContext), document)
53+
appStamp.id = 'app'
54+
document.body.append(appStamp)
55+
56+
const { Row } = await import('./row.js')
57+
const { AppViewModel } = await import('./app-vm.js')
58+
const { RowViewModel } = await import('./row-vm.js')
59+
const vm = new RowViewModel(new AppViewModel(), -999)
60+
const { context: rowContext } = makeTestComponentContext({
61+
select: makeTestEvent(NEVER),
62+
remove: makeTestEvent(NEVER),
63+
})
64+
const rowStamp = buildStamp(Row({ vm }, rowContext), document)
65+
rowStamp.id = 'row'
66+
document.body.append(rowStamp)
67+
68+
await writeFile('./index.html', dom.serialize())
Lines changed: 69 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
import { butterfly } from "butterfloat";
2+
import { filter, map, mergeMap, range } from "rxjs";
3+
import { RowViewModel } from "./row-vm.js";
4+
class AppViewModel {
5+
#idRange;
6+
#setIdRange;
7+
get idRange() {
8+
return this.#idRange;
9+
}
10+
#selectedId;
11+
#setSelectedId;
12+
get selectedId() {
13+
return this.#selectedId;
14+
}
15+
#rows;
16+
get rows() {
17+
return this.#rows;
18+
}
19+
#rowsToUpdate;
20+
#setRowsToUpdate;
21+
get rowsToUpdate() {
22+
return this.#rowsToUpdate;
23+
}
24+
constructor() {
25+
;
26+
[this.#idRange, this.#setIdRange] = butterfly({
27+
min: 0,
28+
max: 0,
29+
added: [-1, -1]
30+
});
31+
[this.#selectedId, this.#setSelectedId] = butterfly(-1);
32+
[this.#rowsToUpdate, this.#setRowsToUpdate] = butterfly(-1);
33+
this.#rows = this.#idRange.pipe(
34+
filter((idRange) => idRange.added[1] > 0),
35+
mergeMap((idRange) => range(idRange.added[0], idRange.added[1])),
36+
map((id) => new RowViewModel(this, id))
37+
);
38+
}
39+
clear() {
40+
this.#setIdRange((current) => ({
41+
min: current.max,
42+
max: current.max,
43+
added: [-1, -1]
44+
}));
45+
}
46+
selectRow(id) {
47+
this.#setSelectedId(id);
48+
}
49+
createRows(count) {
50+
this.#setIdRange((current) => {
51+
const min = current.max;
52+
const max = current.max + count;
53+
return { min, max, added: [current.max, count] };
54+
});
55+
}
56+
appendRows(count) {
57+
this.#setIdRange((current) => {
58+
const min = current.min;
59+
const max = current.max + count;
60+
return { min, max, added: [current.max, count] };
61+
});
62+
}
63+
updateRow(id) {
64+
this.#setRowsToUpdate(id);
65+
}
66+
}
67+
export {
68+
AppViewModel
69+
};
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
import { butterfly, StateSetter } from 'butterfloat'
2+
import { filter, map, mergeMap, Observable, range } from 'rxjs'
3+
import { RowViewModel } from './row-vm.js'
4+
5+
export interface IdRange {
6+
min: number
7+
max: number
8+
added: [start: number, count: number]
9+
}
10+
11+
export class AppViewModel {
12+
readonly #idRange: Observable<IdRange>
13+
readonly #setIdRange: (idRange: StateSetter<IdRange>) => void
14+
get idRange() {
15+
return this.#idRange
16+
}
17+
18+
readonly #selectedId: Observable<number>
19+
readonly #setSelectedId: (id: StateSetter<number>) => void
20+
get selectedId() {
21+
return this.#selectedId
22+
}
23+
24+
readonly #rows: Observable<RowViewModel>
25+
get rows() {
26+
return this.#rows
27+
}
28+
29+
readonly #rowsToUpdate: Observable<number>
30+
readonly #setRowsToUpdate: (rowsToUpdate: StateSetter<number>) => void
31+
get rowsToUpdate() {
32+
return this.#rowsToUpdate
33+
}
34+
35+
constructor() {
36+
;[this.#idRange, this.#setIdRange] = butterfly<IdRange>({
37+
min: 0,
38+
max: 0,
39+
added: [-1, -1],
40+
})
41+
;[this.#selectedId, this.#setSelectedId] = butterfly<number>(-1)
42+
;[this.#rowsToUpdate, this.#setRowsToUpdate] = butterfly<number>(-1)
43+
44+
this.#rows = this.#idRange.pipe(
45+
filter((idRange) => idRange.added[1] > 0),
46+
mergeMap((idRange) => range(idRange.added[0], idRange.added[1])),
47+
map((id) => new RowViewModel(this, id)),
48+
)
49+
}
50+
51+
clear() {
52+
this.#setIdRange((current) => ({
53+
min: current.max,
54+
max: current.max,
55+
added: [-1, -1],
56+
}))
57+
}
58+
59+
selectRow(id: number) {
60+
this.#setSelectedId(id)
61+
}
62+
63+
createRows(count: number) {
64+
this.#setIdRange((current) => {
65+
const min = current.max
66+
const max = current.max + count
67+
return { min, max, added: [current.max, count] }
68+
})
69+
}
70+
71+
appendRows(count: number) {
72+
this.#setIdRange((current) => {
73+
const min = current.min
74+
const max = current.max + count
75+
return { min, max, added: [current.max, count] }
76+
})
77+
}
78+
79+
updateRow(id: number) {
80+
this.#setRowsToUpdate(id)
81+
}
82+
}
Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
import { jsx } from "butterfloat";
2+
import { AppViewModel } from "./app-vm.js";
3+
import { Row } from "./row.js";
4+
import { map, withLatestFrom } from "rxjs";
5+
function App(_props, { bindEffect, bindImmediateEffect, events }) {
6+
const vm = new AppViewModel();
7+
const children = vm.rows.pipe(map((row) => () => /* @__PURE__ */ jsx(Row, { vm: row })));
8+
bindImmediateEffect(events.run, () => vm.createRows(1e3));
9+
bindImmediateEffect(events.runlots, () => vm.createRows(1e4));
10+
bindImmediateEffect(events.add, () => vm.appendRows(1e3));
11+
bindImmediateEffect(events.clear, () => vm.clear());
12+
bindEffect(
13+
events.update.pipe(withLatestFrom(events.tbodyAttach)),
14+
([_, tbody]) => {
15+
const rows = tbody.querySelectorAll("tr");
16+
for (let i = 0; i < rows.length; i += 10) {
17+
const row = rows[i];
18+
const id = Number.parseInt(row.dataset.id, 10);
19+
vm.updateRow(id);
20+
}
21+
}
22+
);
23+
bindEffect(
24+
events.swaprows.pipe(withLatestFrom(events.tbodyAttach)),
25+
([_, tbody]) => {
26+
const rows = tbody.querySelectorAll("tr");
27+
if (rows.length > 998) {
28+
const row0 = rows[0];
29+
const row1 = rows[1];
30+
const row997 = rows[997];
31+
const row998 = rows[998];
32+
row0.after(row998);
33+
row997.after(row1);
34+
}
35+
}
36+
);
37+
return /* @__PURE__ */ jsx("div", { class: "container" }, /* @__PURE__ */ jsx("div", { class: "jumbotron" }, /* @__PURE__ */ jsx("div", { class: "row" }, /* @__PURE__ */ jsx("div", { class: "col-md-6" }, /* @__PURE__ */ jsx("h1", null, "Butterfloat")), /* @__PURE__ */ jsx("div", { class: "col-md-6" }, /* @__PURE__ */ jsx("div", { class: "row" }, /* @__PURE__ */ jsx("div", { class: "col-sm-6 smallpad" }, /* @__PURE__ */ jsx(
38+
"button",
39+
{
40+
type: "button",
41+
class: "btn btn-primary btn-block",
42+
id: "run",
43+
events: { click: events.run }
44+
},
45+
"Create 1,000 rows"
46+
)), /* @__PURE__ */ jsx("div", { class: "col-sm-6 smallpad" }, /* @__PURE__ */ jsx(
47+
"button",
48+
{
49+
type: "button",
50+
class: "btn btn-primary btn-block",
51+
id: "runlots",
52+
events: { click: events.runlots }
53+
},
54+
"Create 10,000 rows"
55+
)), /* @__PURE__ */ jsx("div", { class: "col-sm-6 smallpad" }, /* @__PURE__ */ jsx(
56+
"button",
57+
{
58+
type: "button",
59+
class: "btn btn-primary btn-block",
60+
id: "add",
61+
events: { click: events.add }
62+
},
63+
"Append 1,000 rows"
64+
)), /* @__PURE__ */ jsx("div", { class: "col-sm-6 smallpad" }, /* @__PURE__ */ jsx(
65+
"button",
66+
{
67+
type: "button",
68+
class: "btn btn-primary btn-block",
69+
id: "update",
70+
events: { click: events.update }
71+
},
72+
"Update every 10th row"
73+
)), /* @__PURE__ */ jsx("div", { class: "col-sm-6 smallpad" }, /* @__PURE__ */ jsx(
74+
"button",
75+
{
76+
type: "button",
77+
class: "btn btn-primary btn-block",
78+
id: "clear",
79+
events: { click: events.clear }
80+
},
81+
"Clear"
82+
)), /* @__PURE__ */ jsx("div", { class: "col-sm-6 smallpad" }, /* @__PURE__ */ jsx(
83+
"button",
84+
{
85+
type: "button",
86+
class: "btn btn-primary btn-block",
87+
id: "swaprows",
88+
events: { click: events.swaprows }
89+
},
90+
"Swap Rows"
91+
)))))), /* @__PURE__ */ jsx("table", { class: "table table-hover table-striped test-data" }, /* @__PURE__ */ jsx(
92+
"tbody",
93+
{
94+
id: "tbody",
95+
childrenBind: children,
96+
childrenBindMode: "append",
97+
events: { bfDomAttach: events.tbodyAttach }
98+
}
99+
)));
100+
}
101+
export {
102+
App
103+
};

0 commit comments

Comments
 (0)