最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - How can I export a React Component as an NPM package to use in separate projects? - Stack Overflow

programmeradmin3浏览0评论

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.

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.

Share Improve this question edited Sep 12, 2017 at 2:33 Alex Bollbach asked Sep 12, 2017 at 1:07 Alex BollbachAlex Bollbach 4,5709 gold badges38 silver badges86 bronze badges
Add a comment  | 

4 Answers 4

Reset to default 10

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:

  1. If you specify NODE_ENV=production when building, this will uglify/minify your package, and do some other trimming which you may want later.
  2. Building with this script will output a sourcemap, which you can use with dev tools to inspect your minified code in the debugger window, among other things.
  3. This marks 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 imported 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

You don't need to npm pack a package to use it. If you make your component into a git repo and put it on Github, you can use NPM to install it directly from Github by using npm install alex/mycomponent where alex is your github username and mycomponent is the repo name. Re-running that command will re-install from Github, in case you make changes to the repo.

Once you're happy with the component, you can upload it to the NPM registry to install like any other package (npm install name). Using Github at first makes it a bit easier to develop.

Webpack might not compile things from node_modules by default. Usually, packages are pre-compiled before being published anyway, but you should be able to configure webpack to build your 'packaged' component, along with the rest of your app. Maybe this will help: https://stackoverflow.com/a/38008149/7486612

In order to push react libraries into NPM, you may need some boilerplate which will install and convert many things for you (and you can still use your current react module as the main source, just follow the guides at the end of my answer, then you will surely get all the ideas)

Or you can also refer to my previous answer to a similar question: Issue with publishing to npm

=====

I've also pushed several react libraries successfully into NPM:

https://www.npmjs.com/~thinhvo0108

=====

Your github repositories' folder structure should also look like mine:

https://github.com/thinhvo0108/react-paypal-express-checkout

=====

Useful tutorial below here:

(boilerplate source) https://github.com/juliancwirko/react-npm-boilerplate

(author's article) http://julian.io/creating-react-npm-packages-with-es2015/

Start by looking at existing component library, eg Material UI. Specifically check out npm scripts they have (see package.json):

"build:es2015": "cross-env NODE_ENV=production babel ./src --ignore *.spec.js --out-dir ./build",
"build:es2015modules": "cross-env NODE_ENV=production BABEL_ENV=modules babel ./src/index.js --out-file ./build/index.es.js",
"build:copy-files": "babel-node ./scripts/copy-files.js",
"build:umd:dev": "webpack --config scripts/umd.webpack.config.js",
"build:umd:prod": "cross-env NODE_ENV=production webpack --config scripts/umd.webpack.config.js",
"build": "npm run build:es2015 && npm run build:es2015modules && npm run build:copy-files && npm run build:umd:dev && npm run build:umd:prod",

That's example of very involved and high quality component library, that makes sure that regardless of your build pipeline you'll be able to use it.

Setting up build process with webpack might be cumbersome, but don't concentrate on that too much from the begining, and cover cases that are most straight forward to you.

Also check out https://storybook.js.org/ while working on your components.

发布评论

评论列表(0)

  1. 暂无评论