Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

reflective-bind

Package Overview
Dependencies
Maintainers
1
Versions
18
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

reflective-bind - npm Package Compare versions

Comparing version 0.0.4 to 0.1.0

79

babel/index.js

@@ -50,2 +50,3 @@ /**

let _propRegexCompiled;
let _filename;

@@ -68,2 +69,3 @@ let _hoistedSlug;

log = "off",
propRegex = undefined,

@@ -84,2 +86,4 @@ // Hoisted function name prefix

logger.setLevel(log);
_propRegexCompiled =
propRegex != null ? new RegExp(propRegex) : undefined;
_filename = file.opts.filename;

@@ -130,4 +134,6 @@ _hoistPath = path;

JSXAttribute(path) {
// Don't transform ref callbacks
if (t.isJSXIdentifier(path.node.name) && path.node.name.name === "ref") {
if (
t.isJSXIdentifier(path.node.name) &&
shouldSkipProp(path.node.name.name)
) {
path.skip();

@@ -158,2 +164,8 @@ }

function shouldSkipProp(name) {
return (
name === "ref" || (_propRegexCompiled && !_propRegexCompiled.test(name))
);
}
function processPath(path, state) {

@@ -328,3 +340,3 @@ if (t.isVariableDeclarator(path)) {

// We must detect this case, and prevent the hoisting from happening.
isBindingDefinitelyBeforePath(binding, state.fnPath) &&
isPathDefinitelyBeforeOtherPath(binding.path, state.fnPath) &&
// For all constantViolations, we have to make sure they also come

@@ -340,4 +352,5 @@ // before the fnPath, otherwise we will bind to the wrong value.

makeMsg(
`Cannot transform arrow function because the variable '${path.node
.name}' is assigned to after the arrow function definition.`,
`Cannot transform arrow function because the variable '${
path.node.name
}' is assigned to after the arrow function definition.`,
path

@@ -407,28 +420,2 @@ )

function isBindingDefinitelyBeforePath(binding, path) {
const isBindingFnDeclaration = t.isFunctionDeclaration(binding.path);
/* istanbul ignore if */
if (isBindingFnDeclaration && binding.identifier !== binding.path.node.id) {
throw new Error(
"binding identifier does not match the function declaration id"
);
}
// If the binding is a function declaration (e.g. function foo() {}),
// binding.path.scope will get you the scope of the actual function, not
// the scope the binding is created in. Need to do
// binding.path.parentPath.scope instead.
const bscope = isBindingFnDeclaration
? binding.path.parentPath.scope
: binding.path.scope;
/* istanbul ignore if */
if (bscope !== path.scope && !isAncestorScope(bscope, path.scope)) {
throw new Error(
"binding's scope must be equal to or is an ancestor of the path's scope"
);
}
return isPathDefinitelyBeforeOtherPath(binding.path, path);
}
// Returns true iff we are 100% sure checkPath is executed before otherPath.

@@ -524,16 +511,2 @@ // https://github.com/babel/babel/blob/75808a2d14a5872472eb12ee5135faca4950d57a/packages/babel-traverse/src/path/introspection.js#L216

// Returns true iff maybeAncestorScope is an ancestor of startScope.
// A scope is not an ancestor of itself:
// isAncestor(someScope, someScope) === false
function isAncestorScope(maybeAncestorScope, startScope) {
let curScope = startScope.parent;
while (curScope) {
if (maybeAncestorScope === curScope) {
return true;
}
curScope = curScope.parent;
}
return false;
}
// Return the indices in the ancestor arrays of where the common ancestor

@@ -656,6 +629,6 @@ // is. If no common ancestor, return [-1, -1].

* TODO: move this blob of text out to the docs and link to it.
*
*
* Checks if the path is part of a nested property access.
* This means that it is of the form `pathNode.foo`.
*
*
* We want to encourage developers to manually hoist these nested propery

@@ -665,7 +638,7 @@ * accesses out to constant variables to reduce wasted re-renders because

* function.
*
*
* For example:
* const obj = {...};
* const handleClick = () => this.setState({foo: obj.a.b.c});
*
*
* Is transformed to:

@@ -678,3 +651,3 @@ * function _hoisted(obj) {

* const handleClick = babelBind(_hoisted, this, obj);
*
*
* In this case, the handleClick function will not be reflectively equal

@@ -686,3 +659,3 @@ * whenever the `obj` references changes. It is better for the user to

* const handleClick = () => this.setState({foo: c});
*
*
* This is transformed to:

@@ -696,6 +669,6 @@ * function _hoisted(c) {

* const handleClick = babelBind(_hoisted, this, c);
*
*
* Which will be reflectively equal as long as c doesn't change value, even
* if the `obj` reference changes.
*
*
* Note that `pathNode.foo()` is ok because pulling `pathNode.foo` out and

@@ -702,0 +675,0 @@ * calling `foo()` on its own does not result in the right context within

@@ -7,8 +7,10 @@ # Reflective Bind Change Log

## 0.1.0
* Add "propRegex" option to only transform matching prop names.
## 0.0.4
* Add "log" option to log general transform info and warnings.
* Log info about which inline functions are transformed.
* Log warnings about sub-optimial code and how to fix it.
## 0.0.4-rc2
* Don't transform inline functions on `ref` prop.

@@ -15,0 +17,0 @@ * Don't transform arrow functions defined at the top level.

{
"name": "reflective-bind",
"version": "0.0.4",
"version": "0.1.0",
"description": "Eliminate wasteful re-rendering in React components caused by inline functions",

@@ -5,0 +5,0 @@ "author": "Dounan Shi",

@@ -22,3 +22,3 @@ [![Build Status](https://travis-ci.org/flexport/reflective-bind.svg?branch=master)](https://travis-ci.org/flexport/reflective-bind)

*NOTE: the design goal of the plugin is to preserve the semantics of your code. Your inline functions will still create new function instances each render. The transform simply enables the equality comparison of two function instances via reflection.*
_NOTE: the design goal of the plugin is to preserve the semantics of your code. Your inline functions will still create new function instances each render. The transform simply enables the equality comparison of two function instances via reflection._

@@ -29,3 +29,3 @@ Add it to the top of your plugin list in `.babelrc` (it must be run before other plugins that transform arrow functions and `bind` calls):

"plugins": [
["reflective-bind/babel", {log: "debug"}],
["reflective-bind/babel", {"log": "debug"}],
...

@@ -70,10 +70,17 @@ ]

#### log (*default: off*)
#### propRegex (_default: transform all props_)
When specified, only transform props whose name matches the regular expression. The intended use case is to avoid transforming render callbacks, as this can lead to stale render bugs.
For example, if all of your non-render callbacks are prefixed with `on`, such as `onClick`, consider using `"propRegex": "^on[A-Z].*$"`.
#### log (_default: off_)
Specifies the minimum level of logs to output to the console. Enabling logging at a given level also enables logging at all higher levels.
- **debug** - output messages useful for debugging (e.g. which functions are transformed).
- **info** - output helpful information (e.g. optimization tips).
- **warn** - output warnings (e.g. which functions cannot be transformed). These can usually be fixed with some simple refactoring.
- **off** - disable logging. Recommended for production.
* **debug** - output messages useful for debugging (e.g. which functions are transformed).
* **info** - output helpful information (e.g. optimization tips).
* **warn** - output warnings (e.g. which functions cannot be transformed). These can usually be fixed with some simple refactoring.
* **off** - disable logging. Recommended for production.
### Dependencies

@@ -101,7 +108,7 @@

fn1 === fn2 // false
reflectiveEqual(fn1, fn2) // true
fn1 === fn2; // false
reflectiveEqual(fn1, fn2); // true
const fn3 = reflectiveBind(baseFn, undefined, "world");
reflectiveEqual(fn1, fn3) // false
reflectiveEqual(fn1, fn3); // false
```

@@ -112,4 +119,4 @@

```js
reflectiveEqual(1, 1) // false
reflectiveEqual(baseFn, baseFn) // false
reflectiveEqual(1, 1); // false
reflectiveEqual(baseFn, baseFn); // false
```

@@ -145,3 +152,3 @@

- Inline arrow functions:
* Inline arrow functions:

@@ -151,7 +158,7 @@ ```jsx

const msg = "Hello " + props.user.name.first;
return <PureChild onClick={() => alert(msg)} />
return <PureChild onClick={() => alert(msg)} />;
}
```
- `Function.prototype.bind`:
* `Function.prototype.bind`:

@@ -161,7 +168,7 @@ ```jsx

const handleClick = props.callback.bind(undefined, "yay");
return <PureChild onClick={handleClick} />
return <PureChild onClick={handleClick} />;
}
```
- Multiple assignments / reassignments:
* Multiple assignments / reassignments:

@@ -171,3 +178,3 @@ ```jsx

let handleClick = () => {...};
if (...) {

@@ -183,3 +190,3 @@ handleClick = () => {...};

- Ternary expressions:
* Ternary expressions:

@@ -196,14 +203,13 @@ ```jsx

- For maximum optimization, avoid accessing nested attributes in your arrow function. Prefer to pull the nested value out to a const and close over it in your arrow function.
* For maximum optimization, avoid accessing nested attributes in your arrow function. Prefer to pull the nested value out to a const and close over it in your arrow function.
```jsx
function MyComponent(props) {
// PureChild will re-render whenever `props` changes (bad)
const badHandleClick = () => alert(props.user.name.first);
const badHandleClick = () => alert(props.user.name.first);
const firstName = props.user.name.first;
// Now, PureChild will only re-render when firstName changes (good)
const goodHandleClick = () => alert(firstName);
return (

@@ -222,3 +228,3 @@ <div>

- Your arrow function should not close over variables whose value is set after the arrow function.
* Your arrow function should not close over variables whose value is set after the arrow function.

@@ -228,3 +234,3 @@ ```jsx

let foo = 1;
const badHandleClick = () => {

@@ -235,10 +241,10 @@ // Referencing `foo`, which is reassigned after this arrow function, will

};
foo = 2;
return <PureChild onClick={badHandleClick} />
return <PureChild onClick={badHandleClick} />;
}
```
- Your arrow function must be defined inline the JSX, or at most 1 reference away.
* Your arrow function must be defined inline the JSX, or at most 1 reference away.

@@ -251,13 +257,13 @@ ```jsx

const badHandleClick = fn;
// This arrow function will be transformed since `goodHandleClick` is
// referenced directly in the JSX.
const goodHandleClick = () => {...};
return (
<div>
<PureChild onClick={badHandleClick} />
<PureChild onClick={goodHandleClick} />
{/* This will be optimized since it is defined directly in the JSX */}

@@ -264,0 +270,0 @@ <PureChild onClick={() => {...}} />

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc