Skip to content

feat!: migrate action to native ESM and upgrade @actions/* to ESM majors#210

Open
dhensby wants to merge 3 commits intotediousjs:masterfrom
dhensby:esm-migration
Open

feat!: migrate action to native ESM and upgrade @actions/* to ESM majors#210
dhensby wants to merge 3 commits intotediousjs:masterfrom
dhensby:esm-migration

Conversation

@dhensby
Copy link
Copy Markdown
Collaborator

@dhensby dhensby commented Apr 21, 2026

Migrates the action to native ESM on Node 24 so it can consume the ESM-only majors of the @actions/* toolkit (superseding Dependabot #206).

Commits

  1. feat!: rewrite as an ESM module

    • "type": "module", tsconfig flipped to nodenext with allowImportingTsExtensions + rewriteRelativeImportExtensions; all relative imports use explicit .ts extensions.
    • Bundler swapped from @vercel/ncc to Rollup (single-file ESM bundle at lib/main/index.js).
    • Test harness swapped from mocha + ts-node + chai + sinon + sinon-chai + nyc/c8 to Node's built-in node:test + node:assert/strict + --experimental-test-module-mocks + --experimental-test-coverage. No third-party test runner, assertion library, mocking library, or coverage tool remains.
    • src/actions.ts re-export shim (originally introduced so sinon could stub toolkit calls) is gone — modules use idiomatic import * as core from '@actions/core' etc., restoring Rollup tree-shaking.
    • Test files mock dependencies at the module-resolution layer via mock.module() rather than rebinding namespace imports.
  2. chore(deps): upgrade @actions/* toolkit to ESM majors

    • @actions/core 1→3, @actions/exec 1→3, @actions/glob 0.5→0.6, @actions/http-client 2→4, @actions/io 1→3, @actions/tool-cache 2→4.
    • No source changes required — the public surface we use is unchanged across these majors, and tests mock at the module-resolution layer.

Breaking changes

  • The action now requires Node 24 (unchanged in practice; action.yml already pinned node24).
  • Internal module layout is ESM-only; anyone importing from the compiled bundle directly (unsupported) will need to adapt.

Closes #206.

@dhensby dhensby changed the title esm migration test title update Apr 21, 2026
@dhensby dhensby changed the title test title update feat!: migrate action to native ESM and upgrade @actions/* to ESM majors Apr 21, 2026
dhensby and others added 2 commits April 22, 2026 02:17
Migrate the action from CommonJS to native ESM so that it can consume the
ESM-only majors of the `@actions/*` toolkit packages (and any future ESM-only
dependencies) without a transpile-to-CJS step.

Tooling changes:

- Set `"type": "module"` and emit ESM throughout.
- Replace `@vercel/ncc` (which cannot emit ESM) with Rollup
  (`@rollup/plugin-typescript`, `-node-resolve`, `-commonjs`, `-json`,
  `-terser`). Output is still `lib/main/index.js` so `action.yml` is unchanged.
- Drop `ts-node`/`tsx` in favour of Node 24's native TypeScript type-stripping
  (`.ts` files execute directly under `node`).
- Replace the Mocha + Chai + Sinon + sinon-chai test stack with Node's
  built-in `node:test` runner (using `--experimental-test-module-mocks` and
  `node:assert/strict`). Replace `nyc`/`c8` with Node's built-in
  `--experimental-test-coverage`. `.mocharc.json` and `.nycrc.json` are
  removed.
- Switch relative imports throughout src/, test/, and misc/ to use `.ts`
  extensions and set `allowImportingTsExtensions` +
  `rewriteRelativeImportExtensions` in `tsconfig.json` so both Node and Rollup
  resolve them directly.
- Update `misc/generate-docs.ts` to ESM (JSON import attribute,
  `import.meta.url` in place of `__dirname`).

Source-code style:

- Idiomatic ESM imports throughout: `import * as core from '@actions/core'`,
  named imports where appropriate, default-function exports for modules with a
  single primary export (e.g. `install-native-client.ts`). No
  default-object/re-export wrappers are needed for test stubbing; tests mock
  at the module-resolution layer using `node:test`'s `mock.module()`.

Docs:

- Update `.github/copilot-instructions.md` to describe the new toolchain
  (Rollup, Node 24 native TS, `node:test` + `mock.module()`, built-in
  coverage).

BREAKING CHANGE: The action is now an ESM module and targets Node 24.
Consumers pinning the action via commit SHA will need to re-pin; consumers
using `@v3` or later will continue to work unchanged. Local development now
requires Node 24+ (previously Node 20+).

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Bump the `@actions/*` runtime dependencies to their ESM-only major releases
now that the action itself runs as a native ESM module:

- `@actions/core` 1 → 3
- `@actions/exec` 1 → 3
- `@actions/glob` 0.5 → 0.6
- `@actions/http-client` 2 → 4
- `@actions/io` 1 → 3
- `@actions/tool-cache` 2 → 4

No source changes are required for this bump: the public surface we use
(`core.getInput`, `core.platform`, `exec.exec`, `glob.create`,
`HttpClient#get`, `io.mv`, `tc.downloadTool`/`cacheFile`/`cacheDir`/`find`)
is unchanged across these majors, and tests mock the packages at the
module-resolution layer via `node:test`'s `mock.module()`.

Supersedes Dependabot tediousjs#206.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
tslib is an optional peer of @rollup/plugin-typescript, only needed when
TypeScript emits helper imports (e.g. with importHelpers: true or older
down-levelling targets). We don't set importHelpers and target modern
Node via nodenext, so no tslib references end up in the bundle.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant