babel-plugin-transform-react-remove-prop-types is a Babel plugin that removes unnecessary React propTypes from production builds to reduce bundle size and improve performance. It supports multiple removal strategies, works with all React component patterns, and provides extensive configuration options for fine-tuned control.
npm install --save-dev babel-plugin-transform-react-remove-prop-typesAs a Babel plugin, this package is typically configured in Babel configuration files rather than imported directly:
// .babelrc
{
"plugins": ["transform-react-remove-prop-types"]
}For programmatic usage:
const babelTransform = require('@babel/core');
const plugin = require('babel-plugin-transform-react-remove-prop-types');
babelTransform.transform(code, {
plugins: [plugin]
});Remove all propTypes in production:
{
"env": {
"production": {
"plugins": ["transform-react-remove-prop-types"]
}
}
}Configure the plugin behavior:
{
"env": {
"production": {
"plugins": [
["transform-react-remove-prop-types", {
"mode": "wrap",
"removeImport": true,
"ignoreFilenames": ["node_modules"],
"additionalLibraries": ["react-immutable-proptypes"]
}]
]
}
}
}const { transform } = require('@babel/core');
const result = transform(sourceCode, {
plugins: [
['babel-plugin-transform-react-remove-prop-types', {
mode: 'remove',
removeImport: true
}]
]
});The main plugin export is a Babel plugin factory function (default export).
/**
* Babel plugin factory function for removing React propTypes
* @param api - Babel API object containing template, types, and traverse utilities
* @returns Babel plugin object with visitor methods
*/
export default function(api: BabelAPI): BabelPlugin;
interface BabelAPI {
template: Function;
types: Object;
traverse: Function;
}
interface BabelPlugin {
visitor: {
Program: (path: NodePath, state: PluginState) => void;
};
}The plugin accepts an options object with the following configuration properties:
interface PluginOptions {
/**
* Removal strategy - how to handle propTypes
* @default "remove"
*/
mode?: "remove" | "wrap" | "unsafe-wrap";
/**
* Whether to remove unused propTypes import statements
* Only works when mode is "remove"
* @default false
*/
removeImport?: boolean;
/**
* Array of filename patterns to ignore during transformation
* Creates a regex pattern to match against filenames
* @default undefined
*/
ignoreFilenames?: string[];
/**
* Additional libraries to treat as propTypes sources beyond 'prop-types'
* Can include regular expressions for flexible matching
* @default []
*/
additionalLibraries?: (string | RegExp)[];
/**
* Custom class names to match as React components
* Beyond React.Component and React.PureComponent
* @default undefined
*/
classNameMatchers?: string[];
/**
* Custom name for create-react-class import
* @default "createReactClass"
*/
createReactClassName?: string;
/**
* Additional Babel plugins to run during transformation
* Used internally for extending plugin functionality
* @default undefined
*/
plugins?: (string | [string, object])[];
}Completely removes propTypes definitions from the code:
// Input
Component.propTypes = {
name: PropTypes.string
};
// Output
// (propTypes completely removed)Wraps propTypes with NODE_ENV check, maintaining property access:
// Input
Component.propTypes = {
name: PropTypes.string
};
// Output
Component.propTypes = process.env.NODE_ENV !== "production" ? {
name: PropTypes.string
} : {};Wraps propTypes with conditional block, breaking property access in production:
// Input
Component.propTypes = {
name: PropTypes.string
};
// Output
if (process.env.NODE_ENV !== "production") {
Component.propTypes = {
name: PropTypes.string
};
}The plugin handles all common React component patterns:
class MyComponent extends React.Component {
static propTypes = {
name: PropTypes.string
};
}
// Also handles inheritance chains
class BaseComponent extends React.Component {}
class MyComponent extends BaseComponent {
static propTypes = {
name: PropTypes.string
};
}const MyComponent = () => <div />;
MyComponent.propTypes = {
name: PropTypes.string
};const MyComponent = React.createClass({
propTypes: {
name: PropTypes.string
},
render() {
return <div />;
}
});function MyComponent(props) {
return <div>{props.name}</div>;
}
MyComponent.propTypes = {
name: PropTypes.string
};Force removal using comment annotation for edge cases like HOCs:
Component.propTypes /* remove-proptypes */ = {
name: PropTypes.string
};When removeImport: true and mode: "remove", unused propTypes imports are removed:
// Input
import PropTypes from 'prop-types';
import ImmutablePropTypes from 'react-immutable-proptypes';
const Component = () => <div />;
// (no propTypes usage)
// Output
// (imports removed if not used elsewhere)Support additional propTypes libraries with additionalLibraries:
// Configuration
{
"additionalLibraries": [
"react-immutable-proptypes",
/\/prop-types\/.*/ // Regex pattern
]
}Ignore specific files or directories with ignoreFilenames:
// Configuration
{
"ignoreFilenames": ["node_modules", "vendor"]
}Handle custom React base classes with classNameMatchers:
// Configuration
{
"classNameMatchers": ["BaseComponent", "MyReactClass"]
}
// Will now handle
class MyComponent extends BaseComponent {
static propTypes = { /* ... */ };
}The plugin throws errors for:
removeImport: true with mode: "wrap")Common error messages:
// Invalid mode
"transform-react-remove-prop-type: unsupported mode invalid-mode."
// Invalid option combination
"transform-react-remove-prop-type: removeImport = true and mode != \"remove\" can not be used at the same time."
// Infinite loop protection (from stateless component analysis)
"transform-react-remove-prop-type: infinite loop detected."interface PluginState {
opts: PluginOptions;
hub: {
file: {
opts?: {
filename?: string;
};
};
};
}
interface NodePath {
node: Node;
scope: Scope;
parent: Node;
parentPath: NodePath;
findParent: (callback: (path: NodePath) => boolean) => NodePath | null;
traverse: (visitor: object) => void;
remove: () => void;
replaceWith: (node: Node) => void;
get: (key: string) => NodePath;
matchesPattern: (pattern: string) => boolean;
}
interface Scope {
getBinding: (name: string) => Binding | undefined;
block: Node;
hub: {
file: {
opts?: {
filename?: string;
};
};
};
}
interface Binding {
path: NodePath;
referencePaths: NodePath[];
}