ts-sfc-plugin
v0.0.4
Published
A plugin for optimizing stateless component in React(tsx).
Downloads
3
Readme
ts-sfc-plugin
A plugin for optimizing stateless component of React (tsx)
Why
React functional component(SFC) is easy to use and help to reduce code size significantly, but sometimes people might have been some misunderstanding about its perfomance. Usually, we think functional components would avoid some overheads like mounting / unmounting / lifecycle checking and memory allocations, but in fact, there're no special optimizations currently (but after react 16 was released, sfc is indeed faster than before).
Fortunately SFC just function in react world, if we do care about performance in production there're still a way to improve and this plugin here come to simplify these situation.
const code1 = (
<div>
<Avatar />
</div>
)
const code2 = (
<div>
{ Avatar() }
</div>
)
As we cannot recognize if the component is functional, we have to use an anotation to tag the expression:
<Avatar sfc />
// Plugin use `sfc` as identifier by default, but you can pass an option to override it.
How to use
webpack
module: {
rules: [
{
test: /\.(jsx|tsx|js|ts)$/,
loader: 'ts-loader',
options: {
transpileOnly: true,
getCustomTransformers: () => ({
before: [sfcPlugin()],
}),
compilerOptions: {
module: 'esnext',
},
},
exclude: /node_modules/,
}
],
}
code
import React from 'react'
export const Avatar = ({ name }) => {
return (
<div>
<img src=... />
<span>{ name }</span>
</div>
)
}
import React from 'react'
import { Avatar } from './avatar.component'
export class App extends React.PureComponent {
render() {
return (
<div>
<Avatar name={ 'hello world' } sfc />
</div>
)
}
}
option
sfcPlugin(option?: Option)
interface Option {
pragma?: string
mode?: 1 | 2
}
Deopt
| Reason | Deopt (mode 1) | Deopt (mode 2) |--|--|--| | spread operator | true | false | prop: key | true | false
Considering we transform the code from tsx to native function-call which means the additional vd-layer will be eliminatd, and the effects of key
will be removed as well.
// before
const Message = () => <div>bravo</div>
export class App extends React.PureComponent {
render() {
return <Message key={ 1 } />
}
}
// after
const Message = () => <div>bravo</div>
export class App extends React.PureComponent {
render() {
// won't get benefit from prop: `key`
return Message()
}
}
Notice
Unlike @babel/plugin-transform-react-inline-elements, we won't take ref
into account because of this plugin will be applied to typescript only.
const Message = () => <div>bravo</div>
export class App extends React.PureComponent {
render() {
// ERROR: this is not type-safe
// { ref: any } is not assignable to IntrinsicAttributes
return <Message ref={ ... } />
}
}
Defect
The following code is recommanded:
<Avatar sfc>
// enable rule: `jsx-boolean-value` in tslint.json
using declaration merging in global .d.ts
import React from 'react'
declare module 'react' {
namespace JSX {
interface IntrinsicAttributes extends React.Attributes {
sfc?: boolean
}
}
}
Exception
code like the usage will not work, because the plugin does not include any runtime type checking.
const component = <Avatar sfc={ this.props.flag } />
Benchmark
React 16.4, <Dot />
, 50 times, MacBook Pro (Retina, 13-inch, Early 2013)
| Classical | Functional | Direct-call | Auto-transform | |--|--|--|--| | 660ms | 408ms | 226ms | 229ms |