【问题标题】:Yarn workspaces -- package alias纱线工作区——包别名
【发布时间】:2020-08-21 17:06:21
【问题描述】:

TL;DR 如何为本地纱线工作区依赖项创建别名?

我之前尝试过 yarn 工作区,但从未成功,我正在再试一次。

我在package.json 中设置了"workspaces": ["packages/*"]。

对于每个包,我决定使用命名约定 @-/package-name 来防止命名冲突,并且不用担心内部包的命名空间。

在将包添加为依赖项时,我一直遵循一种使用接口名称进行解析的风格,但将其指向具体的实现。这是我在使用 yarn 工作区之前所做的:

"dependencies": {
  "my-interface-name": "file:some/path/to/packages/some-concrete-implementation"
}

这基本上是为了允许我喜欢称之为编译时静态依赖注入。这也意味着每个包都可以根据需要单独命名其接口依赖项,并防止命名冲突。

但是,我不知道如何使用 yarn 工作区来实现这一点。如何为我的 yarn 工作区包 @-/some-concrete-implementation 创建一个别名,名为 my-interface-name?

我已经尝试过但没有成功:

  • 定义像 "my-interface-name": "@-/some-concrete-implementation"} 这样的依赖项 - 由于某种原因,这会导致 yarn 在 npm 注册表而不是本地工作区中查找 @-/some-concrete-implementation
  • 我也尝试过使用工作区协议:"my-interface-name": "workspace:@-/some-concrete-implementation"},但它仍然会在 npm 注册表中查找包!

我还没有尝试过并且可以工作,但首先消除了使用纱线工作区的好处:

  • "dependencies": {"my-interface-name": "file:../../node_modules/@-/some-concrete-implementation"}"

【问题讨论】:

    标签: node.js npm yarnpkg yarn-workspaces dependency-resolution


    【解决方案1】:

    你见过resolutions package.json key吗?是你需要的吗?

    我已将它用于别名/覆盖外部包,但文档中的示例显示它可以与本地包一起使用。

    决议

    允许您覆盖特定嵌套依赖项的版本。有关完整规范,请参阅 Selective Versions Resolutions RFC。

    {
      "resolutions": {
        "transitive-package-1": "0.0.29",
        "transitive-package-2": "file:./local-forks/transitive-package-2",
        "dependencies-package-1/transitive-package-3": "^2.1.1"
      }
    }
    

    来自 RFC:

    “**/a”表示项目所有嵌套的依赖a。

    "a" 是 **/a 的别名(为了追溯兼容性,请参见下文,因为如果它不是这样的别名,它就没有任何意义,因为它代表非嵌套的一个项目依赖项,不能被覆盖,如下所述)。

    所以,我相信你需要的规则是:

    "**/my-interface-name": "file:some/path/to/packages/some-concrete-implementation"
    
    // OR equivalent
    
    "my-interface-name": "file:some/path/to/packages/some-concrete-implementation"
    

    我相信它在包的 package.json 中有效。在最坏的情况下,您可以将其提升到工作区根并制定特定于工作区的规则,例如“a/b”。

    【讨论】:

    • 但它说它是为了“嵌套依赖”。它是否也适用于同一 package.json 中的依赖项?
    • 有人告诉我可以,但我自己没有测试过。用更多细节更新了答案。
    • 你也可以看看这个包:github.com/mweststrate/relative-deps
    • 我曾经使用file: 协议,但现在我使用的是纱线工作空间,我想使用@myyarnworskpace/package 指向纱线工作空间。反正我明天试试看。
    • resolutions 字段似乎有点工作,但我没有在根 node_modules 文件夹中看到重命名的包。无论如何,我正在考虑从 yarn 切换到 pnpm,因为它们提供了非平面依赖树,并且依赖别名似乎效果更好。感谢大家的帮助!
    【解决方案2】:

    workspace: alias protocol(也可以在 pnpm 中使用) 似乎是要采取的方向。

    我也尝试使用工作区协议:“my-interface-name”:“workspace:@-/some-concrete-implementation”},但它仍然会在 npm 注册表中查找包!

    一定要安装 yarn 3,否则你会遇到奇怪的问题。

    注意"my-interface-name": "workspace:@-/some-concrete-implementation" 的语法看起来不正确。

    它应该是"@xxx/some-concrete-implementation": "workspace:*",,假设链接包的名称是"name": "@xxx/some-concrete-implementation"。

    考虑到这一点,您甚至不需要创建特定的@-/name。使用工作区协议,yarn 将确保它永远不会从 npm 下载。它成为内部工作区依赖项。

    PS:


    Yarn 3 安装

    一般来说,一个简单的yarn set version 3.0.2 && yarn plugin import workspace-tools) 就可以了。

    为避免 pnp 电流限制,请检查生成的配置 .yarnrc.yml 并确保将 nmLinker 设置为“node-modules”

    # Yarn 2+ supports pnp or regular node_modules installs. Use node-modules one.
    nodeLinker: node-modules
    plugins:
      - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs
        spec: "@yarnpkg/plugin-workspace-tools"
    yarnPath: .yarn/releases/yarn-3.0.2.cjs
    

    PS:您可能也想将其添加到.gitignore

    .yarn/*
    !.yarn/patches
    !.yarn/releases
    !.yarn/plugins
    !.yarn/sdks
    !.yarn/versions
    .pnp.*
    

    之后运行yarn install。

    关于 package.json 的

    和你一样,根 package.json 将定义工作区路径:

    {
      "name": "monorepo",
      "workspaces": [
        "packages/*"  // Enable package discovery in packages/* directory.
      ],
      // ... 
      "devDependencies": {
        "husky": "7.0.2", // Only what's needed for monorepo management
      }
    

    在您的应用中packages/app/package.json

    {
      "name": "my-app",
      "devDependencies": {
        "@types/node": "16.10.1",
        //...
      },
      "dependencies": {
        // Assuming the name of packages/shared is "@your-org/some-concrete-implementation",
        // we explicitly declare the dependency on it through
        // workspace: alias (package-manager perspective)
        "@your-org/some-concrete-implementation": "workspace:*",
      }
    }
    
    

    你消费的包应该声明相同的名字

    {
      "name": "@your-org/some-concrete-implementation",
    }
    
    

    奖励:Typescript 别名

    如果您的项目是用 ts 编写的,您甚至可以通过以下方式复制您的路径 typescript path mapping。它将允许按原样包含文件(无需事先编译)。

    按照您的示例,只需以这种方式编辑./packages/xxx/tsconfig.json

    {
      "compilerOptions": {
        // here baseUrl is set at ./src (good practice), can
        // be set to '.'  
        "baseUrl": "./src",
        "paths": {
          // Declare deps here (keep them in sync with what
          // you defined in the package.json)
          // PS: path are relative to baseUrl
          "@your-org/some-concrete-implementation/*": ["../../some-concrete-implementation/src/*"],
          // if you have a barrel in ui-lib 
          "@your-org/some-concrete-implementation": ["../../some-concrete-implementation/src/index"],
        }
      },
    }
    
    

    PS:对于非 typescript:babel/plugin-module-resolver 可以类似的方式使用。

    【讨论】:

    • 我认为您误解了我的意图,无论实现名称本身是什么,我都想为包命名。
    • 啊,是的,你完全正确。上下文切换有时会这样做。呵呵。然后我可能会删除
    猜你喜欢
    • 2018-07-18
    • 1970-01-01
    • 2020-09-30
    • 2019-07-13
    • 2020-07-31
    • 2020-07-04
    • 2021-06-03
    • 2021-08-08
    • 1970-01-01
    相关资源
    最近更新 更多