Skip to content

fix(x-skill): load ora with dynamic import - #1980

Merged
kimteayon merged 3 commits into
ant-design:mainfrom
jay666mnj:fix-x-skill-ora-cjs
Jul 23, 2026
Merged

fix(x-skill): load ora with dynamic import#1980
kimteayon merged 3 commits into
ant-design:mainfrom
jay666mnj:fix-x-skill-ora-cjs

Conversation

@jay666mnj

@jay666mnj jay666mnj commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

🤔 This is a ...

  • 🐞 Bug fix

🔗 Related Issues

Fixes #1971

💡 Background and Solution

@ant-design/x-skill builds a CommonJS CLI entry, but ora@9 is ESM-only. The current top-level static import is transformed into require('ora') in the CJS output, causing ERR_REQUIRE_ESM when running the CLI.

This PR removes the top-level ora import and loads it only when needed through native dynamic import, so the CJS CLI can start normally and the spinner path can still use ora.

Verified with:

  • npm run tsc --workspace packages/x-skill
  • npm run lint --workspace packages/x-skill
  • npm run compile --workspace packages/x-skill
  • node packages\x-skill\bin\index.js --help
  • node packages\x-skill\bin\index.js --list-versions

📝 Change Log

Language Changelog
🇺🇸 English Fix x-skill CLI startup failure caused by loading ESM-only ora from CommonJS output.
🇨🇳 Chinese 修复 x-skill CLI 在 CommonJS 产物中加载 ESM-only ora 导致的启动失败问题。

Summary by CodeRabbit

  • Bug Fixes
    • 修复在部分环境中无法加载版本列表的问题。
    • 改进版本列表加载时的加载指示行为:即使失败也会正确停止加载提示。
    • 提升与现代模块格式的兼容性,确保依赖加载与界面反馈一致。

@dosubot dosubot Bot added bug Something isn't working javascript Pull requests that update Javascript code labels Jul 16, 2026
@coderabbitai

coderabbitai Bot commented Jul 16, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 6cfb4255-ca81-4510-8629-9c4410033056

📥 Commits

Reviewing files that changed from the base of the PR and between 630d565 and 00d8559.

📒 Files selected for processing (1)
  • packages/x-skill/src/index.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • packages/x-skill/src/index.ts

📝 Walkthrough

Walkthrough

ora 改为运行时动态加载,并在 listVersions() 中使用其默认导出;版本获取失败时也会停止已启动的 spinner。

Changes

ora CJS 兼容性

Layer / File(s) Summary
动态加载 ora 并完善版本列表流程
packages/x-skill/src/index.ts
移除顶层 ora 导入,新增带缓存的 loadOra(),在 listVersions() 中动态初始化 spinner,并在异常分支停止 spinner。

Estimated code review effort: 2 (Simple) | ~10 minutes

Poem

小兔轻敲代码门,
ora 动态入运行。
spinner 成功会停转,
出错也不再空等。
CJS 欢快向前奔!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 标题准确概括了本次改动:通过动态导入加载 ora。
Linked Issues check ✅ Passed 已按 #1971 的要求避免在 CJS 中静态 require ESM-only 的 ora,改为按需动态导入。
Out of Scope Changes check ✅ Passed 未见明显超出 issue 目标的改动,spinner 关闭修复属于同一范围内的健壮性调整。
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@gemini-code-assist gemini-code-assist Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review

This pull request refactors the x-skill package to dynamically import the ESM-only ora library, ensuring compatibility with CommonJS builds. The feedback suggests optimizing the dynamic import helper by caching the module and simplifying the loader function. Additionally, the reviewer points out a bug where the spinner is not stopped if an error occurs during version listing, and provides a robust refactoring suggestion to handle errors gracefully.

Important

The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.

Comment on lines +12 to +22
type Ora = typeof import('ora').default;

async function loadOra(): Promise<Ora> {
// Keep native dynamic import in the CJS build because ora is ESM-only.
const loader = new Function('specifier', 'return import(specifier)') as (
specifier: string,
) => Promise<typeof import('ora')>;

const { default: ora } = await loader('ora');
return ora;
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

The dynamic import helper can be simplified by removing the unused specifier parameter from the dynamic function constructor. Additionally, caching the loaded ora module prevents redundant dynamic imports and function recreations if loadOra is called multiple times in the future. Renaming the type to OraFactory also avoids potential confusion with the Ora spinner instance type.

type OraFactory = typeof import('ora').default;

let oraCache: OraFactory | null = null;

async function loadOra(): Promise<OraFactory> {
  if (oraCache) {
    return oraCache;
  }
  // Keep native dynamic import in the CJS build because ora is ESM-only.
  const loader = new Function('return import("ora")') as () => Promise<{ default: OraFactory }>;
  const { default: ora } = await loader();
  oraCache = ora;
  return ora;
}


async listVersions(): Promise<void> {
try {
const ora = await loadOra();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

medium

If this.skillLoader.listVersions() throws an error, spinner.stop() is never called because the execution immediately jumps to the catch block. This can leave the spinner running indefinitely or result in garbled console output when the error message is printed.

Consider refactoring the method to ensure the spinner is stopped in case of an error:

  async listVersions(): Promise<void> {
    let spinner: any;
    try {
      const ora = await loadOra();
      spinner = ora(
        this.helpManager.colorize(getMessage('fetchingVersions', this.language), 'cyan'),
      ).start();
      const versions = await this.skillLoader.listVersions();
      spinner.stop();

      if (versions.length === 0) {
        console.log(
          `${this.helpManager.colorize(getMessage('noVersionsFound', this.language), 'yellow')}`,
        );
        return;
      }

      console.log(
        `${this.helpManager.colorize(getMessage('availableVersions', this.language), 'green')}`,
      );
      versions.forEach((version, index) => {
        const marker = index === 0 ? getMessage('latestMarker', this.language) : '';
        console.log(`  ${this.helpManager.colorize(version, 'yellow')}${marker}`);
      });
    } catch (error) {
      if (spinner) {
        spinner.stop();
      }
      console.error(
        `${this.helpManager.colorize(getMessage('error', this.language), 'red')} ${(error as Error).message}`,
      );
    }
  }

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
packages/x-skill/src/index.ts (1)

205-210: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win

确保在发生错误时停止 spinner。

如果 this.skillLoader.listVersions() 抛出异常,代码会直接跳入 catch 块,导致 spinner.stop() 被跳过。虽然当前逻辑下遇到错误进程会退出,但在退出前,未停止的 spinner 可能会干扰或覆盖终端中的错误信息输出。建议将 spinner 的引用提升,并在发生异常时确保将其停止。

💡 修复建议
   async listVersions(): Promise<void> {
+    let spinner: ReturnType<Ora> | undefined;
     try {
       const ora = await loadOra();
-      const spinner = ora(
+      spinner = ora(
         this.helpManager.colorize(getMessage('fetchingVersions', this.language), 'cyan'),
       ).start();
       const versions = await this.skillLoader.listVersions();
       spinner.stop();

然后在下方的 catch 块中调用停止方法:

     } catch (error) {
+      spinner?.stop();
       console.error(
         `${this.helpManager.colorize(getMessage('error', this.language), 'red')} ${(error as Error).message}`,
       );
     }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@packages/x-skill/src/index.ts` around lines 205 - 210, 在包含 `loadOra`、spinner
创建和 `this.skillLoader.listVersions()` 的流程中,将 spinner 引用提升到 try 块外,并在 catch
块中确保已创建的 spinner 被停止;保留成功路径现有的停止逻辑,避免异常时终端输出被活动 spinner 干扰。
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Outside diff comments:
In `@packages/x-skill/src/index.ts`:
- Around line 205-210: 在包含 `loadOra`、spinner 创建和
`this.skillLoader.listVersions()` 的流程中,将 spinner 引用提升到 try 块外,并在 catch 块中确保已创建的
spinner 被停止;保留成功路径现有的停止逻辑,避免异常时终端输出被活动 spinner 干扰。

ℹ️ Review info
⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 8b8048f1-ba96-47a1-aa71-e8a104338366

📥 Commits

Reviewing files that changed from the base of the PR and between 17db20b and 630d565.

📒 Files selected for processing (1)
  • packages/x-skill/src/index.ts

@dosubot dosubot Bot added the lgtm This PR has been approved by a maintainer label Jul 23, 2026
@kimteayon
kimteayon merged commit f17d4ec into ant-design:main Jul 23, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working javascript Pull requests that update Javascript code lgtm This PR has been approved by a maintainer

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[x-skill] CLI crashes on every command: ERR_REQUIRE_ESM — CJS bin requires ESM-only ora ^9

2 participants