Skip to content

Commit

Permalink
Merge branch 'master' into debug-component-thrashing
Browse files Browse the repository at this point in the history
  • Loading branch information
developit committed May 20, 2019
2 parents da9ed2a + c696534 commit c0e710f
Show file tree
Hide file tree
Showing 36 changed files with 1,452 additions and 297 deletions.
2 changes: 2 additions & 0 deletions .travis.yml
Expand Up @@ -28,3 +28,5 @@ script:
- npm run build
- COVERAGE=true npm run test
- ./node_modules/coveralls/bin/coveralls.js < ./coverage/lcov.info;

after_success: sizereport --config
1 change: 1 addition & 0 deletions compat/package.json
Expand Up @@ -8,6 +8,7 @@
"module": "dist/compat.module.js",
"umd:main": "dist/compat.umd.js",
"source": "src/index.js",
"types": "src/index.d.ts",
"license": "MIT",
"mangle": {
"regex": "^_"
Expand Down
10 changes: 9 additions & 1 deletion compat/server.js
@@ -1,5 +1,13 @@
/* eslint-disable */
var renderToString = dep(require('preact-render-to-string'));
var renderToString
try {
renderToString = dep(require('preact-render-to-string'));
} catch (e) {
throw new Error(
'You seem to be missing the "preact-render-to-string" dependency.\n' +
'You can add this by using "npm install --save preact-render-to-string@next".'
)
}

function dep(obj) { return obj['default'] || obj; }

Expand Down
75 changes: 75 additions & 0 deletions compat/src/index.d.ts
@@ -0,0 +1,75 @@
import * as _hooks from '../../hooks';
import * as preact from '../../src';
import { ForwardFn } from './internal';

export * from '../../hooks';
export import Component = preact.Component;
export import createContext = preact.createContext;
export import createRef = preact.createRef;
export import Fragment = preact.Fragment;
export import createElement = preact.createElement
export import cloneElement = preact.cloneElement
export import Suspense = preact.Suspense;
export import lazy = preact.lazy;

export declare const version: string;

export declare function createPortal(vnode: preact.VNode, container: Element | Element): preact.VNode<any>;

export declare function render(vnode: preact.VNode<any>, parent: Element, callback?: () => void): Component | null;

export declare function hydrate(vnode: preact.VNode<any>, parent: Element, callback?: () => void): Component | null;

export declare function unmountComponentAtNode(container: Element | Document | ShadowRoot | DocumentFragment): boolean;

export declare function createFactory(type: preact.VNode["type"]): preact.VNode<{}>;

export declare function isValidElement(element: any): boolean;

export declare function findDOMNode(component: preact.Component): Element | null;

export declare interface PureComponent<P = {}, S = {}> extends preact.Component {
isPureReactComponenet: boolean;
}

export declare function memo<P = {}>(component: preact.FunctionalComponent<P>, comparer?: (prev: P, next: P) => boolean): preact.FunctionComponent<P>;

export declare function forwardRef<P = {}>(fn: ForwardFn<P, any>): preact.FunctionalComponent<P>;

export declare function unstable_batchedUpdates(callback: (arg?: any) => void, arg?: any): void;


export declare interface Children {
map<T extends preact.ComponentChild, R>(children: T | T[], fn: (child: T, i: number, array: T[]) => R): R[];
forEach<T extends preact.ComponentChild>(children: T | T[], fn: (child: T, i: number, array: T[]) => void): void;
count: (children: preact.ComponentChildren) => number;
only: (children: preact.ComponentChildren) => preact.ComponentChild;
toArray: (children: preact.ComponentChildren) => preact.VNode<{}>[];
}

declare const _default: {
hooks: typeof _hooks,
Component: Component,
createContext: typeof createContext,
createRef: typeof createRef,
Fragment: typeof Fragment,
createElement: typeof createElement,
cloneElement: typeof cloneElement,
version: typeof version,
createPortal: typeof createPortal,
render: typeof render,
hydrate: typeof render,
unmountComponentAtNode: typeof unmountComponentAtNode,
createFactory: typeof createFactory,
isValidElement: typeof isValidElement,
findDOMNode: typeof findDOMNode,
PureComponent: PureComponent,
memo: typeof memo,
forwardRef: typeof forwardRef,
unstable_batchedUpdates: typeof unstable_batchedUpdates,
Children: Children,
Suspense: typeof Suspense,
lazy: typeof lazy,
};

export default _default;
32 changes: 17 additions & 15 deletions compat/src/index.js
@@ -1,4 +1,4 @@
import { render as preactRender, cloneElement as preactCloneElement, createRef, h, Component, options, toChildArray, createContext, Fragment } from 'preact';
import { render as preactRender, cloneElement as preactCloneElement, createRef, h, Component, options, toChildArray, createContext, Fragment, Suspense, lazy } from 'preact';
import * as hooks from 'preact/hooks';
export * from 'preact/hooks';
import { assign } from '../../src/util';
Expand All @@ -15,8 +15,7 @@ options.event = e => {
/* istanbul ignore next */
if (oldEventHook) e = oldEventHook(e);
e.persist = () => {};
e.nativeEvent = e;
return e;
return e.nativeEvent = e;
};

/**
Expand Down Expand Up @@ -54,7 +53,7 @@ function render(vnode, parent, callback) {
preactRender(vnode, parent);
if (typeof callback==='function') callback();

return vnode!=null ? vnode._component : null;
return vnode ? vnode._component : null;
}

class ContextProvider {
Expand Down Expand Up @@ -89,9 +88,8 @@ function createPortal(vnode, container) {
}

const mapFn = (children, fn) => {
if (children == null) return null;
children = toChildArray(children);
return children.map(fn);
if (!children) return null;
return toChildArray(children).map(fn);
};

// This API is completely unnecessary for Preact, so it's basically passthrough.
Expand Down Expand Up @@ -130,7 +128,7 @@ function createElement(...args) {

if (Array.isArray(props.value) && props.multiple && type==='select') {
toChildArray(props.children).forEach((child) => {
if (props.value.indexOf(child.props.value)!==-1) {
if (props.value.indexOf(child.props.value)!=-1) {
child.props.selected = true;
}
});
Expand Down Expand Up @@ -173,15 +171,15 @@ function cloneElement(element) {
* @returns {boolean}
*/
function isValidElement(element) {
return element!=null && element.$$typeof===REACT_ELEMENT_TYPE;
return !!element && element.$$typeof===REACT_ELEMENT_TYPE;
}

/**
* Normalize event handlers like react does. Most famously it uses `onChange` for any input element.
* @param {import('./internal').VNode} vnode The vnode to normalize events on
*/
function applyEventNormalization({ type, props }) {
if (!props || typeof type!=='string') return;
if (!props || typeof type!='string') return;
let newProps = {};
for (let i in props) {
newProps[i.toLowerCase()] = i;
Expand Down Expand Up @@ -210,7 +208,7 @@ function applyEventNormalization({ type, props }) {
* @returns {boolean}
*/
function unmountComponentAtNode(container) {
if (container._prevVNode!=null) {
if (container._prevVNode) {
preactRender(null, container);
return true;
}
Expand Down Expand Up @@ -288,7 +286,7 @@ function memo(c, comparer) {
if (!updateRef) {
ref.call ? ref(null) : (ref.current = null);
}
return (comparer==null
return (!comparer
? shallowDiffers(this.props, nextProps)
: !comparer(this.props, nextProps)) || !updateRef;
}
Expand Down Expand Up @@ -339,7 +337,7 @@ options.vnode = vnode => {

applyEventNormalization(vnode);
let type = vnode.type;
if (type!=null && type._forwarded && vnode.ref!=null) {
if (type && type._forwarded && vnode.ref) {
vnode.props.ref = vnode.ref;
vnode.ref = null;
}
Expand Down Expand Up @@ -378,7 +376,9 @@ export {
memo,
forwardRef,
// eslint-disable-next-line camelcase
unstable_batchedUpdates
unstable_batchedUpdates,
Suspense,
lazy
};

// React copies the named exports to the default one.
Expand All @@ -401,5 +401,7 @@ export default assign({
PureComponent,
memo,
forwardRef,
unstable_batchedUpdates
unstable_batchedUpdates,
Suspense,
lazy
}, hooks);
27 changes: 23 additions & 4 deletions debug/src/debug.js
Expand Up @@ -8,6 +8,7 @@ export function initDebug() {
let oldBeforeDiff = options.diff;
let oldDiffed = options.diffed;
let oldVnode = options.vnode;
const warnedComponents = { useEffect: {}, useLayoutEffect: {} };

options.root = (vnode, parentNode) => {
if (!parentNode) {
Expand Down Expand Up @@ -92,6 +93,22 @@ export function initDebug() {

// Check prop-types if available
if (typeof vnode.type==='function' && vnode.type.propTypes) {
if (vnode.type.displayName === 'Lazy') {
const m = 'PropTypes are not supported on lazy(). Use propTypes on the wrapped component itself. ';
try {
const lazyVNode = vnode.type();
console.warn(m + 'Component wrapped in lazy() is ' + (lazyVNode.type.displayName || lazyVNode.type.name));
}
catch (promise) {
console.warn(m + 'We will log the wrapped component\'s name once it is loaded.');
if (promise.then) {
promise.then((exports) => {
console.warn('Component wrapped in lazy() is ' + (exports.default.displayName || exports.default.name));
});
}

}
}
checkPropTypes(vnode.type.propTypes, vnode.props, getDisplayName(vnode), serializeVNode(vnode));
}

Expand Down Expand Up @@ -168,19 +185,21 @@ export function initDebug() {
});
if (hooks._pendingEffects.length > 0) {
hooks._pendingEffects.forEach((effect) => {
if (!effect._args || !Array.isArray(effect._args)) {
if ((!effect._args || !Array.isArray(effect._args)) && !warnedComponents.useEffect[vnode.type]) {
warnedComponents.useEffect[vnode.type] = true;
/* istanbul ignore next */
throw new Error('You should provide an array of arguments as the second argument to the "useEffect" hook.\n\n' +
console.warn('You should provide an array of arguments as the second argument to the "useEffect" hook.\n\n' +
'Not doing so will invoke this effect on every render.\n\n' +
'This effect can be found in the render of ' + (vnode.type.name || vnode.type) + '.');
}
});
}
if (hooks._pendingLayoutEffects.length > 0) {
hooks._pendingLayoutEffects.forEach((layoutEffect) => {
if (!layoutEffect._args || !Array.isArray(layoutEffect._args)) {
if ((!layoutEffect._args || !Array.isArray(layoutEffect._args)) && !warnedComponents.useLayoutEffect[vnode.type]) {
warnedComponents.useLayoutEffect[vnode.type] = true;
/* istanbul ignore next */
throw new Error('You should provide an array of arguments as the second argument to the "useEffect" hook.\n\n' +
console.warn('You should provide an array of arguments as the second argument to the "useLayoutEffect" hook.\n\n' +
'Not doing so will invoke this effect on every render.\n\n' +
'This effect can be found in the render of ' + (vnode.type.name || vnode.type) + '.');
}
Expand Down
8 changes: 4 additions & 4 deletions debug/src/devtools/custom.js
Expand Up @@ -82,13 +82,13 @@ export function getData(vnode) {
ref: vnode.ref || null,
key: vnode.key || null,
updater,
text: vnode.text,
text: vnode.type===null ? vnode.props : null,
state: c!=null && c instanceof Component ? c.state : null,
props: vnode.props,
// The devtools inline text children if they are the only child
children: vnode.text==null
? children!=null && children.length==1 && children[0].text!=null
? children[0].text
children: vnode.type!==null
? children!=null && children.length==1 && children[0].type===null
? children[0].props
: children
: null,
publicInstance: getInstance(vnode),
Expand Down

0 comments on commit c0e710f

Please sign in to comment.