I have created a React component inside a project that I'd like to use in multiple projects. At the moment, I only care about doing this locally and for development. The React Component is rendered into the root div, the project uses webpack and babel to transpile JSX, ES6 and some ES7 features into a bundle.
I thought it would be simple to export this component such that I can simply run npm install MyComponent
and begin using it in a fresh project. However, I find it isn't so straight forward. In particular, I've been reading for hours and hours and only seem to be getting more confused.
If my end goal is to keep developing 'MyComponent' in its containing project, while using 'MyComponent' in any number of other local projects, what are my options? The first thing I did was change the main
key of my package.json
to /src/components/MyComponent
and run npm pack
. This produces a tgz
file I can install via its absolute filepath in other projects. However, I found that the es6 and jsx was not being transpiled and so my client projects would be unable to parse MyComponent
. I then used webpack to transpile into lib/MyComponent
, but when I have import MyComponent from './path/to/MyComponent-1.0.0.tgz
I'd only see {}
(an empty object) in the console.
Searching for solutions to my problem turn up many different approaches pulling together NPM, Grunt, Gulp, Babel, Webpack, etc.. And I am worried it will be many many more hours (days?) before I can grind that down to something understandable.
Given my requirements, what is the simplest solution I can implement to 1) compile down my React Component to the simplest to import module 2) import it into any local projects 3) continue to develop the package in the original host project and have changes easily propagate to client projects.
To import a component from another file in React:Export the component from file A , e.g. export function Button() {} . Import the component in file B as import {Button} from './another-file' . Use the imported component in file B .
Use named exports to export a component in React, e.g. export function Button() {} . The exported component can be imported by using a named import as import {Button} from './another-file. js' . You can use as many named exports as necessary in a file.
In general, if you're going to begin creating React
components as separated packages (which is a great pattern, for all the reasons you've already mentioned) - you're going to need to get at least a bit familiar with webpack
and babel
. There's a ton to learn here, but let me try to point you in the right direction:
// webpack.config.js
/* eslint-disable */
const path = require('path')
const webpack = require('webpack')
const ENVIRONMENT = process.env.NODE_ENV
const PRODUCTION = ENVIRONMENT === 'production'
const SOURCEMAP = !PRODUCTION || process.env.SOURCEMAP
const library = 'your-lib-name' // << RENAME THIS <<
const filename = PRODUCTION ? `${library}.min.js` : `${library}.js`
const plugins = []
if (PRODUCTION) {
plugins.push(
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(ENVIRONMENT),
}),
new webpack.optimize.ModuleConcatenationPlugin(),
new webpack.optimize.UglifyJsPlugin({
minimize: true,
output: { comments: false, semicolons: false },
sourceMap: SOURCEMAP,
})
)
}
module.exports = {
devtool: SOURCEMAP ? 'source-map' : 'none',
entry: `${__dirname}/path/to/your/component.js`, // << RENAME THIS <<
externals: {
'react': 'react',
'react-dom': 'react-dom',
},
module: {
loaders: [{
test: /\.js$/,
loader: 'babel-loader',
exclude: /node_modules/,
}],
},
output: {
filename,
library,
path: `${__dirname}/lib`,
libraryTarget: 'umd',
umdNamedDefine: true,
},
plugins,
}
I know that looks like a bunch - but it handles the majority of what you're going to want. In specific:
NODE_ENV=production
when building, this will uglify/minify your package, and do some other trimming which you may want later.sourcemap
, which you can use with dev tools to inspect your minified code in the debugger window, among other things.react
and react-dom
as externals
- which means they won't get bundled up and packaged inside your bundle. This is great - because it means you won't get 2+ copies of react
's filesize just because you've import
ed your own component!To use it, though, you now need some package.json
love.
package.json
{
"name": "Your Name",
"version": "0.0.1",
"description": "This is my awesome react package!",
"main": "path/to/your/component.js",
"author": "Your Name",
"license": "MIT",
"repository": { /* Your Repo Info Here */ },
"dependencies": {
"any-packages-you-need-included-in-builds": "^1.0.0"
},
"devDependencies": {
"babel-cli": "^6.22.2",
"babel-loader": "^7.1.0",
"babel-preset-es2015": "^6.22.0",
"babel-preset-react": "^6.22.0",
"prop-types": "^15.5.10",
"react-dom": "^15.6.1",
"webpack": "^3.0.0"
},
"scripts": {
"build": "yarn prebuild && NODE_ENV=production webpack",
"prebuild": "mkdir -p ./lib && rm -rf ./lib/*"
}
}
Obviously, you can have a lot more here if you need it - such as other babel-plugin-*
plugins that you use in your transpilation, other packages, etc.But this set will let your webpack
build run. Note that the scripts here assume you're using yarn
- so that you can run yarn build
, and that you're on a posix system, for mkdir
to work. If you're on windows or not using yarn
, just update the scripts accordingly.
The rest is just learning to publish your package to npm
or another package repository. Primarily, that's just setting the version
number in package.json
to something new (npm version
) and then publishing (npm publish
). You will have to have an npm
account for this, of course - and be logged in (npm login
).
Once you've published to npm
you can just yarn add your-package-name
.
Remember, though - we marked react
and react-dom
as external
- so in the consuming package, you'll need to make sure they're available as window.React
and window.ReactDOM
- or you'll need to include the component directly from node_modules/your-package-name/path/to/your/component.js
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With