Skip to content

Commit

Permalink
fix: fix so that we dont blow up when encountering an "export default… (
Browse files Browse the repository at this point in the history
#4)

* fix: fix so that we dont blow up when encountering an "export default class ..."

also adds tests to cover various scenarios

* fix: have wrapped classes actually return the class

* fix: wrap in standard function instead of arrow function for better compatibility

ideally we would be able to have it go through preset-env to get it to transform the arrow functions if necessary, but we dont appear to get that for free the way we are doing this. perhaps it can be investigated in the future

* updated readme, added changelog, and prepared for publishing

Co-authored-by: Matt Browne <[email protected]>
  • Loading branch information
ammmze and mbrowne authored Mar 10, 2021
1 parent 417e5be commit b238a8c
Show file tree
Hide file tree
Showing 24 changed files with 3,450 additions and 49 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,5 @@ node_modules
*.log
lib
.DS_Store
.idea
*.tgz
20 changes: 20 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Changelog

All notable changes to this project will be documented in this file.

The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).

## 0.2.0

### Fixed

Fix bug when encountering `export default` with class components

### Added

Test suite

## 0.1.0

Initial version
37 changes: 31 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,37 @@
# babel-plugin-pure-static-props

## DEPRECATED
Fixes an issue with tree shaking that can occur when using static properties on React components using styled-components.

This plugin is deprecated in favor of https://github.com/styled-components/babel-plugin-styled-components/pull/248.
It's possible that something other than styled-components might cause a similar issue, in which case this plugin might still be useful, but I won't be maintaining it. (Also, my implementation for babel-plugin-styled-components is a bit more efficient than what I did here.)
This plugin replaces static property assignments on React components (e.g. `MyComponent.defaultProps = {...}`) with `Object.assign()` statements annotated with `/*#__PURE__*/` comments so that tree-shaking will work correctly.

---
## Install

Fixes an issue with tree shaking that can occur when using static properties on React components using styled-components.
```bash
npm i -D babel-plugin-pure-static-props
```

This plugin replaces static property assignments on React components (e.g. `MyComponent.defaultProps = {...}`) with `Object.assign()` statements annotated with `/*#__PURE__*/` comments so that tree-shaking will work correctly.
Or:

```bash
yarn add -D babel-plugin-pure-static-props
```

Then add the plugin to your Babel config as explained in the [Babel documentation](https://babeljs.io/docs/en/options#plugin-and-preset-options).

Example `babel.config.js`:

```js
module.exports = {
presets: ['@babel/preset-env'],
plugins: [
'@babel/plugin-proposal-class-properties',
'babel-plugin-pure-static-props',
],
}
```

## Note on styled components

The tree-shaking issue with static properties on React components also affects [styled components](https://styled-components.com/). This plugin only addresses tree-shaking for regular React components; it will not work on components created using the `styled` helper.

A fix for styled components is in this PR: https://github.com/styled-components/babel-plugin-styled-components/pull/248.
37 changes: 23 additions & 14 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "babel-plugin-pure-static-props",
"version": "0.1.0",
"version": "0.2.0",
"description": "Fixes issue with tree shaking that can occur when using static properties on React components using styled-components",
"main": "lib/index.js",
"files": [
Expand All @@ -9,33 +9,42 @@
"repository": "https://github.com/mbrowne/babel-plugin-pure-static-props",
"author": "Matt Browne",
"license": "ISC",
"devDependencies": {
"@babel/cli": "^7.5.5",
"@babel/core": "^7.5.5",
"@babel/plugin-proposal-class-properties": "^7.5.5",
"@babel/preset-env": "^7.5.5",
"prettier": "^1.18.2",
"rimraf": "^3.0.0"
},
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.0.0",
"babel-plugin-syntax-jsx": "^6.18.0"
},
"scripts": {
"clean": "rimraf lib",
"style": "prettier --write src/**/*.js",
"build": "babel src -d lib",
"watch": "yarn build -w",
"prepublishOnly": "npm-run-all test build",
"test": "jest",
"test:watch": "yarn test -- --watch",
"prepublish": "yarn clean && yarn build"
},
"dependencies": {
"@babel/helper-annotate-as-pure": "^7.0.0",
"@babel/plugin-syntax-jsx": "^7.12.13"
},
"devDependencies": {
"@babel/cli": "^7.5.5",
"@babel/core": "^7.5.5",
"@babel/plugin-proposal-class-properties": "^7.5.5",
"@babel/preset-env": "^7.5.5",
"babel-plugin-tester": "^10.0.0",
"jest": "^26.6.3",
"npm-run-all": "^4.1.5",
"prettier": "^1.18.2",
"rimraf": "^3.0.0"
},
"keywords": [
"react",
"styled-components",
"tree shaking",
"code splitting",
"static properties",
"babel-plugin"
]
],
"jest": {
"watchPathIgnorePatterns": [
"__fixtures__\\/[^/]+\\/(output|error)\\.js"
]
}
}
45 changes: 32 additions & 13 deletions src/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import template from '@babel/template'
import syntax from 'babel-plugin-syntax-jsx'
import syntax from '@babel/plugin-syntax-jsx'
import annotateAsPure from '@babel/helper-annotate-as-pure'
import isStatelessComponent from './isStatelessComponent'
import isReactClass from './isReactClass'

const buildIife = template('(() => {\nBODY;\n})();')
const buildIife = template('(function() {\nBODY;\n})();')

export default function({ types: t }) {
// map of React function components to their static properties
Expand All @@ -24,7 +24,8 @@ export default function({ types: t }) {
path.get('superClass'),
path.scope,
{}
)
) &&
path.parentPath.type !== 'BlockStatement'
) {
const hasStaticProperties = path
.get('body.body')
Expand All @@ -36,19 +37,37 @@ export default function({ types: t }) {
if (hasStaticProperties) {
const componentNameIdentifier =
path.node.id
path.node.type = 'ClassExpression'
const iife = buildIife({
BODY: path.node,
BODY: [
path.node,
t.ReturnStatement(path.node.id),
],
})
annotateAsPure(iife.expression)
path.replaceWith(
t.VariableDeclaration('const', [
t.VariableDeclarator(
componentNameIdentifier,
iife.expression
),
])
)
const declarators = [
t.VariableDeclarator(
componentNameIdentifier,
iife.expression
),
]
if (
path.parentPath.isExportDefaultDeclaration()
) {
path.parentPath.insertBefore(
t.VariableDeclaration(
'const',
declarators
)
)
path.replaceWith(path.node.id)
} else {
path.replaceWith(
t.VariableDeclaration(
'const',
declarators
)
)
}
}
}
},
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
{
"plugins": [
"@babel/plugin-proposal-class-properties",
[
"../../../src"
]
]
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react'

export class MyComponent extends React.Component {
render() {
return <div>My Component</div>
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import React from 'react'
export class MyComponent extends React.Component {
render() {
return <div>My Component</div>
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
import React from 'react'

export function FunctionComponent() {
return <div>My Component</div>
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import React from 'react'
export function FunctionComponent() {
return <div>My Component</div>
}
8 changes: 8 additions & 0 deletions test/__fixtures__/wrap-class-components/code.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from 'react'

export class MyComponent extends React.Component {
static displayName = 'FancyName1'
render() {
return <div>My Component</div>
}
}
28 changes: 28 additions & 0 deletions test/__fixtures__/wrap-class-components/output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true,
})
} else {
obj[key] = value
}
return obj
}

import React from 'react'
export const MyComponent =
/*#__PURE__*/
(function () {
class MyComponent extends React.Component {
render() {
return <div>My Component</div>
}
}

_defineProperty(MyComponent, 'displayName', 'FancyName1')

return MyComponent
})()
8 changes: 8 additions & 0 deletions test/__fixtures__/wrap-class-pure-components/code.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from 'react'

export class MyComponent extends React.PureComponent {
static displayName = 'FancyName1'
render() {
return <div>My Component</div>
}
}
28 changes: 28 additions & 0 deletions test/__fixtures__/wrap-class-pure-components/output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true,
})
} else {
obj[key] = value
}
return obj
}

import React from 'react'
export const MyComponent =
/*#__PURE__*/
(function () {
class MyComponent extends React.PureComponent {
render() {
return <div>My Component</div>
}
}

_defineProperty(MyComponent, 'displayName', 'FancyName1')

return MyComponent
})()
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react'

export const FunctionComponent = () => {
return <div>My Component</div>
}
FunctionComponent.displayName = 'FancyName1'
FunctionComponent.defaultProps = {}
15 changes: 15 additions & 0 deletions test/__fixtures__/wrap-const-arrow-function-components/output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from 'react'

const FunctionComponent =
/*#__PURE__*/
(function () {
const FunctionComponent = () => {
return <div>My Component</div>
}

FunctionComponent.displayName = 'FancyName1'
FunctionComponent.defaultProps = {}
return FunctionComponent
})()

export { FunctionComponent }
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import React from 'react'

export default class MyComponent extends React.Component {
static displayName = 'FancyName1'
render() {
return <div>My Component</div>
}
}
31 changes: 31 additions & 0 deletions test/__fixtures__/wrap-default-export-class-components/output.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
function _defineProperty(obj, key, value) {
if (key in obj) {
Object.defineProperty(obj, key, {
value: value,
enumerable: true,
configurable: true,
writable: true,
})
} else {
obj[key] = value
}
return obj
}

import React from 'react'

const MyComponent =
/*#__PURE__*/
(function () {
class MyComponent extends React.Component {
render() {
return <div>My Component</div>
}
}

_defineProperty(MyComponent, 'displayName', 'FancyName1')

return MyComponent
})()

export default MyComponent
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import React from 'react'

export default function FunctionComponent() {
return <div>My Component</div>
}
FunctionComponent.displayName = 'FancyName1'
FunctionComponent.defaultProps = {}
Loading

0 comments on commit b238a8c

Please sign in to comment.