Skip to content

Commit 96ae724

Browse files
authored
Merge pull request #5167 from preactjs/JoviDeCroock/reduce-core-bundle-size
Reduce core bundle size in v11
2 parents be0996b + 927e919 commit 96ae724

8 files changed

Lines changed: 110 additions & 112 deletions

File tree

src/clone-element.js

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

src/component.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -148,7 +148,7 @@ function renderComponent(component) {
148148
oldVNode._flags & MODE_HYDRATE ? [oldDom] : NULL,
149149
commitQueue,
150150
oldDom == NULL ? getDomSibling(oldVNode) : oldDom,
151-
!!(oldVNode._flags & MODE_HYDRATE),
151+
oldVNode._flags & MODE_HYDRATE,
152152
refQueue
153153
);
154154

@@ -169,8 +169,8 @@ function renderComponent(component) {
169169
function updateParentDomPointers(vnode) {
170170
// Stop at root boundaries (_parentDom)
171171
if (
172-
(vnode = vnode._parent) != NULL &&
173-
vnode._component != NULL &&
172+
(vnode = vnode._parent) &&
173+
vnode._component &&
174174
!vnode.props._parentDom
175175
) {
176176
vnode._dom = NULL;

src/constants.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export const UNDEFINED = undefined;
3232
export const EMPTY_OBJ = /** @type {any} */ ({});
3333
export const EMPTY_ARR = [];
3434

35-
export const MATHML_TOKEN_ELEMENTS = /(mi|mn|mo|ms$|mte|msp)/;
35+
export const MATHML_TOKEN_ELEMENTS = /m(i|n|o|s$|te|sp)/;
3636

3737
export const HAS_MOVE_BEFORE_SUPPORT =
3838
typeof window !== 'undefined' && 'moveBefore' in Element.prototype;

src/create-element.js

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { slice } from './util';
1+
import { assign, slice } from './util';
22
import options from './options';
33
import { NULL, UNDEFINED } from './constants';
44

@@ -17,21 +17,56 @@ export function createElement(type, props, children) {
1717
let normalizedProps = {},
1818
key,
1919
ref,
20-
i;
20+
i,
21+
length = arguments.length;
2122
for (i in props) {
2223
if (i == 'key') key = props[i];
2324
else if (i == 'ref' && typeof type != 'function') ref = props[i];
2425
else normalizedProps[i] = props[i];
2526
}
2627

27-
if (arguments.length > 2) {
28-
normalizedProps.children =
29-
arguments.length > 3 ? slice.call(arguments, 2) : children;
28+
if (length > 2) {
29+
normalizedProps.children = length > 3 ? slice.call(arguments, 2) : children;
3030
}
3131

3232
return createVNode(type, normalizedProps, key, ref, NULL);
3333
}
3434

35+
/**
36+
* Clones the given VNode, optionally adding attributes/props and replacing its
37+
* children.
38+
* @param {import('./internal').VNode} vnode The virtual DOM element to clone
39+
* @param {object} props Attributes/props to add when cloning
40+
* @param {Array<import('./internal').ComponentChildren>} children Any additional arguments will be used
41+
* as replacement children.
42+
* @returns {import('./internal').VNode}
43+
*/
44+
export function cloneElement(vnode, props, children) {
45+
let normalizedProps = assign({}, vnode.props),
46+
key,
47+
ref,
48+
i,
49+
length = arguments.length;
50+
51+
for (i in props) {
52+
if (i == 'key') key = props[i];
53+
else if (i == 'ref' && typeof vnode.type != 'function') ref = props[i];
54+
else normalizedProps[i] = props[i];
55+
}
56+
57+
if (length > 2) {
58+
normalizedProps.children = length > 3 ? slice.call(arguments, 2) : children;
59+
}
60+
61+
return createVNode(
62+
vnode.type,
63+
normalizedProps,
64+
key !== UNDEFINED ? key : vnode.key,
65+
ref !== UNDEFINED ? ref : vnode.ref,
66+
NULL
67+
);
68+
}
69+
3570
/**
3671
* Create a VNode (used internally by Preact)
3772
* @param {import('./internal').VNode["type"]} type The node name or Component
@@ -59,13 +94,13 @@ export function createVNode(type, props, key, ref, original) {
5994
_dom: NULL,
6095
_component: NULL,
6196
constructor: UNDEFINED,
62-
_original: original == NULL ? ++vnodeId : original,
97+
_original: original || ++vnodeId,
6398
_index: -1,
6499
_flags: 0
65100
};
66101

67102
// Only invoke the vnode hook if this was *not* a direct copy:
68-
if (original == NULL && options.vnode != NULL) options.vnode(vnode);
103+
if (!original && options.vnode) options.vnode(vnode);
69104

70105
return vnode;
71106
}

src/diff/catch-error.js

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,9 +20,7 @@ export function _catchError(error, vnode, oldVNode, errorInfo) {
2020
/** @type {import('../internal').Component} */
2121
let component,
2222
/** @type {import('../internal').ComponentType} */
23-
ctor,
24-
/** @type {number} */
25-
handled;
23+
ctor;
2624

2725
for (; (vnode = vnode._parent); ) {
2826
if (
@@ -35,16 +33,14 @@ export function _catchError(error, vnode, oldVNode, errorInfo) {
3533

3634
if (ctor && ctor.getDerivedStateFromError != NULL) {
3735
component.setState(ctor.getDerivedStateFromError(error));
38-
handled = component._bits & COMPONENT_DIRTY;
3936
}
4037

4138
if (component.componentDidCatch != NULL) {
4239
component.componentDidCatch(error, errorInfo || {});
43-
handled = component._bits & COMPONENT_DIRTY;
4440
}
4541

4642
// This is an error boundary. Mark it as having bailed out, and whether it was mid-hydration.
47-
if (handled) {
43+
if (component._bits & COMPONENT_DIRTY) {
4844
component._bits |= COMPONENT_PENDING_ERROR;
4945
return;
5046
}

src/diff/children.js

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,11 @@ export function diffChildren(
6565
/** @type {PreactElement} */
6666
firstChildDom;
6767

68-
// This is a compression of oldParentVNode!=null && oldParentVNode != EMPTY_OBJ && oldParentVNode._children || EMPTY_ARR
69-
// as EMPTY_OBJ._children should be `undefined`.
68+
// This is a compression of oldParentVNode != EMPTY_OBJ && oldParentVNode._children || EMPTY_ARR
69+
// as EMPTY_OBJ._children should be `undefined`. Callers always pass at
70+
// least EMPTY_OBJ, so a null check isn't needed.
7071
/** @type {VNode[]} */
71-
let oldChildren = (oldParentVNode && oldParentVNode._children) || EMPTY_ARR;
72+
let oldChildren = oldParentVNode._children || EMPTY_ARR;
7273

7374
let newChildrenLength = renderResult.length;
7475

@@ -86,8 +87,10 @@ export function diffChildren(
8687

8788
// At this point, constructNewChildrenArray has assigned _index to be the
8889
// matchingIndex for this VNode's oldVNode (or -1 if there is no oldVNode).
90+
// ~_index guards the -1 case: a negative array index is a named property
91+
// access which V8 can't serve from the fast elements path.
8992
oldVNode =
90-
(childVNode._index != -1 && oldChildren[childVNode._index]) || EMPTY_OBJ;
93+
(~childVNode._index && oldChildren[childVNode._index]) || EMPTY_OBJ;
9194

9295
// Update childVNode._index to its final index
9396
childVNode._index = i;
@@ -119,7 +122,7 @@ export function diffChildren(
119122
);
120123
}
121124

122-
if (firstChildDom == NULL && newDom != NULL) {
125+
if (!firstChildDom && newDom) {
123126
firstChildDom = newDom;
124127
}
125128

@@ -130,7 +133,7 @@ export function diffChildren(
130133
oldDom,
131134
parentDom,
132135
shouldPlace,
133-
oldVNode == NULL || oldVNode._original == NULL
136+
oldVNode._original == NULL
134137
);
135138

136139
// When a matched VNode is physically moved via INSERT_VNODE, its old
@@ -196,11 +199,11 @@ function constructNewChildrenArray(
196199
// If this newVNode is being reused (e.g. <div>{reuse}{reuse}</div>) in the same diff,
197200
// or we are rendering a component (e.g. setState) copy the oldVNodes so it can have
198201
// it's own DOM & etc. pointers
202+
// Anything that isn't an object at this point is a string, number or
203+
// bigint (null, booleans and functions are handled above), String
204+
// objects are the lone object type rendered as text.
199205
else if (
200-
typeof childVNode == 'string' ||
201-
typeof childVNode == 'number' ||
202-
// eslint-disable-next-line valid-typeof
203-
typeof childVNode == 'bigint' ||
206+
typeof childVNode != 'object' ||
204207
childVNode.constructor == String
205208
) {
206209
childVNode = newParentVNode._children[i] = createVNode(
@@ -249,7 +252,8 @@ function constructNewChildrenArray(
249252
));
250253

251254
oldVNode = NULL;
252-
if (matchingIndex != -1) {
255+
// ~matchingIndex is only falsy for -1, i.e. when no match was found
256+
if (~matchingIndex) {
253257
oldVNode = oldChildren[matchingIndex];
254258
remainingOldChildren--;
255259
if (oldVNode) {
@@ -260,8 +264,8 @@ function constructNewChildrenArray(
260264
// Here, we define isMounting for the purposes of the skew diffing
261265
// algorithm. Nodes that are unsuspending are considered mounting and we detect
262266
// this by checking if oldVNode._original == null
263-
if (oldVNode == NULL || oldVNode._original == NULL) {
264-
if (matchingIndex == -1) {
267+
if (!oldVNode || !oldVNode._original) {
268+
if (!~matchingIndex) {
265269
// When the array of children is growing we need to decrease the skew
266270
// as we are adding a new element to the array.
267271
// Example:
@@ -330,7 +334,7 @@ function constructNewChildrenArray(
330334
if (remainingOldChildren) {
331335
for (i = 0; i < oldChildrenLength; i++) {
332336
oldVNode = oldChildren[i];
333-
if (oldVNode != NULL && (oldVNode._flags & MATCHED) == 0) {
337+
if (oldVNode && !(oldVNode._flags & MATCHED)) {
334338
if (oldVNode._dom == oldDom) {
335339
oldDom = getDomSibling(oldVNode);
336340
}
@@ -388,7 +392,7 @@ function insert(parentVNode, oldDom, parentDom, shouldPlace, isMounting) {
388392

389393
do {
390394
oldDom = oldDom && oldDom.nextSibling;
391-
} while (oldDom != NULL && oldDom.nodeType == 8);
395+
} while (oldDom && oldDom.nodeType == 8);
392396

393397
return oldDom;
394398
}
@@ -428,7 +432,7 @@ function findMatchingIndex(
428432
const key = childVNode.key;
429433
const type = childVNode.type;
430434
let oldVNode = oldChildren[skewedIndex];
431-
const matched = oldVNode != NULL && (oldVNode._flags & MATCHED) == 0;
435+
const matched = oldVNode && !(oldVNode._flags & MATCHED);
432436

433437
// We only need to perform a search if there are more children
434438
// (remainingOldChildren) to search. However, if the oldVNode we just looked
@@ -443,10 +447,12 @@ function findMatchingIndex(
443447
// we should not search as we risk re-using state of an unrelated VNode. (reverted for now)
444448
let shouldSearch =
445449
// (typeof type != 'function' || type === Fragment || key) &&
450+
// The ternary keeps this a Smi comparison; `> matched` would compare
451+
// number to boolean which V8 can't serve from the fast path.
446452
remainingOldChildren > (matched ? 1 : 0);
447453

448454
if (
449-
(oldVNode === NULL && key == null) ||
455+
(oldVNode === NULL && key == NULL) ||
450456
(matched && key == oldVNode.key && type == oldVNode.type)
451457
) {
452458
return skewedIndex;
@@ -457,8 +463,8 @@ function findMatchingIndex(
457463
const childIndex = x >= 0 ? x-- : y++;
458464
oldVNode = oldChildren[childIndex];
459465
if (
460-
oldVNode != NULL &&
461-
(oldVNode._flags & MATCHED) == 0 &&
466+
oldVNode &&
467+
!(oldVNode._flags & MATCHED) &&
462468
key == oldVNode.key &&
463469
type == oldVNode.type
464470
) {

0 commit comments

Comments
 (0)