纱线工作区——包别名

Posted

技术标签:

【中文标题】纱线工作区——包别名【英文标题】: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""

【问题讨论】:

【参考方案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 可以类似的方式使用。

【讨论】:

我认为您误解了我的意图,无论实现名称本身是什么,我都想为包命名。 啊,是的,你完全正确。上下文切换有时会这样做。呵呵。然后我可能会删除

以上是关于纱线工作区——包别名的主要内容,如果未能解决你的问题,请参考以下文章

关于Mybatis-别名

Java包导入别名[重复]

6trait特质包别名文件

11 MyBatis——别名设置

text 我通过composer包管理器使用phpunit的别名

在制作 Laravel 包时,如何注册依赖包的服务提供者和别名?