【问题标题】:Cherry-pick modules with Rollup and ES Modules?带有 Rollup 和 ES 模块的 Cherry-pick 模块?
【发布时间】:2020-02-14 19:15:04
【问题描述】:

使用 lodash-es,我们可以像这样挑选模块:import drop from 'lodash/drop'; 这样只有 drop 被使用,没有别的。

如何使用 Rollup 实现相同的目标?

我正在配置一个 react 和 typescript ui 库以用于两个 create-react-app 项目。我了解到使用 esm 最适合我的用例,它是使用 Rollup 实现 treeshaking 的最有效方式。但是,当我使用我的库时,我是这样导入的:import { someComponent }from 'my-ui-library'; 是不是像上面的cherry-pick 方法一样挑出someComponent。语法重要吗?

这是我的rollup.config.js

import babel from 'rollup-plugin-babel';
import resolve from '@rollup/plugin-node-resolve';
import typescript from 'rollup-plugin-typescript2';
import svgr from '@svgr/rollup';
import url from '@rollup/plugin-url';
import json from '@rollup/plugin-json';
import external from 'rollup-plugin-peer-deps-external';
import includePaths from 'rollup-plugin-includepaths';

const pkg = require('./package.json');

export default {
  cache: false,
  input: 'src/index.ts',
  output: [{ file: pkg.module, format: 'esm' }],
  treeshake: true,
  plugins: [
    external({
      preferBuiltins: false,
    }),
    babel({
      exclude: /node_modules/,
      plugins: ['external-helpers'],
      externalHelpers: true, // Exclude babel helpers.
    }),
    json(),
    resolve(),
    svgr({
      ref: true,
      svgo: false,
    }),
    typescript({
      clean: true,
      typescript: require('typescript'),
    }),
    url(),
    includePaths({
      paths: ['src'],
    }),
  ],
};

【问题讨论】:

    标签: reactjs typescript configuration rollup rollupjs


    【解决方案1】:

    在摇树 ESM 包时似乎有一些问题。第一个问题是 tree shaking 仅在生产中有效,第二个问题是您的 package.json 必须包含 sideEffects: false 属性。不幸的是,在开发中,tree shaking 仍然导入整个库以检索命名导出。点击here更多关于webpack tree-shaking的信息。

    例如(开发中):import screenshot exmaple

    在上面的示例中,我导入了一个名为 defaultLayoutCommands 的命名导出;但是,它仍然显示所有库都已导入,即使 webpack 正在使用 esm 文件。但是,如果我将文件分开并直接导入,那么它会显示较小的导入大小。在生产中,这个应该 tree-shake 导入defaultLayoutCommands 并且就像第二个导入示例一样。也就是说,tree-shaking 仅适用于 webpack AND ESM。

    使用 CJS/UMD/AMD 时,摇树将不起作用。相反,您必须将所有导出组合到单个类/对象(如exports 对象)。然后使用 ES6 解构,您可以实现该方法。

    例如,lodash 将所有功能都放在一个文件中,例如:

        function throttle(func, wait, options) {
          var leading = true,
          trailing = true;
    
          if (typeof func != 'function') {
            throw new TypeError(FUNC_ERROR_TEXT);
          }
          if (isObject(options)) {
            leading = 'leading' in options ? !!options.leading : leading;
            trailing = 'trailing' in options ? !!options.trailing : trailing;
          }
          return debounce(func, wait, {
           'leading': leading,
           'maxWait': wait,
           'trailing': trailing
         });
       }
    

    然后将该函数作为方法附加到对象:

    lodash.add = add;
    lodash.attempt = attempt;
    lodash.camelCase = camelCase;
    ...
    lodash.throttle = throttle;
    lodash.thru = thru;
    lodash.toArray = toArray;
    ...etc
    

    然后使用IIFE 导出lodash 对象。这样做的好处是您可以一次要求多个命名导入:

    const { get, debounce, isEmpty } = require("lodash");
    

    缺点是您需要整个 lodash 对象。因此,为了解决这个问题,他们有单独的文件(和/或 npm 包!!!)以将导入限制在需要的范围内。因此,他们在根包文件夹中包含了类似这样的附加文件:

    ...js
    get.js
    debounce.js
    isEmpty.js
    ...js
    

    但是,这样做的缺点是您现在将拥有三个导入:

    const get = require("lodash/get");
    const debounce = require("lodash/debounce");
    const isEmpty = require("lodash/isEmpty");
    

    但是!您将有一个整体较小的导入大小......但是,包大小更大!因此,为了缓解这种情况,他们将一些流行的方法分解为自己的单独包:lodash.get、lodash.debouncelodash.isEmpty

    因此,总而言之,如果您不打算使用 CJS/UMD/AMD(就像 lodash 那样),那么在使用 webpack 时,tree-shaking 将在 production 中按预期工作客户端中的ESM包。但是,如果您包含额外的构建以获得更高的兼容性,那么您必须创建一个具有不同 inputs 和不同 outputs 的汇总配置数组。

    例如:

    const resolutions = {
        globals: {
            react: "React",
            "react-is": "reactIs",
        },
        exports: "named",
    };
    
    export default [
      {
        input: "./src/index.js", // this transforms the entire source
        output: [
            {
                file: pkg.main,
                format: "cjs",
                ...resolutions,
            },
            {
                file: pkg.fallback,
                format: "umd",
                name: "My-Example-Library",
                ...resolutions,
            },
            {
                file: pkg.module,
                format: "esm",
                ...resolutions,
            },
        ],
        ...etc
      },
      {
        input: "./src/components/example.js", // this transforms just an "example.js" file and ouputs to a "dist/example.[build].js" file
        output: [
            {
                file: "dist/example.cjs.js,
                format: "cjs",
                ...resolutions,
            },
            {
                file: dist/example.umd.js,
                format: "umd",
                name: "My-Example",
                ...resolutions,
            },
        ],
        ...etc
      }
    ]
    

    有关不同构建的用例的更多信息可以在here 找到,并且可以在here 找到示例汇总配置。

    【讨论】:

      猜你喜欢
      • 2021-08-13
      • 1970-01-01
      • 2021-05-15
      • 1970-01-01
      • 1970-01-01
      • 2013-11-18
      • 2018-07-15
      • 2021-05-26
      • 1970-01-01
      相关资源
      最近更新 更多