trailblazer
trailblazer

Reputation: 1451

Publish a react component to npm and reuse it

I am trying to publish a basic React component to my npm registry and trying to reuse it. I think I am not following proper way to distribute my react component. Here's what I have:

This is the directory structure:

MyReactPOC
    -> main.jsx
    -> .npmrc
    -> package.json
    -> webpack.config.js

main.jsx

import React from 'react';

class MyComponent extends React.Component {
    render() {
        return (
            <div>
                <p>Hello from MyComponent!!</p>
            </div>
        );
    }
}

export default MyComponent

package.json

{
  "name": "@pankaj/my-component",
  "version": "1.0.7",
  "description": "POC for importing a component",
  "main": "./dist/bundle.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "prepublish": "webpack --config webpack.config.js"
  },
  "repository": {
    "type": "git",
    "url": "my git repo"
  },
  "author": "Pankaj",
  "license": "ISC",
  "dependencies": {
    "react": "~15.5.4",
    "react-dom": "~15.5.4"
  },
  "devDependencies": {
    "babel-cli": "~6.24.1",
    "babel-core": "~6.24.1",
    "babel-loader": "~6.4.1",
    "babel-preset-es2015": "~6.24.1",
    "babel-preset-react": "~6.24.1",
    "webpack": "~2.4.1"
  }
}

webpack.config.js

var path = require('path');
var webpack = require('webpack');

module.exports = {
    entry: './main.jsx',
    output: { path: path.join(__dirname, 'dist'), filename: 'bundle.js' },
    module: {
        loaders: [
            {
                test: /.jsx?$/,
                loader: 'babel-loader',
                exclude: /node_modules/,
                query: {
                    presets: ['es2015', 'react']
                }
            }
        ]
    },
};

I import the module in another project using import MyComponent from '@pankaj/my-component'.

When I use this component like

I get the following error:

React.createElement: type is invalid -- expected a string (for built-in components) or a class/function (for composite components) but got: object. You likely forgot to export your component from the file it's defined in.

Please help me understand the right way to distribute the react components so that they can be used by other projects within my org.

Here is how I use this component:

ComponentUse.js

import React from 'react';
import ReactDOM from 'react-dom';
import MyComponent from '@pankaj/my-component';

ReactDOM.render(
  <MyComponent/>,
  document.getElementById('root')
);

I have an index.html that has the 'root' div.

Upvotes: 5

Views: 3833

Answers (4)

Mohammad Mahdi Kabir
Mohammad Mahdi Kabir

Reputation: 790

After several days of searching, I believe microbundle effortlessly achieves this. Below is my build command:

"scripts": {
    "build": "microbundle build --globals react=React,react-dom=ReactDOM --jsx cloneElement,createContext,isValidElement,useContext,useReducer --jsxFragment Fragment --jsxImportSource react",
    "dev": "microbundle watch"
  },

Upvotes: 0

Broda Noel
Broda Noel

Reputation: 1980

I wrote a full Medium story because I had the same issue as you and there is no information about it. Check it out: https://medium.com/@BrodaNoel/how-to-create-a-react-component-and-publish-it-in-npm-668ad7d363ce

The main fix is to add libraryTarget: 'umd' in the webpack.config.js file

Upvotes: 1

Pasquale Mangialavori
Pasquale Mangialavori

Reputation: 81

If you export with es6 syntax with babel, your component will be in MyComponent.default namespace. To avoid this you should install:

npm i --save-dev babel-plugin-add-module-exports in your .babelrc?

and add it to the babel conf:

{
  "presets": [ "es2015", "react"],
  "plugins": ["add-module-exports"]
}

Upvotes: 0

sidag95
sidag95

Reputation: 101

Every react component needs a return statement. Add a return statement in your render function and it should work.

...
render() {
     return (<div>...</div>)
}

You cannot directly render to the Dom from your react component, instead return it so that react can work with it.

In webpack, specify your output file as a library using output.library https://webpack.js.org/concepts/output/#output-library

Upvotes: 3

Related Questions