Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Bug]: 当使用仓库镜像时,modern 命令报错:package @modern-js/codesmith-global@latest not found in registry #6879

Open
StephenPCG opened this issue Feb 24, 2025 · 22 comments
Labels
bug Something isn't working

Comments

@StephenPCG
Copy link

版本信息

System:
    OS: macOS 15.3.1
    CPU: (16) arm64 Apple M3 Max
    Memory: 6.06 GB / 64.00 GB
    Shell: 5.2.37 - /opt/homebrew/bin/bash
  Browsers:
    Edge: 133.0.3065.82
    Safari: 18.3
  npmPackages:
    @modern-js/app-tools: 2.65.1 => 2.65.1 
    @modern-js/plugin-tailwindcss: 2.65.1 => 2.65.1 
    @modern-js/runtime: 2.65.1 => 2.65.1 
    @modern-js/tsconfig: 2.65.1 => 2.65.1

问题详情

我们公司内部搭建了 npmjs 的镜像(使用 nexus oss 搭建),我在本地的 ~/.npmrc 中如下配置:

registry=https://nexus.my-company.com/repository/npmjs-proxy/

该镜像已使用了数年,之前没有碰到过问题。这两天我们打算开始用 modern.js,碰到了问题。

首先是创建项目,pnpm dlx @modern-js/create@latest,会报如下错误:

/Users/stephen/.npm/_npx/12956c23babf5cf1/node_modules/@modern-js/codesmith/dist/cjs/utils/downloadPackage.js:138
      throw new Error(`package ${pkgName}@${pkgVersion} not found in registry`);
            ^

Error: package @modern-js/codesmith-global@latest not found in registry
    at downloadPackage (/Users/stephen/.npm/_npx/12956c23babf5cf1/node_modules/@modern-js/codesmith/dist/cjs/utils/downloadPackage.js:138:13)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)
    at async MaterialsManager.loadRemoteGenerator (/Users/stephen/.npm/_npx/12956c23babf5cf1/node_modules/@modern-js/codesmith/dist/cjs/materials/index.js:48:23)
    at async MaterialsManager.prepareGlobal (/Users/stephen/.npm/_npx/12956c23babf5cf1/node_modules/@modern-js/codesmith/dist/cjs/materials/index.js:83:28)
    at async CodeSmith.prepareGlobal (/Users/stephen/.npm/_npx/12956c23babf5cf1/node_modules/@modern-js/codesmith/dist/cjs/codesmith/index.js:79:5)

npmrcregistry 一行注释掉之后重新运行上述命令,可以成功。恢复 npmrc 文件,日常所有操作都正常。但运行 modern new 等命令时,仍然会报上述错误。

不知道是不是 downloadPackage 中下载包的方式有问题,导致 nexus 没有去上游检查文件,而是直接返回了 404(这是我根据现象猜测的,希望没有把问题带偏)?

复现链接

复现步骤

见问题详情

@StephenPCG StephenPCG added the bug Something isn't working label Feb 24, 2025
@zllkjc
Copy link
Member

zllkjc commented Feb 24, 2025

你的意思是加上了 https://nexus.my-company.com/repository/npmjs-proxy/ 这个 npm 源后会出现找不到包的现象吗,是不是因为这些包没有在内部源上同步过。不清楚你们内部源的同步策略是怎么样的,我们内部也会遇到某些包(比如有时候使用 Nuxt)没有同步的问题,通常我们都会手动同步。

你可以试试在这个 npm 源下,直接执行 npm install @modern-js/codesmith-global 是否正常。

@StephenPCG
Copy link
Author

我直接 yarn add @modern-js/codesmith-global@latest 可以执行成功。

我简单跟进了一下 codesmith 中的代码:

export async function getNpmPackageInfo(
  pkgName: string,
  pkgVersion: string,
  options?: Options,
): Promise<PackageInfo> {
  const packageName = `${pkgName}@${pkgVersion}`;
  const packageInfo = NpmPackageInfoCache.get(packageName);
  if (packageInfo) {
    return packageInfo;
  }
  const { registryUrl = await getNpmRegistry(), logger } = options || {};

  const url = `${registryUrl.replace(/\/$/, '')}/${pkgName}/${pkgVersion || 'latest'}`;

  let response: PackageInfo;
  try {
    response = (
      await timeoutPromise(
        axios.get(url),
        NPM_API_TIMEOUT,
        `Get npm package info of '${pkgName}'`,
      )
    ).data;
  } catch (e) {
    logger?.error(e);
    response = await getNpmPackageInfoWithCommand(pkgName, pkgVersion, options);
  }

  const { version } = response;

  NpmPackageInfoCache.set(`${pkgName}@${version || pkgVersion}`, response);

  return response;
}

我看了下,如果是默认的,则要请求的地址是 https://registry.npmjs.org/@modern-js/codesmith-global/latest,使用我们公司的镜像则是 https://registry.my-company.com/repository/npmjs-proxy/@modern-js/codesmith-global/latest,然后代码中期望 response 中有 version 属性,于是我手动检查了一下,发现这两个 url 返回的内容竟然不一样,不知道是不是 nexus oss 的问题了。

npmjs 返回的内容:

Image

我司镜像返回的内容:

Image

@caohuilin
Copy link
Member

@StephenPCG 使用 @modern-js/create 的时候加一下 --registry 参数,指向你们自己的 registry

@StephenPCG
Copy link
Author

@caohuilin 正是由于用了我们自己的 registry 才导致的错误,见我前面那条回复,我跟进了一下 codesmith 的代码,发现 getNpmPackageInfo() 中先拼接了一个包的 metadata 的 url,然后请求这个地址,并从这个地址中读取 version 字段,但我发现我们自己的 registry 返回的内容里没有 version 字段。我不太清楚 nexus oss 返回这样的内容(上面有截图)是否符合相关的规范。不过到目前为止,我还没有碰到过问题。npm 安装各种包都是正常的。

PS,我看 getNpmPackageInfo() 中如果发生请求错误,会尝试用 getNpmPackageInfoWithCommand(),这里面用 npm view 来获取版本号,我试了一下,npm view 也是正常的:

Image

@caohuilin
Copy link
Member

@StephenPCG 看起来是你们 nexus oss 的问题了,正常应该存在 version 字段的

@StephenPCG
Copy link
Author

我搜了一下 commonjs registry specification,package version url 中确实提到了返回的内容中应当有 version 字段。看起来 nexus oss 的实现有问题(或者是有其他补充规范?毕竟各种包管理器 npm/yarn/pnpm 等安装包都是正常的)。

这个问题就不打扰你们了,我回头如果有其他发现的话再来补充信息。目前这个问题对我的主要影响是 modern new 命令无法使用(create 毕竟用的少,用的时候临时修改一下npmrc 文件即可。modern new使用相对高频,每次使用时都修改一下 npmrc 文件就有点麻烦了。)

@StephenPCG
Copy link
Author

我刚才找了一下,最新的 npm public registry 的 API:https://github.com/npm/registry/blob/main/docs/REGISTRY-API.md

这里面似乎没有提及 package version url 的 response 内容,只提到了 package root url 的 response,即 Package Metadata ,这里面似乎确实没有提到 version 字段。

我看了一下 npm view 命令的输出,其请求的是 package root url:

npm --loglevel verbose view @modern-js/codesmith-global@latest dist version --json
npm verbose cli /Users/stephen/.venvs/node20/bin/node /Users/stephen/.venvs/node20/bin/npm
npm info using [email protected]
npm info using [email protected]
npm verbose title npm view @modern-js/codesmith-global@latest dist version
npm verbose argv "--loglevel" "verbose" "view" "@modern-js/codesmith-global@latest" "dist" "version" "--json"
npm verbose logfile logs-max:10 dir:/Users/stephen/.npm/_logs/2025-02-24T06_48_22_863Z-
npm verbose logfile /Users/stephen/.npm/_logs/2025-02-24T06_48_22_863Z-debug-0.log
npm http fetch GET 200 https://nexus.my-company.com/repository/npm-group/@modern-js%2fcodesmith-global 117ms (cache revalidated)
{
  "dist": {
    "shasum": "f9af224e98a5cec100cf21a0c55f64614438942e",
    "tarball": "https://nexus.my-company.com/repository/npm-group/@modern-js/codesmith-global/-/codesmith-global-2.6.5.tgz",
    "fileCount": 4,
    "integrity": "sha512-uanilIB5kI5YpeQqm+LPdb9/c6nIdJUMDzXLyC2jNIDaQk01yvxK6pc6mdH3z/0JSabb5TBXWkwADt2paTYN/g==",
    "signatures": [
      {
        "sig": "MEUCIQDjaiEfQimLpYv5thuC6Gh3G6I+zBqo9tZsd7tYcKTljwIgLDR9FI/niSvXO4kvDQWKBVjh9H5mrsjw7aPveMPTdn8=",
        "keyid": "SHA256:jl3bwswu80PjjokCgh0o2w5c2U4LhQAE57gj9cz1kzA"
      }
    ],
    "attestations": {
      "url": "https://registry.npmjs.org/-/npm/v1/attestations/@modern-js%[email protected]",
      "provenance": {
        "predicateType": "https://slsa.dev/provenance/v1"
      }
    },
    "unpackedSize": 1655332
  },
  "version": "2.6.5"
}
npm verbose cwd /Users/stephen/Work/...
npm verbose os Darwin 24.3.0
npm verbose node v20.18.3
npm verbose npm  v11.1.0
npm verbose exit 0
npm info ok

对于 package root url,我看了下,我们自己的 registry 返回的内容跟 npmjs 的一致,这里面都没有 version 字段:

Image

@caohuilin
Copy link
Member

@StephenPCG 不一样吧,我理解路径上面有 latest 的话应该有 version 字段的,路径上面没有的话应该没有 version 字段

@StephenPCG
Copy link
Author

@caohuilin 对,是两个不同的 url。

我一时也没有找到 package version url 的比较权威、比较新的 spec 文档。对于 version url,我试了一下,npmjs、淘宝的镜像,返回的内容是一样的,nexus oss 返回的就不同。而 nexus oss 对于不同的包返回的内容似乎也不同,随便试了几个包,发现对于没有 scope 的包似乎返回的内容都带 version 字段,对于有 scope 的包,返回的内容好像都不带 version 字段(不过因为是手动试的,所以也不确定这是不是规律)。我在网上搜了一圈也没有找到相关的文章。

不知道能否改一下 getNpmPackageInfo() 的实现,如果 registry 返回的内容里没有 version 字段,就尝试用 getNpmPackageInfoWithCommand () 获取一下,而不只是当请求 registry 跑出 error 时才尝试用 command?

@caohuilin
Copy link
Member

嗯嗯 可以的,我去改一下

@caohuilin
Copy link
Member

@StephenPCG web-infra-dev/codesmith#175 看看这样 ok 吗?

@StephenPCG
Copy link
Author

@StephenPCG web-infra-dev/codesmith#175 看看这样 ok 吗?

@caohuilin 目测应该没问题。不过我有没有什么办法可以本地测试一下的?

@caohuilin
Copy link
Member

不好测试,我这里是直接拿的 npx 的版本,得去 npx 的 cache 目录去修改源码

@StephenPCG
Copy link
Author

那就不用测了吧 😂

@StephenPCG
Copy link
Author

我看了下,@modern-js/codesmith 包已经发布了新版本 2.6.6,不过我本地尝试 @modern-js/create 和 modern new 仍然报错,我已经删除了 ~/.npm/_npx/~/Library/Caches/pnpm/dlx/ 目录,也就是删除了本地的 npx、dlx 缓存目录。

看了一下报错时,_npx、dlx 缓存目录中的 codesmith 包仍然是 2.6.5 版本的。是不是因为这个版本是写在 modern.js 里的,需要等待 modern.js 发布新版本才行?

看了下,这两个命令相关的包应该是 packages/toolkit/createpackages/generator/new-action 吧:

Image

@caohuilin
Copy link
Member

caohuilin commented Feb 24, 2025

@StephenPCG 我发了一个 next 版本,你试试 npx @modern-js/create@next my-app --dist-tag next

@lanmingle
Copy link

我也是使用 nexus 搭建,并使用了认证,但是 create 项目不会带默认 .npmrc 的认证 token

@StephenPCG
Copy link
Author

@StephenPCG 我发了一个 next 版本,你试试 npx @modern-js/create@next my-app --dist-tag next

@caohuilin

我试了一下,还是不行:

$ npx @modern-js/create@next my-app --dist-tag next
Need to install the following packages:
@modern-js/[email protected]
Ok to proceed? (y)

🏃  Load Generator.../Users/stephen/.npm/_npx/dc0c274888ad1976/node_modules/@modern-js/create/dist/index.js:45353
        throw new Error(`package ${pkgName}@${pkgVersion} not found in registry`);
              ^

Error: package @modern-js/codesmith-global@latest not found in registry
    at /Users/stephen/.npm/_npx/dc0c274888ad1976/node_modules/@modern-js/create/dist/index.js:45353:15
    at Generator.next (<anonymous>)
    at fulfilled (/Users/stephen/.npm/_npx/dc0c274888ad1976/node_modules/@modern-js/create/dist/index.js:59:24)
    at process.processTicksAndRejections (node:internal/process/task_queues:95:5)

Node.js v20.18.3

# 将上述报错中的 @modern-js/create 路径找到 package.json,查看 version 确实是 next 版本,但依赖的 codesmith 仍然是2.6.5
$ grep -E '(version|codesmith)' /Users/stephen/.npm/_npx/dc0c274888ad1976/node_modules/@modern-js/create/package.json
  "version": "0.0.0-next-20250224105011",
    "@modern-js/codesmith": "2.6.5",
    "@modern-js/codesmith-utils": "2.6.5",

@StephenPCG
Copy link
Author

我也是使用 nexus 搭建,并使用了认证,但是 create 项目不会带默认 .npmrc 的认证 token

@lanmingle

根据我最前面贴的 getNpmPackageInfo() 的代码看,确实不会使用 token。就是很粗暴的用 registryUrl + pkgName + pkgVersion 拼一个 url 出来然后去访问。

看起来 getNpmPackageInfo() 只有当发生 timeout 时才会 fallback 到 getNpmPackageInfoWithCommand(),http请求错误(比如返回401)似乎不会抛出异常。不过等这次他们的 patch 发布之后,你的问题应该也会“意外”的被修复。因为当发生401时,response 里也不会有 version,因此也会 fallback 到 getNpmPackageInfoWithCommand()

不过我比较好奇,为什么明明有 getNpmPackageInfoWithCommand(),却不优先用,而是优先自己构造 registry 的 url 去请求并解析。我看了一下,这个逻辑是在这里面添加的:https://github.com/web-infra-dev/codesmith/pull/170/files

@caohuilin
Copy link
Member

@StephenPCG 那就等一下周四发版吧,这里优先用 url 是因为命令返回的时间比较慢,做了个优化

@lanmingle
Copy link

$ pnpx @modern-js/create@latest --no-need-install
Packages: +1
+
Progress: resolved 1, reused 0, downloaded 1, added 1, done
🏃  Load Generator...  create:error AxiosError: Request failed with status code 400
  create:error     at settle 

...

      redirects: [],
      [Symbol(shapeMode)]: true,
      [Symbol(kCapture)]: false,
      [Symbol(kHeaders)]: {
        server: 'nginx',
        date: 'Tue, 25 Feb 2025 09:15:01 GMT',
        'transfer-encoding': 'chunked',
        connection: 'keep-alive',
        'x-content-type-options': 'nosniff',
        'content-security-policy': 'sandbox allow-forms allow-modals allow-popups allow-presentation allow-scripts allow-top-navigation',
        'x-xss-protection': '1; mode=block',
        'www-authenticate': 'BASIC realm="Sonatype Nexus Repository Manager"'
      },
      [Symbol(kHeadersCount)]: 16,
      [Symbol(kTrailers)]: null,
      [Symbol(kTrailersCount)]: 0
    }
  },
  status: 401
}

本地 .npmrc

$ cat ~/.npmrc 
#registry=https://registry.npmmirror.com
registry=https://nexus.域名.com/repository/npm
//nexus.域名.com/repository/npm-distribution/:_authToken=打码
//nexus.域名.com/repository/npm/:_authToken=打码
//nexus.域名.com/repository/:_authToken=打码
//registry.npmjs.org/:_authToken=打码

@caohuilin 这个 401 问题是否也处理一下?

@caohuilin
Copy link
Member

@lanmingle 这次发版之后应该这个问题会自动修复

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working
Projects
None yet
Development

No branches or pull requests

4 participants