0. 引言
本站采用的是微软Azure Static Web App服务(以下简称SWA)部署的,如果不使用Github Actions或Azure Devops,那么SWA CLI是将网站部署到SWA的唯一选择。
SWA CLI在部署网站时依赖一个二进制文件:StaticSitesClient.exe,这个文件的下载可谓是极其的缓慢,60多M的文件,在我这里甚至需要近一个小时的下载时间,这实在是不可忍受的。
为了解决这个问题,我们可以手动下载这个文件并且手动生成配置文件以供SWA CLI使用。
以下是解决方法。
1. 查询版本信息
首先我们使用微软的https://swalocaldeploy.azureedge.net/downloads/versions.jsonAPI来获取到当前可供下载的版本信息,SWA CLI一般使用version为stable的版本。
下面是一个获取到的stable版本的示例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| { "version": "stable", "buildId": "1.0.026911", "publishDate": "2024-05-15T19:23:23.3973684Z", "files": { "linux-x64": { "url": "https://swalocaldeploy.azureedge.net/downloads/1.0.026911/linux/StaticSitesClient", "sha": "e1d9e033c973a35f64b7e41b6a114bd8e48022c9c3f7676e79047e87245a874d" }, "win-x64": { "url": "https://swalocaldeploy.azureedge.net/downloads/1.0.026911/windows/StaticSitesClient.exe", "sha": "c67e5eed2b28fcf5c98348732653d1e2b37d842e6dde9a6b30322832c5d86fc7" }, "osx-x64": { "url": "https://swalocaldeploy.azureedge.net/downloads/1.0.026911/macOS/StaticSitesClient", "sha": "18ca42a1b13db9b8b6db6bd8c77e65def56fa7bf3ce3fb1184e890d8cd7dd033" } } }
|
我们找到其中的win-x64字段,其中的url字段就是下载链接,我们将其下载至本地。
2. 创建本地文件
我们在目录C:\Users\你的用户名.swa\deploy下创建一个文件夹,文件夹名为上方获取到的buildId内容,比如这里是1.0.026911,那么文件夹的全路径就是C:\Users\你的用户名\.swa\deploy\1.0.026911。
将你下载好的StaticSitesClient.exe放入创建好的文件夹中,回到上级文件夹(deploy目录)中,创建StaticSitesClient.json文件,并向其中写入以下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| { "metadata": { "version": "stable", "buildId": "1.0.026911", "publishDate": "2024-05-15T19:23:23.3973684Z", "files": { "linux-x64": { "url": "https://swalocaldeploy.azureedge.net/downloads/1.0.026911/linux/StaticSitesClient", "sha": "e1d9e033c973a35f64b7e41b6a114bd8e48022c9c3f7676e79047e87245a874d" }, "win-x64": { "url": "https://swalocaldeploy.azureedge.net/downloads/1.0.026911/windows/StaticSitesClient.exe", "sha": "c67e5eed2b28fcf5c98348732653d1e2b37d842e6dde9a6b30322832c5d86fc7" }, "osx-x64": { "url": "https://swalocaldeploy.azureedge.net/downloads/1.0.026911/macOS/StaticSitesClient", "sha": "18ca42a1b13db9b8b6db6bd8c77e65def56fa7bf3ce3fb1184e890d8cd7dd033" } } }, "binary":"C:\\Users\\你的用户名\\.swa\\deploy\\1.0.026911\\StaticSitesClient.exe", "checksum":"c67e5eed2b28fcf5c98348732653d1e2b37d842e6dde9a6b30322832c5d86fc7" }
|
其中的metadata字段即为在微软版本API中获得的内容,binary字段为可执行文件的绝对路径(注意路径使用双反斜线分隔),checksum字段则为校验字段,其内容应于metadata中files各平台字段中sha字段内容保持一致。
保存退出该文件,再次运行swa deploy即可成功部署了。
3. 探索过程
解决方案到上面就结束了,下面是整个问题探索的技术过程。
首先我们定位到工具的static-web-apps-cli\dist\cli\commands\deploy\deploy.js文件,这里包含了swa deploy命令的具体执行内容。
顺着文件向下查找,我们可以在此文件中的第220行中发现以下内容:
1
| const { binary, buildId } = await (0, deploy_client_1.getDeployClientPath)();
|
追踪getDeployClientPath函数可以发现,该函数首先尝试获取本地可执行文件的metadata,同时尝试获取远程API中的metadata:
1 2 3
| const localClientMetadata = getLocalClientMetadata(); const binaryVersion = (0, env_1.swaCLIEnv)().SWA_CLI_DEPLOY_BINARY_VERSION || constants_1.DEPLOY_BINARY_STABLE_TAG; const remoteClientMetadata = await fetchClientVersionDefinition(binaryVersion);
|
此处的fetchClientVersionDefinition函数中传入的binaryVersion参数应为”stable”,具体原理由于时间关系未能探明。
继续追踪fetchClientVersionDefinition函数,可以看到该函数尝试从一个常量中定义的URL,也就是之前提到的API地址获取版本信息,具体网址为:https://swalocaldeploy.azureedge.net/downloads/versions.json。
访问这个地址会得到一个数组:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59
| [ { "version": "latest", "buildId": "1.0.027044", "publishDate": "2024-05-28T19:44:23.0025058Z", "files": { "linux-x64": { "url": "https://swalocaldeploy.azureedge.net/downloads/1.0.027044/linux/StaticSitesClient", "sha": "e1d9e033c973a35f64b7e41b6a114bd8e48022c9c3f7676e79047e87245a874d" }, "win-x64": { "url": "https://swalocaldeploy.azureedge.net/downloads/1.0.027044/windows/StaticSitesClient.exe", "sha": "c67e5eed2b28fcf5c98348732653d1e2b37d842e6dde9a6b30322832c5d86fc7" }, "osx-x64": { "url": "https://swalocaldeploy.azureedge.net/downloads/1.0.027044/macOS/StaticSitesClient", "sha": "18ca42a1b13db9b8b6db6bd8c77e65def56fa7bf3ce3fb1184e890d8cd7dd033" } } }, { "version": "stable", "buildId": "1.0.026911", "publishDate": "2024-05-15T19:23:23.3973684Z", "files": { "linux-x64": { "url": "https://swalocaldeploy.azureedge.net/downloads/1.0.026911/linux/StaticSitesClient", "sha": "e1d9e033c973a35f64b7e41b6a114bd8e48022c9c3f7676e79047e87245a874d" }, "win-x64": { "url": "https://swalocaldeploy.azureedge.net/downloads/1.0.026911/windows/StaticSitesClient.exe", "sha": "c67e5eed2b28fcf5c98348732653d1e2b37d842e6dde9a6b30322832c5d86fc7" }, "osx-x64": { "url": "https://swalocaldeploy.azureedge.net/downloads/1.0.026911/macOS/StaticSitesClient", "sha": "18ca42a1b13db9b8b6db6bd8c77e65def56fa7bf3ce3fb1184e890d8cd7dd033" } } }, { "version": "backup", "buildId": "1.0.026792", "publishDate": "2024-05-03T18:31:36.0288058Z", "files": { "linux-x64": { "url": "https://swalocaldeploy.azureedge.net/downloads/1.0.026792/linux/StaticSitesClient", "sha": "a9dcd998d22a3476fb97fe1c446e83cc7f060a3a36cdb6757b828d0facc42347" }, "win-x64": { "url": "https://swalocaldeploy.azureedge.net/downloads/1.0.026792/windows/StaticSitesClient.exe", "sha": "15f03e3f91208db2ea4015c4fce0623a692da1a289f23a782578ab7bc8a810e2" }, "osx-x64": { "url": "https://swalocaldeploy.azureedge.net/downloads/1.0.026792/macOS/StaticSitesClient", "sha": "454b10f0351694ec3475a3d85b8746356932b2061a5be7e7fc093a6509cf000c" } } } ]
|
函数会筛选返回的结果以匹配binaryVersion字段的内容,例如version为stable的内容。
追踪getLocalClientMetadata函数可以发现,该函数尝试从部署文件夹中读取一个名为StaticSitesClient.json的文件并做二进制文件存在性检测,代码如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| exports.getDeployClientPath = getDeployClientPath; function getLocalClientMetadata() { const metadataFilename = path_1.default.join(constants_1.DEPLOY_FOLDER, `${constants_1.DEPLOY_BINARY_NAME}.json`); if (!fs_1.default.existsSync(metadataFilename)) { utils_1.logger.warn(`Could not find ${constants_1.DEPLOY_BINARY_NAME} local binary`); return null; } let metadata = null; try { metadata = JSON.parse(fs_1.default.readFileSync(metadataFilename, "utf8")); } catch (err) { utils_1.logger.warn(`Could not read ${constants_1.DEPLOY_BINARY_NAME} metadata: ${err}`); return null; } if (metadata) { utils_1.logger.warn(fs_1.default.existsSync(metadata.binary)); if (!fs_1.default.existsSync(metadata.binary)) { utils_1.logger.warn(`Could not find ${constants_1.DEPLOY_BINARY_NAME} binary: ${metadata.binary}`); return null; } else if (fs_1.default.existsSync(metadata.binary)) { return metadata; } } return null; }
|
顺着getDeployClientPath函数继续往下走,会发现当localClientMetadata不存在时,函数便会调用download_binary_helper.js中的downloadAndValidateBinary函数进行二进制文件的下载。
继续追踪downloadAndValidateBinary函数,我们直奔重点,发现其中存在一个名为saveMetadata的函数,想必这其中就包含了我们需要的Json文件的内容。
追踪saveMetadata函数,可以看到该函数有如下内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
|
function saveMetadata(release, binaryFileName, sha, binaryName) { const downloadFolder = getFolderForSavingMetadata(binaryName); if (downloadFolder != null) { const metadataFileName = path_1.default.join(downloadFolder, `${binaryName}.json`); const metdata = { metadata: release, binary: binaryFileName, checksum: sha, }; fs_1.default.writeFileSync(metadataFileName, JSON.stringify(metdata)); utils_1.logger.silly(`Saved metadata to ${metadataFileName}`); } }
|
该函数内容清晰易懂,结合上方分析内容,即可得出我们需要的Json内容了。
将二进制文件和Json文件分别放置在版本号文件夹和部署文件夹后,再次运行swa deploy,问题即可完美解决。
感谢你能看到这里,如果这篇文章能解决你关于SWA CLI下载二进制文件速度慢的问题的话,那再好不过了。
顺带吐槽微软这个stable版本的下载速度,科学上网也只有两三百K,怪不得慢呢。