ApkList 源问题修复
问题描述
很久没动的 Angular
项目忽然修改东西,自动化发布失败了。
问题原因
淘宝源从 https://registry.npm.taobao.org/
更换为 https://registry.npmmirror.com
导致获取依赖失败
修复方案
方案一 更改源后生成新的 yarn.lock 文件(失败)
- 移除
yarn.lock
文件 - 使用
npm config set registry https://registry.npmmirror.com
设置源 - 然后执行
yarn install
最后运行 node_modules/@angular/cli/bin/ng build
为什么之前还能构建的项目,现在就不行呢?
这个问题实际上次构建使用的依赖是保存在 yarn.lock
文件上的,移除整个yarn.lock
文件后,同时因为package.json
声明小版本可以升级的问题,导致最后生成的 yarn.lock
文件实际上用到的依赖和以前的依赖是不一样的
从文件对比中可以发现,版本是有小升级的,为什么会这样? ,因为我们写的 package.json
文件的依赖关系是有问题的。
上图中可以看到每个依赖的版本号前面都有符号,这些符号是代表不同的意思,完整意思如下
在使用 yarn add
命令添加依赖项时,可以通过指定版本号以及使用不同的符号来控制安装的依赖版本范围。这些符号包括 ^
, ~
, <=
, >=
, =
, 和无符号版本号。下面是一些常用的例子和它们的含义:
使用 ^
符号
- 命令:
yarn add @angular/forms@^8.2.14
- 含义:安装
@angular/forms
版本 8.2.14 及其所有向后兼容的次版本更新,即>= 8.2.14 < 9.0.0
。
使用 ~
符号
- 命令:
yarn add @angular/forms@~8.2.14
- 含义:安装
@angular/forms
版本 8.2.14 及其所有向后兼容的修订版本更新,即>= 8.2.14 < 8.3.0
。
使用 <=
符号
- 命令:
yarn add @angular/forms@<=8.2.14
- 含义:安装
@angular/forms
版本 8.2.14 或更低版本。
使用 >=
符号
- 命令:
yarn add @angular/forms@>=8.2.14
- 含义:安装
@angular/forms
版本 8.2.14 或更高版本。
使用 =
符号
- 命令:
yarn add @angular/forms@=8.2.14
- 含义:安装
@angular/forms
的确切版本 8.2.14。
不使用符号(默认行为)
- 命令:
yarn add @angular/forms
- 含义:安装
@angular/forms
的最新版本(通常是最新的稳定版本)。
使用多个版本范围
你也可以结合多个版本范围来指定更复杂的依赖规则。
- 命令:
yarn add @angular/forms@">=8.2.14 <9.0.0"
- 含义:安装
@angular/forms
版本在 8.2.14 及其以上但低于 9.0.0 的版本。
示例
假设你想安装 @angular/forms
版本在 8.2.x 系列中最新的修订版本,但不想升级到 8.3.x 或更高版本,可以使用以下命令:
yarn add @angular/forms@~8.2.14
这样会确保安装版本范围在 >= 8.2.14 < 8.3.0
之间。
总结
使用这些版本控制符号,你可以更精确地管理项目中的依赖版本,确保在获得最新更新的同时,不会因为版本不兼容而引发问题。以下是一些常见的符号及其含义的总结:
^
: 允许升级到不改变主版本号的最新版本。~
: 允许升级到不改变次版本号的最新版本。<=
: 允许安装指定版本或更低版本。>=
: 允许安装指定版本或更高版本。=
: 安装确切版本。
根据项目需求选择合适的符号,可以更好地控制依赖版本的安装。
方案二 直接替换 yarn.lock
文件域名(完美可行)
就像这样直接全局替换为 https://registry.npmmirror.com/
即可
方案三 最终解决方案
真正的问题是因为 package.json
编写的 version
并不是固定的,而是动态的,这个在依赖管理中其实是大忌,毕竟你永远不知道第三方包的一个小升级是否会导致你代码出现问题。
所以,根本的解决方案是把,yarn.lock
中依赖的版本提取出来,然后放到 package.json
文件中。我用 kotlin 编写了以下代码来进行校准版本
package com.hangox.test
import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.JsonObject
import java.io.File
/**
* package 文件位置,用来对比更新
*/
val PACKAGE_JSON_PATH = "/path/package.json"
/**
* lock 文件位置,用来提取实际上依赖的包
*/
val YARN_LOCK_FILE = File("/patch/yarn.lock")
fun main() {
val yarnLockFile = YARN_LOCK_FILE
val lockFilerVersionMap = mutableMapOf<String, String>()
yarnLockFile.bufferedReader().use { reader ->
var currentPackage: String? = null
reader.forEachLine { line ->
val trimmedLine = line.trim()
when {
!line.startsWith(" ") && trimmedLine.endsWith(":") -> {
val lineName = trimmedLine.replace("\"", "").replace(":", "")
val packageName = if (lineName.startsWith("@")) {
// 提取第二个 @ 位置的内容
"@" + lineName.substringAfter("@").substringBefore("@")
} else {
trimmedLine.substringBefore("@")
}
currentPackage = packageName
}
trimmedLine.startsWith("version") -> {
// Extract version
val version = trimmedLine.substringAfter("version").trim().removeSurrounding("\"")
if (currentPackage != null) {
lockFilerVersionMap[currentPackage!!] = version
}
}
}
}
}
// Print all versions
lockFilerVersionMap.forEach { (packageName, version) ->
println("Package: $packageName, Version: $version")
}
File(PACKAGE_JSON_PATH).readText().let {
val data = Gson().fromJson(it, JsonObject::class.java)
listOf("dependencies", "devDependencies").forEach { depKey ->
val depJson = data.get(depKey).asJsonObject
depJson.entrySet().forEach { (packageName, packageVersion) ->
val key = packageName
val lockVersion = lockFilerVersionMap[key]
if (lockVersion == null) {
println("不存在的版本: $packageName, lockVersion: $lockVersion packageVersion : $packageVersion")
return@forEach
}
if (packageVersion.asString != lockVersion) {
println("replace: $packageName, lockVersion: $lockVersion packageVersion : $packageVersion")
}
depJson.addProperty(key, lockVersion)
}
println(GsonBuilder().setPrettyPrinting().create().toJson(depJson))
}
}
}
脚本会输出完整的依赖文本(如下),只要替换掉原本的依赖文本即可