首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >共享组件库最佳实践

共享组件库最佳实践
EN

Stack Overflow用户
提问于 2020-01-24 16:40:06
回答 5查看 11.1K关注 0票数 22

我正在创建一个可共享的React组件库。

库包含许多组件,但最终用户可能只需要使用其中的几个组件。

当您将代码与Webpack (或Parcel或Rollup)捆绑在一起时,它会创建一个包含所有代码的文件。

出于性能原因,除非实际使用,否则我不希望浏览器下载所有的代码。我认为不应该捆绑组件的想法是正确的吗?捆绑应该留给组件的消费者吗?我是否给组件的使用者留下了其他的东西?我是不是只是把它转过来了就这样了?

如果同一个回购包含许多不同的组件,那么main.js中应该包含什么?

EN

回答 5

Stack Overflow用户

发布于 2020-02-01 23:05:47

这是一个非常长的答案,因为这个问题应该得到一个非常长和详细的答案,因为“最佳实践”方法比简单的几行回答要复杂得多。

在这段时间里,我一直在维护我们的内部库,我已经确定了两种方法,我认为图书馆应该捆绑在一起。权衡取决于您的库有多大,就我个人而言,我们编写这两种方法都是为了取悦消费者的两个子集。

方法1:创建一个包含您想要公开的所有内容的index.ts文件,并将该文件的目标汇总作为它的输入。将整个库绑定到单个index.js文件和index.css文件中;使用从使用者项目继承的外部依赖项,以避免库代码的重复。(示例配置底部包含的gist)

  • 优点:易于使用,因为项目使用者可以从根相对库路径import { Foo, Bar } from "library"导入所有内容
  • 缺点:这永远不会是树的摇摆不定,在人们说要用ESM做这件事之前,它将是树的摇动。NextJS在现阶段不支持ESM,也不支持很多项目设置,这就是为什么将这个构建编译成CJS仍然是个好主意。如果有人导入了你的一个组件,他们会得到你所有组件的所有CSS和所有javascript。

方法2:这是为高级用户创建的:为每个导出创建一个新文件,并使用rollup plugin-多输入选项"preserveModules: true“,这取决于您使用的CSS系统还需要确保您的CSS不合并到单个文件中,但是每个CSS文件需要(”.css“)语句在汇总后留在输出文件中,并且该CSS文件是存在的。

  • 优点:当用户从"library/dist/ Foo“导入{ Foo }时,他们只会获得Foo的代码,而只获取Foo的CSS,仅此而已。
  • 缺点:此设置涉及到使用者在使用node_modules进行构建配置时必须处理NextJS要求(“.css”)语句--这是用next-transpile-modules npm包完成的。
  • 注意:我们使用我们自己的babel插件,您可以在这里找到它:https://www.npmjs.com/package/babel-plugin-qubic允许人们使用import { Foo, Bar } from "library",然后使用babel将其转换为.
代码语言:javascript
复制
import { Foo } from "library/dist/export/foo"
import { Bar } from "library/dist/export/bar"

在实际使用这两种方法的情况下,我们有多个汇总配置;因此对于不关心树抖动的库使用者,只需执行"Foo from "library"并导入单个CSS文件,而对于关心树抖动且只使用关键CSS的库使用者,他们只需打开我们的babel插件即可。

汇总最佳实践指南:

无论您是否使用类型记录,都要确保您的"rollup-plugin-babel": "5.0.0-alpha.1"看起来像这样。

代码语言:javascript
复制
{
  "presets": [
    ["@babel/preset-env", {
      "targets": {"chrome": "58", "ie": "11"},
      "useBuiltIns": false
    }],
    "@babel/preset-react",
    "@babel/preset-typescript"
  ],
  "plugins": [
    ["@babel/plugin-transform-runtime", {
      "absoluteRuntime": false,
      "corejs": false,
      "helpers": true,
      "regenerator": true,
      "useESModules": false,
      "version": "^7.8.3"
    }],
    "@babel/plugin-proposal-class-properties",
    "@babel/plugin-transform-classes",
    ["@babel/plugin-proposal-optional-chaining", {
      "loose": true
    }]
  ]
}

加上babel插件看起来像这样..。

代码语言:javascript
复制
        babel({
            babelHelpers: "runtime",
            extensions,
            include: ["src/**/*"],
            exclude: "node_modules/**",
            babelrc: true
        }),

你的package.json看起来至少是这样的:

代码语言:javascript
复制
    "dependencies": {
        "@babel/runtime": "^7.8.3",
        "react": "^16.10.2",
        "react-dom": "^16.10.2",
        "regenerator-runtime": "^0.13.3"
    },
    "peerDependencies": {
        "react": "^16.12.0",
        "react-dom": "^16.12.0",
    }

最后,你的外挂看起来至少像这样。

代码语言:javascript
复制
const makeExternalPredicate = externalArr => {
    if (externalArr.length === 0) return () => false;
    return id => new RegExp(`^(${externalArr.join('|')})($|/)`).test(id);
};

//... rest of rollup config above external.
    external: makeExternalPredicate(Object.keys(pkg.peerDependencies || {}).concat(Object.keys(pkg.dependencies || {}))),
// rest of rollup config below external.

为什么?

  • 这将将您的垃圾绑定到自动地从使用者项目继承、响应/反应-dom和其他对等/外部依赖项,这意味着它们不会在您的包中复制。
  • 这将绑定到ES5
  • 这将自动要求(“.”)在用于objectSpread的所有babel函数中,来自使用者项目的类等将从您的包大小中再删除15-25KB,这意味着objectSpread的辅助函数不会在库输出+捆绑的消费项目中重复。
  • 异步函数仍然可以工作。
  • 外部将匹配任何以同级依赖后缀开头的内容,即babel-helpers将匹配babel-helpers/helpers/对象传播的外部。

最后,这里是一个示例index.js文件输出rollup配置文件的要点。在https://gist.github.com/ShanonJackson/deb65ebf5b2094b3eac6141b9c25a0e3中,目标src/export/index.ts看起来如下.

代码语言:javascript
复制
export { Button } from "../components/Button/Button";
export * from "../components/Button/Button.styles";

export { Checkbox } from "../components/Checkbox/Checkbox";
export * from "../components/Checkbox/Checkbox.styles";

export { DatePicker } from "../components/DateTimePicker/DatePicker/DatePicker";
export { TimePicker } from "../components/DateTimePicker/TimePicker/TimePicker";
export { DayPicker } from "../components/DayPicker/DayPicker";
// etc etc etc

如果您遇到任何关于打包/库的问题,请告诉我。

票数 32
EN

Stack Overflow用户

发布于 2020-01-26 21:47:07

当您将代码与Webpack (或Parcel或Rollup)捆绑在一起时,它会创建一个包含所有代码的文件。 出于性能原因,除非实际使用,否则我不希望浏览器下载所有的代码。

可以为每个组件生成单独的文件。Webpack有这样的能力,通过定义多个条目和输出。假设您有下面的项目结构

代码语言:javascript
复制
- my-cool-react-components
  - src // Folder contains all source code
    - index.js
    - componentA.js
    - componentB.js
    - ...
  - lib // Folder is generated when build
    - index.js // Contains components all together
    - componentA.js
    - componentB.js
    - ...

Webpack的文件会像这样

代码语言:javascript
复制
const path = require('path');

module.exports = {
  entry: {
    index: './src/index.js',
    componentA: './src/componentA.js',
    componentB: './src/componentB.js',
  },
  output: {
    filename: '[name].js',
    path: path.resolve(__dirname, 'lib'),
  },
};

有关“代码拆分”的更多信息在Webpack博士

如果同一个回购包含许多不同的组件,那么main.js中应该包含什么?

package.json文件中只有一个名为main的字段,根据上面的项目结构将其值lib/index.js放入其中是很好的。并在index.js文件中导出所有组件。如果使用者想要使用单个组件,只需执行以下操作即可达到

代码语言:javascript
复制
const componentX = require('my-cool-react-components/lib/componentX');

我认为不应该捆绑组件的想法是正确的吗?捆绑应该留给组件的消费者吗?我是否给组件的使用者留下了其他的东西?我是不是只是把它转过来了就这样了?

那就看你的了。我发现有些React库是以原始的方式发布的,另一些是以捆绑的方式发布的。如果您需要一些构建过程,那么定义它并导出捆绑版本。

希望,你的所有问题都得到了回答:)

票数 6
EN

Stack Overflow用户

发布于 2020-01-26 21:39:43

您可以像房客为其方法所做的那样拆分您的组件。

您可能拥有的是可以允许单独导入或通过主组件导入的单独组件。

然后消费者就可以导入整个包。

代码语言:javascript
复制
import {MyComponent} from 'my-components';

或其个别部分

代码语言:javascript
复制
import MyComponent from 'my-components/my-component';

消费者将根据导入的组件创建自己的捆绑包。这应该可以防止下载整个包。

票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/59900538

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档