Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Fixed more bugs + added more tests + bumped version
  • Loading branch information
trueadm committed Jan 17, 2019
commit f472a2af8bed7505af347a99a50e12a133bba752
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`Babel plugin optimize React hooks should support destructuring hooks from imports #2 1`] = `
exports[`React hook transforms should support destructuring hooks from imports #2 1`] = `
"import React from \\"react\\";
const __reactCreateElement__ = React.createElement;
const {
Expand All @@ -15,7 +15,7 @@ export function MyComponent() {
}"
`;

exports[`Babel plugin optimize React hooks should support destructuring hooks from imports #3 1`] = `
exports[`React hook transforms should support destructuring hooks from imports #3 1`] = `
"import React from \\"react\\";
const __reactCreateElement__ = React.createElement;
const useState = React.useState;
Expand All @@ -28,7 +28,7 @@ export function MyComponent() {
}"
`;

exports[`Babel plugin optimize React hooks should support destructuring hooks from imports #4 1`] = `
exports[`React hook transforms should support destructuring hooks from imports #4 1`] = `
"import React from \\"react\\";
const __reactCreateElement__ = React.createElement;
const foo = React.useState;
Expand All @@ -41,7 +41,7 @@ export function MyComponent() {
}"
`;

exports[`Babel plugin optimize React hooks should support destructuring hooks from imports #5 1`] = `
exports[`React hook transforms should support destructuring hooks from imports #5 1`] = `
"import React from \\"react\\";
const __reactCreateElement__ = React.createElement;
const {
Expand All @@ -56,7 +56,7 @@ export function MyComponent() {
}"
`;

exports[`Babel plugin optimize React hooks should support destructuring hooks from imports 1`] = `
exports[`React hook transforms should support destructuring hooks from imports 1`] = `
"import React from \\"react\\";
const __reactCreateElement__ = React.createElement;
const {
Expand All @@ -71,7 +71,7 @@ export function MyComponent() {
}"
`;

exports[`Babel plugin optimize React hooks should support destructuring hooks from require calls 1`] = `
exports[`React hook transforms should support destructuring hooks from require calls 1`] = `
"const React = require(\\"react\\");

const __reactCreateElement__ = React.createElement;
Expand All @@ -87,105 +87,40 @@ export function MyComponent() {
}"
`;

exports[`Babel plugin optimize React hooks should support transform hook imports 1`] = `
"import React from \\"react\\";
const {
exports[`React hook transforms should support hook CJS require with no default 1`] = `
"const {
useState
} = React;"
} = require(\\"react\\");"
`;

exports[`Babel plugin optimize React hooks should support transform hook imports with aliasing 1`] = `
exports[`React hook transforms should support hook imports with aliasing 1`] = `
"import React from \\"react\\";
const {
useState: foo
} = React;"
`;

exports[`React hook transforms should support destructuring hooks from imports #2 1`] = `
exports[`React hook transforms should support hook imports with no default 1`] = `
"import React from \\"react\\";
const __reactCreateElement__ = React.createElement;
const {
useState
} = React;
export function MyComponent() {
const _ref_0 = useState(0);

const setCounter = _ref_0[1];
const counter = _ref_0[0];
return __reactCreateElement__(\\"div\\", null, counter);
}"
`;

exports[`React hook transforms should support destructuring hooks from imports #3 1`] = `
"import React from \\"react\\";
const __reactCreateElement__ = React.createElement;
const useState = React.useState;
export function MyComponent() {
const _ref_0 = useState(0);

const setCounter = _ref_0[1];
const counter = _ref_0[0];
return __reactCreateElement__(\\"div\\", null, counter);
}"
`;

exports[`React hook transforms should support destructuring hooks from imports #4 1`] = `
"import React from \\"react\\";
const __reactCreateElement__ = React.createElement;
const foo = React.useState;
export function MyComponent() {
const _ref_0 = foo(0);

const setCounter = _ref_0[1];
const counter = _ref_0[0];
return __reactCreateElement__(\\"div\\", null, counter);
}"
`;

exports[`React hook transforms should support destructuring hooks from imports #5 1`] = `
"import React from \\"react\\";
const __reactCreateElement__ = React.createElement;
const {
useState: foo
} = React;
export function MyComponent() {
const _ref_0 = foo(0);

const setCounter = _ref_0[1];
const counter = _ref_0[0];
return __reactCreateElement__(\\"div\\", null, counter);
}"
} = React;"
`;

exports[`React hook transforms should support destructuring hooks from imports 1`] = `
exports[`React hook transforms should support mixed hook imports 1`] = `
"import React from \\"react\\";
const __reactCreateElement__ = React.createElement;
import { memo } from \\"react\\";
const {
useState
} = React;
export function MyComponent() {
const _ref_0 = useState(0);

const setCounter = _ref_0[1];
const counter = _ref_0[0];
return __reactCreateElement__(\\"div\\", null, counter);
}"
} = React;"
`;

exports[`React hook transforms should support destructuring hooks from require calls 1`] = `
"const React = require(\\"react\\");

const __reactCreateElement__ = React.createElement;
exports[`React hook transforms should support mixed hook imports with no default 1`] = `
"import React from \\"react\\";
const {
useState
} = React;
export function MyComponent() {
const _ref_0 = useState(0);

const setCounter = _ref_0[1];
const counter = _ref_0[0];
return __reactCreateElement__(\\"div\\", null, counter);
}"
import { memo } from \\"react\\";"
`;

exports[`React hook transforms should support transform hook imports 1`] = `
Expand All @@ -194,17 +129,3 @@ const {
useState
} = React;"
`;

exports[`React hook transforms should support transform hook imports with aliasing 1`] = `
"import React from \\"react\\";
const {
useState: foo
} = React;"
`;

exports[`React hook transforms should support transform hook imports with no default 1`] = `
"import React from \\"react\\";
const {
useState
} = React;"
`;
30 changes: 28 additions & 2 deletions packages/babel-plugin-optimize-react/__tests__/hooks-test.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ describe('React hook transforms', () => {
expect(output).toMatchSnapshot();
});

it('should support transform hook imports with aliasing', () => {
it('should support hook imports with aliasing', () => {
const test = `
import React, {useState as foo} from "react";
`;
Expand Down Expand Up @@ -114,11 +114,37 @@ describe('React hook transforms', () => {
expect(output).toMatchSnapshot();
});

it('should support transform hook imports with no default', () => {
it('should support hook imports with no default', () => {
const test = `
import {useState} from "react";
`;
const output = transform(test);
expect(output).toMatchSnapshot();
});

it('should support hook CJS require with no default', () => {
const test = `
const {useState} = require("react");
`;
const output = transform(test);
expect(output).toMatchSnapshot();
});

it('should support mixed hook imports', () => {
const test = `
import React from "react";
import {memo, useState} from "react";
`;
const output = transform(test);
expect(output).toMatchSnapshot();
});

it('should support mixed hook imports with no default', () => {
const test = `
import {useState} from "react";
import {memo} from "react";
`;
const output = transform(test);
expect(output).toMatchSnapshot();
});
});
29 changes: 20 additions & 9 deletions packages/babel-plugin-optimize-react/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@ module.exports = function(babel) {
const { types: t } = babel;

// Collects named imports of React hooks from the "react" package
function collectReactHooksAndRemoveTheirNamedImports(path) {
function collectReactHooksAndRemoveTheirNamedImports(path, state) {
const node = path.node;
const hooks = [];
if (t.isStringLiteral(node.source) && node.source.value === 'react') {
const specifiers = path.get('specifiers');
let hasDefaultSpecifier = false;
if (state.hasDefaultSpecifier === undefined) {
state.hasDefaultSpecifier = false;
}

for (let specifier of specifiers) {
if (t.isImportSpecifier(specifier)) {
Expand All @@ -39,14 +41,17 @@ module.exports = function(babel) {
}
}
} else if (t.isImportDefaultSpecifier(specifier)) {
hasDefaultSpecifier = true;
state.hasDefaultSpecifier = true;
}
}
// If there is no default specifier for React, add one
if (!hasDefaultSpecifier && specifiers.length > 0) {
const defaultSpecifierNode = t.importDefaultSpecifier(t.identifier("React"));

if (state.hasDefaultSpecifier === false && specifiers.length > 0) {
const defaultSpecifierNode = t.importDefaultSpecifier(
t.identifier('React')
);

path.pushContainer('specifiers', defaultSpecifierNode);
state.hasDefaultSpecifier = true;
}
}
return hooks;
Expand Down Expand Up @@ -180,7 +185,10 @@ module.exports = function(babel) {
]);
const bindingPath = binding.path;

if (t.isImportDefaultSpecifier(bindingPath) || t.isVariableDeclarator(bindingPath)) {
if (
t.isImportDefaultSpecifier(bindingPath) ||
t.isVariableDeclarator(bindingPath)
) {
bindingPath.parentPath.insertAfter(createElementDeclaration);
// Make sure we declare our new now so scope tracking continues to work
const reactElementDeclarationPath = bindingPath.parentPath.getNextSibling();
Expand All @@ -192,12 +200,15 @@ module.exports = function(babel) {
return {
name: 'babel-plugin-optimize-react',
visitor: {
ImportDeclaration(path) {
ImportDeclaration(path, state) {
// Collect all hooks that are named imports from the React package. i.e.:
// import React, {useState} from "react";
// As we collection them, we also remove the imports from the declaration.

const importedHooks = collectReactHooksAndRemoveTheirNamedImports(path);
const importedHooks = collectReactHooksAndRemoveTheirNamedImports(
path,
state
);
if (importedHooks.length > 0) {
// Create a destructured variable declaration. i.e.:
// const {useEffect, useState} = React;
Expand Down
2 changes: 1 addition & 1 deletion packages/babel-plugin-optimize-react/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "babel-plugin-optimize-react",
"version": "0.0.2",
"version": "0.0.3",
"description": "Babel plugin for optimizing common React patterns",
"repository": "facebookincubator/create-react-app",
"license": "MIT",
Expand Down