How to package your React Component for distribution via NPM (2024)

I wrote a React component, transpiling using Babel, bundling and building using Webpack. I wanted to use it in another application via NPM. My NPM publish package needed to include component behavior, styles and images. So how difficult is it to package my React Component for distribution via NPM? An hour or so of work maybe right?

Well, it took me a lot longer to figure this out because of the following speed-bumps.
– React version conflict
– How to bundle and consume styles from a component
– How to include and bundle images

Here are the steps.

npm init

In the package.json, make sure these fields are populated:

package.json{
"name": "myUnflappableComponent",
"version": "0.0.29",
"main": "dist/index.js",
"publishConfig": {
"access": "restricted"
},
...
}

In package.json, add React and react-dom in the project’s peerDependencies (And remove it from dependencies, but add it to devDependencies for development)

..."peerDependencies": { 
"react": ">=15.0.1",
"react-dom": ">=15.0.1"
},
"devDependencies": {
"react": ">=15.0.1",
"react-dom": ">=15.0.1"
},
...

In your webpack configuration, create a UMD bundle

...
module.exports = {
...
output: {
path: path.join(__dirname, './dist'),
filename: 'myUnflappableComponent.js',
library: libraryName,
libraryTarget: 'umd',
publicPath: '/dist/',
umdNamedDefine: true
},
plugins: {...},
module: {...},
resolve: {...},
externals: {...}
}

And super-duper important, don’t bundle React

module.exports = { 
output: {...},
plugins: {...},
module: {...},
resolve: {
alias: {
'react': path.resolve(__dirname, './node_modules/react'),
'react-dom': path.resolve(__dirname, './node_modules/react-dom'),
}
},
externals: {
// Don't bundle react or react-dom
react: {
commonjs: "react",
commonjs2: "react",
amd: "React",
root: "React"
},
"react-dom": {
commonjs: "react-dom",
commonjs2: "react-dom",
amd: "ReactDOM",
root: "ReactDOM"
}
}
}

If you don’t set up a .npmignore file, npm uses your .gitignore file and bad things will happen. An empty .npmignore file is allowed. This is what mine looks like:

webpack.local.config.js
webpack.production.config.js
.eslintrc
.gitignore

To build before publishing.

"scripts": {
"prepublish": "rm -rf ./dist && npm run build",
...
}

We use SCSS files for our styles. These are compiled into css and extracted out by Webpack.

Install the following:

npm install --save-dev extract-text-webpack-plugin node-sass style-loader css-loader sass-loader

Update your webpack.config

const ExtractTextPlugin = require('extract-text-webpack-plugin');module.exports = {
...
plugins:[
new ExtractTextPlugin({
filename: 'myUnflappableComponent.css',
}),
],
module:{
rules:[
{
test: /\.*css$/,
use : ExtractTextPlugin.extract({
fallback : 'style-loader',
use : [
'css-loader',
'sass-loader'
]
})
},
....
]
}
}

The way you include images in your component will determine if the consumer of your component will get them.

I include them in the css file using the content property. For example

.mySky{
width: 20px;
height: 20px;
content: url('../assets/images/thunderSky.png');
}

The issue I ran into was the relative paths of the images in the published CSS files were messed up. After a lot of searching, this article (also in the links below) helped.

Install the following:

npm install --save-dev file-loader url-loader

Update your webpack.config like this:

module.exports = {
...
module: {
rules: [
{
test: /\.(png|svg|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options:{
fallback: "file-loader",
name: "[name][md5:hash].[ext]",
outputPath: 'assets/',
publicPath: '/assets/'
}
}
]
},
...
resolve: {
alias:{
...
'assets': path.resolve(__dirname, 'assets')
}
}
]
}
}
  1. How to publish your package on npm(all about package.json)
  2. Publish Beta to NPM
  3. Exporting images via webpack (webpack.config.js)
  4. My full webpack configuration:
const webpack = require('webpack');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
const pkg = require('./package.json');
const path = require('path');
const libraryName= pkg.name;module.exports = {
entry: path.join(__dirname, "./src/index.js"),
output: {
path: path.join(__dirname, './dist'),
filename: 'myUnflappableComponent.js',
library: libraryName,
libraryTarget: 'umd',
publicPath: '/dist/',
umdNamedDefine: true
},
plugins: [
new ExtractTextPlugin({
filename: 'myUnflappableComponent.css',
}),
],
node: {
net: 'empty',
tls: 'empty',
dns: 'empty'
},
module: {
rules : [
{
test: /\.(png|svg|jpg|gif)$/,
use: [
{
loader: 'url-loader',
options:{
fallback: "file-loader",
name: "[name][md5:hash].[ext]",
outputPath: 'assets/',
publicPath: '/assets/'
}
}
]
},
{
test: /\.*css$/,
use : ExtractTextPlugin.extract({
fallback : 'style-loader',
use : [
'css-loader',
'sass-loader'
]
})
},
{
test: /\.(js|jsx)$/,
use: ["babel-loader"],
include: path.resolve(__dirname, "src"),
exclude: /node_modules/,
},
{
test: /\.(eot|ttf|woff|woff2)$/,
use: ["file-loader"],
},
{
test: /\.(pdf|doc|zip)$/,
use: ["file-loader"],
}]
},
resolve: {
alias: {
'react': path.resolve(__dirname, './node_modules/react') ,
'react-dom': path.resolve(__dirname, './node_modules/react-dom'),
'assets': path.resolve(__dirname, 'assets')
}
},
externals: {
// Don't bundle react or react-dom
react: {
commonjs: "react",
commonjs2: "react",
amd: "React",
root: "React"
},
"react-dom": {
commonjs: "react-dom",
commonjs2: "react-dom",
amd: "ReactDOM",
root: "ReactDOM"
}
}
};
How to package your React Component for distribution via NPM (2024)
Top Articles
What is a Sneaker Bot | Is it Legal & Work Mechanism Explained | Imperva
Macy's Credit Card Reviews
Exclusive: Baby Alien Fan Bus Leaked - Get the Inside Scoop! - Nick Lachey
Mcoc Immunity Chart July 2022
Autobell Car Wash Hickory Reviews
Bloxburg Image Ids
Mail Healthcare Uiowa
Osrs But Damage
ds. J.C. van Trigt - Lukas 23:42-43 - Preekaantekeningen
Pwc Transparency Report
Crusader Kings 3 Workshop
Edible Arrangements Keller
Https //Advanceautoparts.4Myrebate.com
Wordle auf Deutsch - Wordle mit Deutschen Wörtern Spielen
Jackson Stevens Global
7 Fly Traps For Effective Pest Control
Simplify: r^4+r^3-7r^2-r+6=0 Tiger Algebra Solver
Kürtçe Doğum Günü Sözleri
Po Box 35691 Canton Oh
Farmer's Almanac 2 Month Free Forecast
Breckie Hill Mega Link
Pokemon Unbound Shiny Stone Location
How Long After Dayquil Can I Take Benadryl
Caring Hearts For Canines Aberdeen Nc
Defending The Broken Isles
Spiritual Meaning Of Snake Tattoo: Healing And Rebirth!
Divina Rapsing
Soul Eater Resonance Wavelength Tier List
Garden Grove Classlink
NV Energy issues outage watch for South Carson City, Genoa and Glenbrook
How To Improve Your Pilates C-Curve
Nurofen 400mg Tabletten (24 stuks) | De Online Drogist
Otis Offender Michigan
Que Si Que Si Que No Que No Lyrics
Http://N14.Ultipro.com
Rvtrader Com Florida
Marine Forecast Sandy Hook To Manasquan Inlet
Selfservice Bright Lending
Unity Webgl Player Drift Hunters
Hannibal Mo Craigslist Pets
How To Get Soul Reaper Knife In Critical Legends
Dying Light Nexus
Zasilacz Dell G3 15 3579
Aita For Announcing My Pregnancy At My Sil Wedding
Citibank Branch Locations In North Carolina
What to Do at The 2024 Charlotte International Arts Festival | Queen City Nerve
Bekkenpijn: oorzaken en symptomen van pijn in het bekken
Hawkview Retreat Pa Cost
Rescare Training Online
Sam's Club Gas Price Sioux City
Puss In Boots: The Last Wish Showtimes Near Valdosta Cinemas
Mkvcinemas Movies Free Download
Latest Posts
Article information

Author: Delena Feil

Last Updated:

Views: 6408

Rating: 4.4 / 5 (65 voted)

Reviews: 80% of readers found this page helpful

Author information

Name: Delena Feil

Birthday: 1998-08-29

Address: 747 Lubowitz Run, Sidmouth, HI 90646-5543

Phone: +99513241752844

Job: Design Supervisor

Hobby: Digital arts, Lacemaking, Air sports, Running, Scouting, Shooting, Puzzles

Introduction: My name is Delena Feil, I am a clean, splendid, calm, fancy, jolly, bright, faithful person who loves writing and wants to share my knowledge and understanding with you.