【问题标题】:How can I export a React Component as an NPM package to use in separate projects?如何将 React 组件导出为 NPM 包以在单独的项目中使用?
【发布时间】:2018-02-20 07:49:11
【问题描述】:

我在一个项目中创建了一个 React 组件,我想在多个项目中使用它。目前,我只关心在本地和开发方面做这件事。 React 组件被渲染到根 div 中,项目使用 webpack 和 babel 将 JSX、ES6 和一些 ES7 特性转换成一个包。

我认为导出这个组件会很简单,这样我就可以简单地运行npm install MyComponent 并开始在新项目中使用它。但是,我发现它并不是那么直截了当。特别是,我已经阅读了几个小时,似乎只是变得更加困惑。

如果我的最终目标是在其包含的项目中继续开发“MyComponent”,同时在任意数量的其他本地项目中使用“MyComponent”,我的选择是什么?我做的第一件事是将我的package.jsonmain 键更改为/src/components/MyComponent 并运行npm pack。这会产生一个tgz 文件,我可以通过它在其他项目中的绝对文件路径进行安装。但是,我发现 es6 和 jsx 没有被转译,所以我的客户端项目将无法解析 MyComponent。然后我使用 webpack 转译为lib/MyComponent,但是当我有import MyComponent from './path/to/MyComponent-1.0.0.tgz 时,我只会在控制台中看到{}(一个空对象)。

为我的问题寻找解决方案会发现许多不同的方法将 NPM、Grunt、Gulp、Babel、Webpack 等结合在一起。而且我担心在我能够解决之前需要更多的时间(几天?)到可以理解的地方。

考虑到我的要求,我可以实现的最简单的解决方案是 1) 将我的 React 组件编译为最简单的导入模块 2) 将其导入任何本地项目 3) 继续在原始宿主项目中开发包并让更改轻松传播到客户项目。

【问题讨论】:

    标签: javascript reactjs npm webpack ecmascript-6


    【解决方案1】:

    一般来说,如果您要开始将 React 组件创建为单独的包(这是一个很好的模式,出于您已经提到的所有原因) - 您将需要至少获得一个对webpackbabel 有点熟悉。这里有很多东西要学,但让我试着为你指明正确的方向:

    // 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,
    }
    

    我知道这看起来像一堆 - 但它可以处理您想要的大部分内容。具体来说:

    1. 如果您在构建时指定 NODE_ENV=production,这将 uglify/minify 您的包,并进行一些您以后可能需要的其他修剪。
    2. 使用此脚本构建将输出 sourcemap,您可以将其与开发工具一起用于在调试器窗口中检查您的缩小代码等。
    3. 这会将reactreact-dom 标记为externals - 这意味着它们不会被捆绑在您的捆绑包中。这很棒 - 因为这意味着您不会因为 imported 自己的组件而获得 react 的文件大小的 2+ 个副本!

    不过,要使用它,您现在需要一些 package.json 的爱。

    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/*"
      }
    }
    

    显然,如果您需要,您可以在这里拥有更多 - 例如您在转译中使用的其他 babel-plugin-* 插件、其他包等。但是这个集合将让您的 webpack 构建运行。请注意,此处的脚本假定您使用的是yarn - 这样您就可以运行yarn build,并且您在posix 系统上,以便mkdir 工作。如果您在 Windows 上或不使用 yarn,只需相应地更新脚本即可。

    剩下的只是学习将你的包发布到npm 或另一个包存储库。首先,这只是将package.json 中的version 数字设置为新的(npm version),然后发布(npm publish)。当然,您必须拥有一个 npm 帐户 - 并登录 (npm login)。

    一旦您发布到npm,您就可以直接yarn add your-package-name

    请记住,虽然 - 我们将 reactreact-dom 标记为 external - 所以在消费包中,您需要确保它们可以作为 window.Reactwindow.ReactDOM 使用 - 或者您需要直接包含来自node_modules/your-package-name/path/to/your/component.js的组件

    【讨论】:

    • 所以我非常感谢深入的回答。我真的只是在寻找在本地跨项目共享包的直接途径。因此,关于开发/生产、发布到 npm 注册表的部分超出了我的期望范围。也许,我应该学会正确地或根本不做这一切.. 我确实发现npm install ../projects/HostProject 会让我将组件导入另一个项目,并且在我运行 webpack 后,对 HostProject 组件的更新将反映在客户端项目中。当然,对文件系统布局的任何更改都会破坏事情
    • 这完全有道理。对于您的本地开发目的 - 这可能很棒。 yarn 现在也有一个 workspace 概念——它可以解决你正在寻找的东西,你也可以看看yarn link(或npm link)——它可以让你使用本地项目作为依赖本地开发,无需对 repo 进行发布/更新过程。
    • 另外 - 正如@Sidney 提到的 (stackoverflow.com/a/46166499/1454806) - 您可以创建一个 GitHub 存储库并直接添加 npmyarnyarn add username:reponame
    • npm 链接非常有用。我看到的唯一缺点是任何“npm install..”似乎都清除了链接
    • 我发现它使用起来也有点麻烦。我认为npm link 的目的是允许您同时处理两个以上单独的包,而不必为每次迭代重新发布每个包。一旦您做了超出此范围的操作(例如实际上提高已安装软件包的版本号),事情似乎会以各种方式出现奇怪的错误。你可能想看看yarn - 它有类似的功能,iirc 也有一些额外的 api 用于跨包工作。
    【解决方案2】:

    你不需要npm pack 一个包来使用它。如果你将你的组件放入一个 git repo 并放在 Github 上,你可以使用 NPM 直接从 Github 安装它,使用 npm install alex/mycomponent 其中alex 是你的 github 用户名,mycomponent 是 repo 名称。重新运行该命令将从 Github 重新安装,以防您对 repo 进行更改。

    一旦您对该组件感到满意,您就可以将其上传到 NPM 注册表以像安装任何其他软件包 (npm install name) 一样进行安装。一开始使用 Github 会更容易开发。

    默认情况下,Webpack 可能不会从 node_modules 编译东西。通常,包在发布之前会被预编译,但是你应该能够配置 webpack 来构建你的“打包”组件,以及你的应用程序的其余部分。也许这会有所帮助:https://stackoverflow.com/a/38008149/7486612

    【讨论】:

      【解决方案3】:

      为了将 react 库推送到 NPM 中,您可能需要一些样板文件来为您安装和转换许多东西(并且您仍然可以使用当前的 react 模块作为主要来源,只需按照我末尾的指南进行操作即可回答,那么你一定会得到所有的想法)

      或者你也可以参考我之前对类似问题的回答: Issue with publishing to npm

      =====

      我还成功地将几个 react 库推送到 NPM 中:

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

      =====

      您的 github 存储库的文件夹结构也应该类似于我的:

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

      =====

      以下有用的教程:

      (样板源)https://github.com/juliancwirko/react-npm-boilerplate

      (作者文章)http://julian.io/creating-react-npm-packages-with-es2015/

      【讨论】:

        【解决方案4】:

        首先查看现有的组件库,例如Material UI。 具体检查他们拥有的 npm 脚本(参见 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",
        

        这是一个非常复杂且高质量的组件库的示例,它确保无论您的构建管道如何,您都可以使用它。

        使用 webpack 设置构建过程可能很麻烦,但从一开始就不要过多地关注这一点,并涵盖最直接的案例。

        还可以在处理组件时查看https://storybook.js.org/

        【讨论】:

          猜你喜欢
          • 2018-09-10
          • 2020-01-04
          • 2012-08-27
          • 1970-01-01
          • 2019-09-09
          • 2018-10-12
          • 2018-02-07
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多