【问题标题】:Import from subfolder of npm package从 npm 包的子文件夹导入
【发布时间】:2017-11-04 19:53:39
【问题描述】:

我一直致力于创建一个小型 React 组件库,以用于其他几个项目。我在内部发布包(使用私有 GitHub 存储库),然后包含在另一个项目中。但是,当我从包的子目录导入时,由于路径不匹配,我无法这样做。

使用该包的项目都使用 webpack 来捆绑/转译代码,因为我尽量避免在组件库中进行任何构建。

目录结构

- package.json
- src/
  - index.js
  - Button/
    - index.js
    - Button.jsx
    - ButtonGroup.jsx
  - Header/
    - index.js
    - Header.jsx (default export)

package.json

...
"main": "./src/index.js",
"scripts": "",
...

src/Button/index.js

import Button from './Button';
import ButtonGroup from './ButtonGroup';

export default Button;

export { Button, ButtonGroup};

src/index.js

如果只从子目录导入,这个文件真的有必要吗?

import Button from './Button';
import ButtonGroup from './Button/ButtonGroup';
import Header from './Header';

export { Button, ButtonGroup, Header };

其他项目

// This project is responsible for building/transpiling after importing
import { Button, ButtonGroup } from 'components-library/Button';

示例

Material-UI 是一个 React 组件库,通过以下方式使用:import { RadioButtonGroup } from 'material-ui/RadioButton。我试图弄清楚这对他们是如何工作的,但还没有成功。

类似问题

问题

  1. 我可以在导入路径中以某种方式跳过src/ 目录吗?
  2. 我可以跳过包中的任何类型的构建阶段(这样开发人员就不必在提交之前构建)吗?
  3. 类似于 material-ui 的包如何处理这个问题?

【问题讨论】:

  • 您是否发现Material-UI 是如何实现import npm-package/subfolder/Component 的方式来导入src/subfolder/Component 组件的?
  • 我最终从这个转向其他选择,抱歉。
  • 您能分享一下您的经验吗?我目前正在寻找类似的东西,但找不到有用的资源。现在我正在打包一个我正在编写的没有src 目录(github.com/tonix-tuft/react-js-utl)的库。我在项目的根目录中使用 ES6 源代码创建子文件夹并将这些目录发布到 NPM,但我想这不是最佳的(例如 ES6 导出在 Node 中的服务器端不起作用)......不过,我可以使用react-js-utl/subfolder 语法导入所需的文件。顺便说一句,祝你新年快乐!谢谢。
  • 不幸的是我不记得我最后做了什么,因为它已经快一年半了:(。我确实希望有这方面的资源,但请记住我不能很快就弄清楚了,不得不继续前进。
  • 你可以这个我的anwser stackoverflow.com/a/61829655/8079868

标签: javascript node.js npm webpack package.json


【解决方案1】:

答案可能取决于您安装组件库的方式。如果您是通过npm install <git-host>:<git-user>/<repo-name>npm install <git repo url> 完成的,

  1. 根据your first linked question,您应该可以按原样使用import {Button} from 'component-library/Button'。与Node's require() resolution 类似,Webpack 应该解析组件库中相对于组件库入口点的子目录。您可以通过 webpack.config.resolve 属性找到有关自定义解析行为的文档。 material-ui 似乎依赖于从模块入口目录解析子目录导入。

  2. 要分发 ES 模块库,无需在分发之前进行构建。但是,create-react-app 等项目可能需要预编译版本。

或者,您可以写import {Button} from 'components-library'。 Webpack 会毫不费力地通过每个 index 追溯依赖关系。

【讨论】:

    【解决方案2】:

    其中一个可能的解决方案是 webpack 别名系统。
    您可以创建另一个项目,例如将其命名为“app-aliases”,这样您的别名就可以重复使用。
    这个项目将有一个包含所有包路径的 js 文件:

    const path = require('path');
    
    module.exports = {
    '@components': path.resolve(__dirname, 'node_modules/components-library/src'),
    '@another': path.resolve(__dirname, 'node_modules/any/path/you/want'),
    }
    

    然后将其添加到任何负责构建/转译的项目的 webpack 配置中:
    webpack.config.js

    const appAliases = require('app-aliases');
    
    const config = {
    ...
      resolve: {
        alias: {
          ...appAlises
        }
      }
    }
    

    在运行时代码中你可以这样使用它:

    import {Button} from '@components/Button';
    import {Something} from '@another'
    

    如果您使用的是 typescript,则需要将相同的别名添加到 paths tsconfig 属性。
    所以你的问题的答案是:

    1. 是的,您可以在别名中使用任何路径
    2. 是的,不必构建所有项目
    3. 我看到现在 mui 使用来自 directi 包(例如核心)的导入,请参阅 https://material-ui.com/components/radio-buttons/import Radio from '@material-ui/core/Radio';。但我希望他们使用我在下面描述的再出口。

    还有关于node.js的解析机制。
    当您导入某个库时,它会尝试在其中找到 node_modules/some-library/package.jsonmain 属性。此属性应指向您的主要入口点。通常是src/index.js(如果还没有,你应该在 package.json 中设置它)。在此文件中,您可以从内部文件结构中重新导出您想要的任何内容,并且可以在没有完整路径的情况下使用它。 有关示例,请参阅此repo

    【讨论】:

    • 我不能花时间在原始答案的上下文中验证这一点(因为我不再拥有该项目);但是,它似乎与我现在对 Webpack 别名等的了解相匹配。
    【解决方案3】:

    我是一名 Angular 开发人员,从未使用过 react,但我可以说 material-ui 正在使用 monorepo,其中相同的概念存在于 angular 中,我们创建一个工作区,并且该工作区包含多个项目/包,如 react 中命名的那样。欲了解更多信息Workspaces with Yarn

    Material-ui 在 tsconfig 中使用假路径使其看起来像 src 文件夹在您提供的 git 中不存在:tsconfig.json

    【讨论】:

    • 这个答案是否解决了用户的问题?您可能希望将您的技能和经验带到带有 angular 标记的问题中。
    • 是的,如果你按照我的回答,你可以创建一个与军事-ui 项目结构相同的项目。他们所做的是一个包含多个包的工作区,这被称为 monorepo 项目结构。问题的第二部分,您可以将包作为 import { componentName} from '@company/workspaceName' 导入,这是在 tsconfig.json 中完成的,并给了他来自 material-ui 的 axcample,如下所示:“paths”:{“@material -ui/core": ["./packages/material-ui/src"], "@material-ui/core/*": ["./packages/material-ui/src/*"], ... . } 这称为创建假路径。
    【解决方案4】:

    我可以在导入路径中以某种方式跳过 src/ 目录吗?

    是的。使用 package.json "exports" 字段,Webpack 应该会在不久的将来支持该字段(请参阅此 issue),但自 Node 12 LTS 之后的 Bare Module Specifier Resolution proposal 之后,Node 已经支持:

    package.json

    ...
    "main": "./src/index.js",
    "type": "module",
    ...
    "exports": {
      "./Button": "./src/Button/index.js",
      "./Header": "./src/Header/index.js"
    },
    ...
    

    现在,下面的代码:

    // This project is responsible for building/transpiling after importing
    import { Button, ButtonGroup } from 'components-library/Button';
    

    应该翻译成:

    import { Button, ButtonGroup } from 'components-library/src/Button/index.js';
    

    应该正确导入请求的模块。

    警告

    现在,尝试更简单的版本肯定会很诱人:

    ...
    "exports": {
      "./Button": "./src/Button/",
      "./Header": "./src/Header/"
    },
    ...
    

    所以和通常的导入语句一样

    import { ... } from 'components-library/Button';
    

    被翻译成

    import { ... } from 'components-library/src/Button';
    

    这看起来不错,但在这种情况下它不起作用,因为您的子模块没有各自的 package.json 文件,而是依赖于它们的 index.js 文件才能找到。

    /!\ 与 CommonJS 不同,没有自动搜索 index.js 或 index.mjs 或文件扩展名。


    src/index.js - 如果只从子目录导入,这个文件真的有必要吗?

    我不这么认为,但如果你愿意,你可以保留它。


    我可以跳过包中的任何类型的构建阶段吗?

    使用"exports" 字段不需要您转译代码。

    【讨论】:

    【解决方案5】:

    你必须安装babel-plugin-module-resolver

    像这样在 .babelrc 文件别名中指定包的相对路径

    {
      "plugins": [
        ["module-resolver", {
          "alias": {
            "components-library": "./node_module/components-library"
          }
        }]
      ]
    }
    

    然后你可以像这样导入npm包的子目录

    import { Button, ButtonGroup } from 'components-library/Button';
    

    【讨论】:

      【解决方案6】:

      这是可能的,但需要发布一个精选的 dist 文件夹,而不是项目的根目录。

      如果您了解模块解析的工作原理,整个事情就相当简单了,您只需要一个小脚本来准备您的分发。

      为了避免我在这里重复所有细节,请参阅我对Importing from subfolders for a javascript package的回答。

      【讨论】:

        猜你喜欢
        • 2020-10-12
        • 2021-07-09
        • 2021-09-30
        • 2016-04-21
        • 1970-01-01
        • 2013-02-19
        • 1970-01-01
        • 2022-11-23
        • 1970-01-01
        相关资源
        最近更新 更多