纱线工作区——包别名
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 可以类似的方式使用。
【讨论】:
我认为您误解了我的意图,无论实现名称本身是什么,我都想为包命名。 啊,是的,你完全正确。上下文切换有时会这样做。呵呵。然后我可能会删除以上是关于纱线工作区——包别名的主要内容,如果未能解决你的问题,请参考以下文章