Skip to content

Commit

Permalink
optimize by not accessing the dom
Browse files Browse the repository at this point in the history
  • Loading branch information
JoviDeCroock committed Jun 15, 2024
1 parent 4d8357a commit 87376bc
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 195 deletions.
221 changes: 27 additions & 194 deletions demo/index.jsx
Original file line number Diff line number Diff line change
@@ -1,197 +1,30 @@
import { render, Component, Fragment } from 'preact';
// import renderToString from 'preact-render-to-string';
import './style.scss';
import { Router, Link } from 'preact-router';
import Pythagoras from './pythagoras';
import Spiral from './spiral';
import Reorder from './reorder';
import Todo from './todo';
import Fragments from './fragments';
import Context from './context';
import installLogger from './logger';
import ProfilerDemo from './profiler';
import KeyBug from './key_bug';
import StateOrderBug from './stateOrderBug';
import PeopleBrowser from './people';
import StyledComp from './styled-components';
import { initDevTools } from 'preact/devtools/src/devtools';
import { initDebug } from 'preact/debug/src/debug';
import DevtoolsDemo from './devtools';
import SuspenseDemo from './suspense';
import Redux from './redux';
import TextFields from './textFields';
import ReduxBug from './reduxUpdate';
import SuspenseRouterBug from './suspense-router';
import NestedSuspenseBug from './nested-suspense';
import Contenteditable from './contenteditable';
import { MobXDemo } from './mobx';
import Zustand from './zustand';
import ReduxToolkit from './redux_toolkit';

let isBenchmark = /(\/spiral|\/pythagoras|[#&]bench)/g.test(
window.location.href
);
if (!isBenchmark) {
// eslint-disable-next-line no-console
console.log('Enabling devtools and debug');
initDevTools();
initDebug();
}

// mobx-state-tree fix
window.setImmediate = setTimeout;

class Home extends Component {
render() {
return (
<div>
<h1>Hello</h1>
</div>
);
}
}

class DevtoolsWarning extends Component {
onClick = () => {
window.location.reload();
};

render() {
return (
<button onClick={this.onClick}>
Start Benchmark (disables devtools)
</button>
);
}
import { render, h } from 'preact';
import { useState, useEffect } from 'preact/hooks';
// import './patch'

const Button = props => {
return (
<div>
<p>hello next there</p>
</div>
);
};

function App() {
const [, setValue] = useState(0);

useEffect(() => {
const interval = setInterval(() => setValue(v => v + 1), 1000);

return () => clearInterval(interval);
}, []);

return (
<>
<h1>Hello</h1>
<Button label="Next" />
</>
);
}

class App extends Component {
render({ url }) {
return (
<div class="app">
<header>
<nav>
<Link href="/" activeClassName="active">
Home
</Link>
<Link href="/reorder" activeClassName="active">
Reorder
</Link>
<Link href="/spiral" activeClassName="active">
Spiral
</Link>
<Link href="/pythagoras" activeClassName="active">
Pythagoras
</Link>
<Link href="/todo" activeClassName="active">
ToDo
</Link>
<Link href="/fragments" activeClassName="active">
Fragments
</Link>
<Link href="/key_bug" activeClassName="active">
Key Bug
</Link>
<Link href="/profiler" activeClassName="active">
Profiler
</Link>
<Link href="/context" activeClassName="active">
Context
</Link>
<Link href="/devtools" activeClassName="active">
Devtools
</Link>
<Link href="/empty-fragment" activeClassName="active">
Empty Fragment
</Link>
<Link href="/people" activeClassName="active">
People Browser
</Link>
<Link href="/state-order" activeClassName="active">
State Order
</Link>
<Link href="/styled-components" activeClassName="active">
Styled Components
</Link>
<Link href="/redux" activeClassName="active">
Redux
</Link>
<Link href="/mobx" activeClassName="active">
MobX
</Link>
<Link href="/suspense" activeClassName="active">
Suspense / lazy
</Link>
<Link href="/textfields" activeClassName="active">
Textfields
</Link>
<Link href="/reduxBug/1" activeClassName="active">
Redux Bug
</Link>
<Link href="/suspense-router" activeClassName="active">
Suspense Router Bug
</Link>
<Link href="/nested-suspense" activeClassName="active">
Nested Suspense Bug
</Link>
<Link href="/contenteditable" activeClassName="active">
contenteditable
</Link>
<Link href="/zustand" activeClassName="active">
zustand
</Link>
<Link href="/redux-toolkit" activeClassName="active">
redux-toolkit
</Link>
</nav>
</header>
<main>
<Router url={url}>
<Home path="/" />
<StateOrderBug path="/state-order" />
<Reorder path="/reorder" />
<div path="/spiral">
{!isBenchmark ? <DevtoolsWarning /> : <Spiral />}
</div>
<div path="/pythagoras">
{!isBenchmark ? <DevtoolsWarning /> : <Pythagoras />}
</div>
<Todo path="/todo" />
<Fragments path="/fragments" />
<ProfilerDemo path="/profiler" />
<KeyBug path="/key_bug" />
<Context path="/context" />
<DevtoolsDemo path="/devtools" />
<SuspenseDemo path="/suspense" />
<EmptyFragment path="/empty-fragment" />
<PeopleBrowser path="/people/:user?" />
<StyledComp path="/styled-components" />
<Redux path="/redux" />
<MobXDemo path="/mobx" />
<TextFields path="/textfields" />
<ReduxBug path="/reduxBug/:start" />
<SuspenseRouterBug path="/suspense-router" />
<NestedSuspenseBug path="/nested-suspense" />
<Contenteditable path="/contenteditable" />
<Zustand path="/zustand" />
<ReduxToolkit path="/redux-toolkit" />
</Router>
</main>
</div>
);
}
}

function EmptyFragment() {
return <Fragment />;
}

// document.body.innerHTML = renderToString(<App url={location.href.match(/[#&]ssr/) ? undefined : '/'} />);
// document.body.firstChild.setAttribute('is-ssr', 'true');

installLogger(
String(localStorage.LOG) === 'true' || location.href.match(/logger/),
String(localStorage.CONSOLE) === 'true' || location.href.match(/console/)
);

render(<App />, document.body);
65 changes: 65 additions & 0 deletions demo/patch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import { options } from 'preact';

// Fix Preact rendering when Google Translate breaks the DOM
const FONT_AS_TEXT = {
localName: {
value: null
},
nodeType: {
value: 3
},
data: {
get() {
return this._data;
},
set(v) {
v += '';
if (v === this._data) return;
const t = document.createTextNode((this._data = v));
this.parentNode.replaceChild(t, this);
this.__v.__e = t;
}
}
};
function check(child, ref) {
if (ref && ref.nodeType === 3 && child) {
let intercept = child.localName === 'msreadoutspan';
if (!intercept && child.localName === 'font') {
for (let i in child) {
if (i.startsWith('_gt_')) {
intercept = true;
break;
}
}
}
if (intercept) {
ref._font = child;
child._data = ref.data;
Object.defineProperties(child, FONT_AS_TEXT);
}
}
}
const ib = Element.prototype.insertBefore;
Element.prototype.insertBefore = function (child, ref) {
check(child, ref);
return ib.apply(this, arguments);
};
const rc = Element.prototype.replaceChild;
Element.prototype.replaceChild = function (child, ref) {
check(child, ref);
return rc.apply(this, arguments);
};
const oldDiffedHook = options.diffed;
options.diffed = vnode => {
if (vnode.type === null && vnode.__e) {
const font = vnode.__e._font;
if (font) {
vnode.__e = font;
font.__v = vnode;
font.data = vnode.props;
}
}
if (oldDiffedHook) {
oldDiffedHook(vnode);
}
};
2 changes: 1 addition & 1 deletion src/diff/children.js
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,7 @@ export function diffChildren(
oldVNode._children === childVNode._children
) {
// @ts-expect-error olDom should be present on a DOM node
if (oldDom && oldDom.nodeType === 1 && !oldDom.isConnected) {
if (oldDom && typeof childVNode.type == 'string' && !oldDom.isConnected) {
oldDom = getDomSibling(oldVNode);
}
oldDom = insert(childVNode, oldDom, parentDom);
Expand Down

0 comments on commit 87376bc

Please sign in to comment.