如何在本地开发 Angular 7 个相互依赖的库? (npm link 问题)
How can I locally develop Angular 7 libraries that depend on each other? (npm link issues)
我有两个 angular 库 NPM 包:
- A有基本成分
- A-BC 的组件建立在 A 的组件之上,增加了与 BC 集成的功能图书馆
A-BC
中的某些组件从 A
导入,例如 import { MyThing } from 'A';
A-BC
的package.json是:
"peerDependencies": {
"A": 1.0.0,
"BC": 4.0.0
},
"devDependencies": {
"A": 1.0.0,
"BC": 4.0.0
}
我尝试的开发步骤是:
npm link --only=production
在(内置版本)A
npm link --only=production
在(内置版本)A-BC
- 在
my-app
, 运行 npm link A
- 在
my-app
、运行npm link A-BC
- 运行
my-app
当 A-BC
找不到安装在任何地方的 A
时,my-app
的编译失败。它们都作为符号链接文件夹在 node_modules
中正确列出。我已经在 tsconfig.json
和 angular.json
中启用了 preserveSymlinks
,但没有帮助。
A
可能是 A-BC
的直接依赖项,但是:
A
和 A-BC
都有一个 forRoot()
调用,它是安装它的应用程序正常运行所必需的。我不知道有什么方法将 forRoot()
参数从 A-BC
forRoot()
动态传递到 A
forRoot()
my-app
需要使用来自 A
的组件和来自 A-BC
的组件。
- 如果
A
是直接依赖项,我不知道如何在本地开发 A-BC
——这可能涉及同时更改 A-BC
和偶尔更改 A
.
目前我的创可贴解决方案是:
- 将
A
发布为测试版
- 在
A-BC
和 my-app
中安装测试版
- Link
A-BC
通过 npm link
到 my-app
- 如果需要进行更改,请发布
A
的新测试版,然后在 my-app
和 A-BC
中再次安装它
可能存在通过 NPM 对本地文件的支持安装 A
的替代工作流程,但我不确定。
我假设您正在谈论的这两个包是使用 ngCli v6 创建的,或者您正在从现有的 ng 工作区中合并它们,无论哪种方式,让我们尝试解决您的问题。
我将假定您具有如下所示的 ng 工作区结构
...
projects >
A
B
host
...
其中 A 是一个库 B 是一个依赖于 A 的库,host 是一个使用 B 的应用程序。
当 working/developing ng 在您的 ng 工作区本地打包时,您应该将它们的别名添加到您的 root
tsconfig.json
文件中,例如:
{
...
"compilerOptions": {
...
"paths": {
"a": [
"dist/a"
],
"a/*": [
"dist/a/*"
],
"b": [
"dist/b"
],
"b/*": [
"dist/b/*"
]
}
}
}
这是在使用 ng new lib {yourLibName}
命令生成库时在 CLI v7 中自动为您完成的。
确保您拥有此配置后,我建议向您的 package.json
添加一些脚本,以便构建您的库并以更直接的方式为您的开发应用程序提供服务(host
在示例的情况)
"build:a": "ng build A --watch=true",
"build:b": "ng build B --watch=true",
"serve:host": "ng serve host"
之后,通过运行三个脚本相继导入相应的libModules
from lib B
in your Host App
和相应的libModules
来自 lib A
inside Lib B
,您将能够使用 lib B
的组件,这取决于来自 lib A
inside Host APP
.[=41= 的组件]
请记住,您不能在您的工作区中安装这两个库,因为这会破坏您项目中的导入,而且这些库不应成为您工作区的一部分 package.json
。
如果您已完成上述步骤但问题仍未解决,请向我们提供 link 到 git 存储库,或分享您的 tsconfig.json
、package.json
, angular.json
文件,以便我们可以继续调查。
回复子评论
所以如果我得到你的情况,你希望能够开发这些 packages
并将它们安装在一个单独的 ng 工作区中。
如果是这种情况,据我所知,没有直接的方法可以做到这一点,您可能可以通过调整 tsconfig.json
文件。
但在我看来,如果你想在同一个工作区内使用这个 ng packages
,你不一定需要推送它们,因为归根结底,它们只是另一组 ngModules
将在您引用它们的应用程序中 "first-class citizens"。因此,在为生产构建时,它们将是 tree-shaken、minimized-optimized 等。在这种情况下,您应该只扩展 package.json
中的部署脚本,这样在您开始构建主应用程序之前,这将取决于那些 npm/ng/packages
,您构建那些包。
"deploy": "ng build A && ng build B && ng build MainApp --production"
与此同时,那些 npm/ng/packages
仍然可以 npm
发布,您将能够在其他工作区中使用它们。
请记住,它们不应属于同一(正在开发它们的工作区)工作区的 package.json
依赖项。
我最初尝试做的事情遇到了很多问题,因为场景一开始就错了。
我在这里学到的主要两件事是:
- 只在内部 angular 项目中使用的包不应该
发布到 npm
- 如果库相互依赖,它们应该直接从您的 typescript/angular 来源导入
如果您试图使我描述的场景有效,它会让您头疼不已,因为它是一种根本上有问题的方法。
现在共享这些库的所有相关项目都在一个 nx monorepo 中。直接导入库后,一切都会自动进行实时重新加载、tree shaking 等,正如其他 answers/comments 此处所建议的那样。迁移不是很麻烦,monorepo 设置的工具非常好。
当设置你的 monorepo 使这个场景工作时,库将通过 tsconfig 路径导入到每个项目,如下所示。这使得 npm 包的旧导入语句能够保持不变,因为您的路径可以只引用以前的 npm 包的名称(如上面问题中的 A 或 A-BC)。
每个项目现在也共享相同的包 json,并且通过将这些工具脚本集中在 monorepo 根中,而不是在每个项目中单独使用工具,用于服务、构建等的 npm 脚本得到了极大的改进回购
@angular/*
的路径修复了库冲突的一些问题。
示例路径来自 /apps/example-project/tsconfig.json
"paths": {
"@angular/*": ["../node_modules/@angular/*"],
"@exampleNPMOrg/A": [
"../../libs/A/src/index"
],
"@exampleNPMOrg/A-BC": [
"../../libs/A-BC/src/index"
],
}
示例路径来自 /tsconfig.json
"paths": {
"@exampleNPMOrg/A": [
"libs/A/src/index"
],
"@exampleNPMOrg/A-BC": [
"libs/A-BC/src/index"
],
}
我有两个 angular 库 NPM 包:
- A有基本成分
- A-BC 的组件建立在 A 的组件之上,增加了与 BC 集成的功能图书馆
A-BC
中的某些组件从 A
导入,例如 import { MyThing } from 'A';
A-BC
的package.json是:
"peerDependencies": {
"A": 1.0.0,
"BC": 4.0.0
},
"devDependencies": {
"A": 1.0.0,
"BC": 4.0.0
}
我尝试的开发步骤是:
npm link --only=production
在(内置版本)A
npm link --only=production
在(内置版本)A-BC
- 在
my-app
, 运行npm link A
- 在
my-app
、运行npm link A-BC
- 运行
my-app
当 A-BC
找不到安装在任何地方的 A
时,my-app
的编译失败。它们都作为符号链接文件夹在 node_modules
中正确列出。我已经在 tsconfig.json
和 angular.json
中启用了 preserveSymlinks
,但没有帮助。
A
可能是 A-BC
的直接依赖项,但是:
A
和A-BC
都有一个forRoot()
调用,它是安装它的应用程序正常运行所必需的。我不知道有什么方法将forRoot()
参数从A-BC
forRoot()
动态传递到A
forRoot()
my-app
需要使用来自A
的组件和来自A-BC
的组件。- 如果
A
是直接依赖项,我不知道如何在本地开发A-BC
——这可能涉及同时更改A-BC
和偶尔更改A
.
目前我的创可贴解决方案是:
- 将
A
发布为测试版 - 在
A-BC
和my-app
中安装测试版
- Link
A-BC
通过npm link
到 - 如果需要进行更改,请发布
A
的新测试版,然后在my-app
和A-BC
中再次安装它
my-app
可能存在通过 NPM 对本地文件的支持安装 A
的替代工作流程,但我不确定。
我假设您正在谈论的这两个包是使用 ngCli v6 创建的,或者您正在从现有的 ng 工作区中合并它们,无论哪种方式,让我们尝试解决您的问题。
我将假定您具有如下所示的 ng 工作区结构
...
projects >
A
B
host
...
其中 A 是一个库 B 是一个依赖于 A 的库,host 是一个使用 B 的应用程序。
当 working/developing ng 在您的 ng 工作区本地打包时,您应该将它们的别名添加到您的 root
tsconfig.json
文件中,例如:
{
...
"compilerOptions": {
...
"paths": {
"a": [
"dist/a"
],
"a/*": [
"dist/a/*"
],
"b": [
"dist/b"
],
"b/*": [
"dist/b/*"
]
}
}
}
这是在使用 ng new lib {yourLibName}
命令生成库时在 CLI v7 中自动为您完成的。
确保您拥有此配置后,我建议向您的 package.json
添加一些脚本,以便构建您的库并以更直接的方式为您的开发应用程序提供服务(host
在示例的情况)
"build:a": "ng build A --watch=true",
"build:b": "ng build B --watch=true",
"serve:host": "ng serve host"
之后,通过运行三个脚本相继导入相应的libModules
from lib B
in your Host App
和相应的libModules
来自 lib A
inside Lib B
,您将能够使用 lib B
的组件,这取决于来自 lib A
inside Host APP
.[=41= 的组件]
请记住,您不能在您的工作区中安装这两个库,因为这会破坏您项目中的导入,而且这些库不应成为您工作区的一部分 package.json
。
如果您已完成上述步骤但问题仍未解决,请向我们提供 link 到 git 存储库,或分享您的 tsconfig.json
、package.json
, angular.json
文件,以便我们可以继续调查。
回复子评论
所以如果我得到你的情况,你希望能够开发这些 packages
并将它们安装在一个单独的 ng 工作区中。
如果是这种情况,据我所知,没有直接的方法可以做到这一点,您可能可以通过调整 tsconfig.json
文件。
但在我看来,如果你想在同一个工作区内使用这个 ng packages
,你不一定需要推送它们,因为归根结底,它们只是另一组 ngModules
将在您引用它们的应用程序中 "first-class citizens"。因此,在为生产构建时,它们将是 tree-shaken、minimized-optimized 等。在这种情况下,您应该只扩展 package.json
中的部署脚本,这样在您开始构建主应用程序之前,这将取决于那些 npm/ng/packages
,您构建那些包。
"deploy": "ng build A && ng build B && ng build MainApp --production"
与此同时,那些 npm/ng/packages
仍然可以 npm
发布,您将能够在其他工作区中使用它们。
请记住,它们不应属于同一(正在开发它们的工作区)工作区的 package.json
依赖项。
我最初尝试做的事情遇到了很多问题,因为场景一开始就错了。
我在这里学到的主要两件事是:
- 只在内部 angular 项目中使用的包不应该 发布到 npm
- 如果库相互依赖,它们应该直接从您的 typescript/angular 来源导入
如果您试图使我描述的场景有效,它会让您头疼不已,因为它是一种根本上有问题的方法。
现在共享这些库的所有相关项目都在一个 nx monorepo 中。直接导入库后,一切都会自动进行实时重新加载、tree shaking 等,正如其他 answers/comments 此处所建议的那样。迁移不是很麻烦,monorepo 设置的工具非常好。
当设置你的 monorepo 使这个场景工作时,库将通过 tsconfig 路径导入到每个项目,如下所示。这使得 npm 包的旧导入语句能够保持不变,因为您的路径可以只引用以前的 npm 包的名称(如上面问题中的 A 或 A-BC)。
每个项目现在也共享相同的包 json,并且通过将这些工具脚本集中在 monorepo 根中,而不是在每个项目中单独使用工具,用于服务、构建等的 npm 脚本得到了极大的改进回购
@angular/*
的路径修复了库冲突的一些问题。
示例路径来自 /apps/example-project/tsconfig.json
"paths": {
"@angular/*": ["../node_modules/@angular/*"],
"@exampleNPMOrg/A": [
"../../libs/A/src/index"
],
"@exampleNPMOrg/A-BC": [
"../../libs/A-BC/src/index"
],
}
示例路径来自 /tsconfig.json
"paths": {
"@exampleNPMOrg/A": [
"libs/A/src/index"
],
"@exampleNPMOrg/A-BC": [
"libs/A-BC/src/index"
],
}