Skip to content

fix(gha): bundle action with esbuild - #454

Merged
macalbert merged 11 commits into
mainfrom
fix/typescript-7-esbuild-bundle
Jul 23, 2026
Merged

fix(gha): bundle action with esbuild#454
macalbert merged 11 commits into
mainfrom
fix/typescript-7-esbuild-bundle

Conversation

@macalbert

@macalbert macalbert commented Jul 23, 2026

Copy link
Copy Markdown
Owner

Summary

Updates TypeScript to 7.0.2 and replaces the incompatible GitHub Action build tooling.

The action remains a single committed bundle, while TypeScript continues to type-check sources and emit decorator metadata before esbuild packages the compiled output.

Changes

  • Replace @vercel/ncc with esbuild for the GitHub Action bundle.
  • Replace ts-node with tsx in direct TypeScript execution paths.
  • Regenerate github-action/dist/index.js and update the dependency lockfile.
  • Document the bundler decision and update related contributor guidance.

Testing

  • pnpm build:gha, pnpm verify:gha, and the GitHub Action bundle smoke check
  • pnpm lint, the website build, the CDK build, and focused GHA and website tests
  • pnpm test -- Docker is unavailable locally for Testcontainers acceptance tests

Related

#422

Summary by CodeRabbit

  • Changed

    • GitHub Action builds now use esbuild to produce a single optimized, minified bundle.
    • Development and packaging commands now use tsx instead of ts-node.
    • Updated CDK and local installation workflows to reflect the new execution commands.
  • Documentation

    • Added architecture guidance and release notes covering the updated build and development workflows.
    • Refreshed setup and publishing documentation.

dependabot Bot and others added 11 commits July 22, 2026 08:08
Bumps [@aws-sdk/client-ssm](https://github.com/aws/aws-sdk-js-v3/tree/HEAD/clients/client-ssm) from 3.1084.0 to 3.1092.0.
- [Release notes](https://github.com/aws/aws-sdk-js-v3/releases)
- [Changelog](https://github.com/aws/aws-sdk-js-v3/blob/main/clients/client-ssm/CHANGELOG.md)
- [Commits](https://github.com/aws/aws-sdk-js-v3/commits/v3.1092.0/clients/client-ssm)

---
updated-dependencies:
- dependency-name: "@aws-sdk/client-ssm"
  dependency-version: 3.1092.0
  dependency-type: direct:development
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
Bumps [typescript](https://github.com/microsoft/TypeScript) from 6.0.3 to 7.0.2.
- [Release notes](https://github.com/microsoft/TypeScript/releases)
- [Commits](https://github.com/microsoft/TypeScript/commits)

---
updated-dependencies:
- dependency-name: typescript
  dependency-version: 7.0.2
  dependency-type: direct:production
  update-type: version-update:semver-major
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
…ks/nodejs/aws-sdk/client-ssm-3.1092.0' into macalbert-fix-dependabot-pipelines
…pt-7.0.2' into macalbert-fix-dependabot-pipelines
TypeScript 7 removes the compiler API required by ncc and ts-node.

Compile first, bundle with esbuild, and use tsx for scripts that run TypeScript directly.

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
Copilot AI review requested due to automatic review settings July 23, 2026 07:18
@github-actions github-actions Bot added documentation Improvements or additions to documentation npm Pull requests that update npm/pnpm packages iac Infrastructure as Code (AWS CDK) skills Changes to .github/skills guidance e2e End-to-end tests (Playwright) size/XL Very large change — 400+ lines / 25+ files; should be split shell Shell / PowerShell scripts bug Something isn't working labels Jul 23, 2026
@gemini-code-assist

Copy link
Copy Markdown
Contributor

Caution

The consumer version of Gemini Code Assist on GitHub has been sunset. All code review activity has officially ceased.

@coderabbitai

coderabbitai Bot commented Jul 23, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

The PR documents and implements an esbuild-based GitHub Action bundle, updates related ADR and changelog entries, and replaces ts-node-based TypeScript execution with tsx in packaging, E2E, and CDK workflows.

Changes

GitHub Action and TypeScript tooling

Layer / File(s) Summary
GitHub Action esbuild bundling
docs/adr/0006-monorepo-structure.md, docs/adr/0010-github-action-bundler.md, scripts/build-github-action.mjs, scripts/README.md
Documents and implements a minified ES module bundle targeting Node.js 22, with createRequire support and output at github-action/dist/index.js.
tsx execution migration
scripts/pack-and-install.ts, e2e/cli.test.ts, src/iac/cdk.json, src/iac/package.json, scripts/README.md, docs/changelogs/gha.md
Replaces ts-node invocation and dependency usage with tsx for packaging, E2E setup, CDK execution, and local development documentation.

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

Possibly related PRs

  • macalbert/envilder#38: Updates documentation around the pack-and-install script in the same documentation surface.

Suggested labels: github-actions, dependencies

Suggested reviewers: copilot

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: switching the GitHub Action bundle to esbuild.
Description check ✅ Passed The description covers the change, testing, and related issue, but it omits some template sections like type of change, checklist, and reviewer notes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/typescript-7-esbuild-bundle

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 Checkov (3.3.8)
src/iac/cdk.json

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'

src/iac/package.json

Traceback (most recent call last):
File "/usr/local/bin/checkov", line 2, in
from checkov.main import Checkov
ModuleNotFoundError: No module named 'checkov'


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.

@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.

Actionable comments posted: 1

🤖 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.

Inline comments:
In `@scripts/build-github-action.mjs`:
- Around line 1-14: Update the GitHub Actions workflow that invokes the
composite action to add an actions/setup-node step with node-version set to 22
before the node command runs github-action/dist/index.js. Keep the existing
esbuild target in the build script unchanged; the runtime version must be pinned
in the workflow execution path.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 0c93addb-bbd8-4c7e-99ed-34f85fe40d60

📥 Commits

Reviewing files that changed from the base of the PR and between 3f27ac5 and 8558eb4.

⛔ Files ignored due to path filters (7)
  • .github/copilot-instructions.md is excluded by none and included by none
  • .github/skills/common-security/SKILL.md is excluded by none and included by none
  • CONTRIBUTING.md is excluded by none and included by none
  • github-action/dist/index.js is excluded by !**/dist/**, !github-action/dist/** and included by none
  • package.json is excluded by none and included by none
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml, !pnpm-lock.yaml and included by none
  • pnpm-workspace.yaml is excluded by none and included by none
📒 Files selected for processing (9)
  • docs/adr/0006-monorepo-structure.md
  • docs/adr/0010-github-action-bundler.md
  • docs/changelogs/gha.md
  • e2e/cli.test.ts
  • scripts/README.md
  • scripts/build-github-action.mjs
  • scripts/pack-and-install.ts
  • src/iac/cdk.json
  • src/iac/package.json

Comment on lines +1 to +14
import { build } from 'esbuild';

await build({
entryPoints: ['lib/envilder/apps/gha/entry/Index.js'],
bundle: true,
platform: 'node',
format: 'esm',
target: 'node22',
minify: true,
outfile: 'github-action/dist/index.js',
banner: {
js: "import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);",
},
});

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.

🩺 Stability & Availability | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

files="$(fd -a -t f . | rg '(^|/)(action\.ya?ml|package\.json)$')"
printf '%s\n' "$files"
printf '%s\n' "$files" | xargs -r rg -n '"type"\s*:|using:|main:'

Repository: macalbert/envilder

Length of output: 1084


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '--- github-action/action.yml ---\n'
sed -n '1,80p' github-action/action.yml

printf '\n--- scripts/build-github-action.mjs ---\n'
sed -n '1,80p' scripts/build-github-action.mjs

printf '\n--- root package.json relevant fields ---\n'
python3 - <<'PY'
import json
from pathlib import Path
p=Path('package.json')
data=json.loads(p.read_text())
for key in ['name','version','type','engines','scripts','devDependencies','dependencies']:
    if key in data:
        print(f'{key}: {json.dumps(data[key], indent=2)}')
PY

printf '\n--- other action files ---\n'
fd -a -t f '^\.(github|devcontainer|scripts)/?|action\.(ya?ml|json)$' github-action .github .devcontainer . 2>/dev/null | sed -n '1,80p'

Repository: macalbert/envilder

Length of output: 247


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

printf '%s\n' '--- github-action/action.yml ---'
sed -n '1,80p' github-action/action.yml

printf '%s\n' ''
printf '%s\n' '--- scripts/build-github-action.mjs ---'
sed -n '1,80p' scripts/build-github-action.mjs

printf '%s\n' ''
printf '%s\n' '--- root package.json relevant fields ---'
python3 - <<'PY'
import json
from pathlib import Path
p=Path('package.json')
data=json.loads(p.read_text())
for key in ['name','version','type','engines','scripts','devDependencies','dependencies']:
    if key in data:
        print(f'{key}: {json.dumps(data[key], indent=2)}')
PY

printf '%s\n' ''
printf '%s\n' '--- action/package boundary files ---'
fd -a -t f '^\.(github|devcontainer|scripts)/?|action\.(ya?ml|json)$' . | rg '(^|/)github-action/|^\.github/|^\.devcontainer/|(^|/)package\.json$' || true

Repository: macalbert/envilder

Length of output: 4829


🌐 Web query:

GitHub Actions composite action step shell node runner image Node version GHA Node 22

💡 Result:

GitHub Actions composite actions do not have a dedicated runs: using: 'node22' runtime configuration. The 'runs: using' syntax is specifically for JavaScript actions (which execute code directly), whereas composite actions use 'runs: using: "composite"' and consist of a sequence of steps [1][2][3][4]. To use Node.js 22 within a composite action, you must explicitly set up the Node.js environment as a step within your action using the actions/setup-node action [4][5]. Example implementation: runs: using: "composite" steps: - name: Setup Node.js 22 uses: actions/setup-node@v6 with: node-version: '22' - name: Run script shell: bash run: node your-script.js Key considerations: 1. Shell Requirement: In composite actions, every 'run' step must explicitly define a 'shell' (e.g., 'shell: bash'), as there is no default shell provided [2][4]. 2. Node.js Environment: As of July 2026, Node.js 22 is a supported and common version on GitHub Actions runners, with many runners having transitioned to it as a default [6]. You can verify the availability and manage specific versions via actions/setup-node [7][8]. 3. JavaScript Actions vs. Composite: If you are creating a 'JavaScript action' (using 'runs: using: nodeXX'), you are limited to the specific Node versions supported by the runner's underlying action engine (often node20 or node24) [9][10]. Composite actions provide more flexibility because they execute steps in the runner's shell environment [2][4].

Citations:


🌐 Web query:

GitHub Actions composite run steps node runtime default runner node20 node command commonjs esm

💡 Result:

In GitHub Actions, composite actions and JavaScript actions are distinct types with different configurations [1]. Composite Actions: Composite actions use using: composite in their action.yml file [2][3]. They do not have a built-in Node.js runtime environment; instead, they define a sequence of steps that run using specified shells (e.g., bash, powershell) [2][4][3]. To use Node.js within a composite action, you must explicitly include a step that installs it, typically using actions/setup-node [5][6][7]. Because composite actions rely on the shell environment, they are not directly affected by the runs.using node version configuration, but rather by the Node.js version installed in the runner's path [5][3]. JavaScript Actions: JavaScript actions use runs.using (e.g., node20, node24) to specify the runtime [1][8]. As of July 2026, Node24 is the standard runtime, with Node20 undergoing deprecation [8]. JavaScript actions execute an entry JavaScript file defined in the main field [1]. CommonJS vs. ESM: GitHub Actions runners support both CommonJS (CJS) and ECMAScript Modules (ESM) [7][9]. - For JavaScript actions, your build tool (like ncc) can be configured to produce either format, though you must ensure the main file is compatible with the specified runtime version [9]. - For composite actions, because you are executing scripts or commands (e.g., node index.js) via a shell, you can use ESM by either setting "type": "module" in your package.json or by using the .mjs extension [7][9]. If using actions/github-script within a composite action, you can load ESM modules dynamically using the await import() syntax [7][10][9]. Key Technical Notes: - The shell attribute is required for every run step in a composite action [2][4]. - Node20 reached its end-of-life in April 2026, and runners began defaulting to Node24 in June 2026 [8]. To continue using older runtimes temporarily, users may need to set environment variables like ACTIONS_ALLOW_USE_UNSECURE_NODE_VERSION=true [8][11]. - steps are not valid for node20 or node24 runtimes; they are specific to using: composite [1].

Citations:


🌐 Web query:

GitHub Actions node command shell Bash ESM files import module .js CommonJS detection

💡 Result:

When executing Node.js files within a GitHub Actions Bash shell, Node.js uses standard detection rules to determine whether a file should be treated as an ECMAScript Module (ESM) or CommonJS (CJS) [1][2]. Detection Rules Node.js identifies the module format based on the following hierarchy [1][3]: 1. Explicit Markers: - File Extension: Files ending in.mjs are always treated as ESM; files ending in.cjs are always treated as CJS [1][2][3]. - Package Configuration: If the nearest parent package.json contains a "type" field set to "module", all.js files in that directory and its subdirectories are treated as ESM. If the field is set to "commonjs" or is missing,.js files are treated as CJS [1][2][3]. 2. Ambiguous Detection: - For.js files without an explicit "type" setting in a package.json, Node.js attempts to parse the code as CommonJS first [2]. If the parser encounters ESM-specific syntax (e.g., import, export, import.meta) that is invalid in CommonJS, Node.js will treat the file as an ESM module [1][2][4]. GitHub Actions Considerations - Running Scripts: You can execute Node.js scripts in your workflow using the run keyword (e.g., run: node script.js) [5][6]. Ensure your environment is configured by using the actions/setup-node action to specify the desired Node.js version [7][5]. - github-script Action: The official actions/github-script action historically relied on CommonJS, which limited direct ESM imports [8][9]. For modern workflows requiring ESM, it is recommended to either: - Use dynamic import within your script: await import('${{ github.workspace }}/your-script.js') [10][9]. - Bundle your code (e.g., using vercel/ncc) to produce a single, compatible CJS file [8]. - Use standard node commands in a Bash step rather than the actions/github-script wrapper if you require full native ESM support for your project files [6]. Note that require can only load CommonJS modules [9]. If you are working in an ESM-defined context, you must use import statements [1][9].

Citations:


Pin the GitHub Actions Node runtime explicitly.

The composite action only calls node "${{ github.action_path }}/dist/index.js"; the runner image’s Node version defaults to what the workflow matrix specifies, not the bundled target: 'node22'. Add an actions/setup-node step with node-version: '22' before running this action so the ESM bundle gets a compatible runtime.

🤖 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 `@scripts/build-github-action.mjs` around lines 1 - 14, Update the GitHub
Actions workflow that invokes the composite action to add an actions/setup-node
step with node-version set to 22 before the node command runs
github-action/dist/index.js. Keep the existing esbuild target in the build
script unchanged; the runtime version must be pinned in the workflow execution
path.

Copilot AI 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.

Pull request overview

This PR updates the GitHub Action build pipeline to support TypeScript 7 by replacing @vercel/ncc/ts-node with an esbuild bundling step plus tsx for TypeScript script execution, while keeping the action distributed as a single committed bundle.

Changes:

  • Replace GHA bundling from ncc build to tsc output + esbuild bundling (scripts/build-github-action.mjs, package.json).
  • Replace ts-node execution with tsx across CDK, local install tooling, and E2E setup (src/iac/*, scripts/*, e2e/cli.test.ts).
  • Update docs/ADRs/changelogs to reflect the new bundler/tooling and commit the updated lockfile/catalog changes.

Reviewed changes

Copilot reviewed 14 out of 16 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/iac/package.json Swap IaC dev script runner from ts-node to tsx.
src/iac/cdk.json Run CDK app via pnpm exec tsx instead of npx ts-node.
scripts/README.md Update contributor docs to reference esbuild + tsx.
scripts/pack-and-install.ts Update script shebang to tsx runner.
scripts/build-github-action.mjs New esbuild bundling script for github-action/dist/index.js.
pnpm-workspace.yaml Catalog updates: TypeScript 7 + tsx, remove ts-node.
pnpm-lock.yaml Lockfile updates for TypeScript 7 / tsx / esbuild and removals.
package.json Wire build:gha to esbuild script; add esbuild; swap local:install to tsx.
e2e/cli.test.ts Use pnpm exec tsx for pack-and-install during E2E setup.
docs/changelogs/gha.md Add Unreleased changelog entry documenting bundler/tooling changes.
docs/adr/0010-github-action-bundler.md New ADR documenting the esbuild bundler decision.
docs/adr/0006-monorepo-structure.md Update monorepo ADR to state GHA uses esbuild bundling.
CONTRIBUTING.md Update contributor commands list for esbuild-based build:gha.
.github/skills/common-security/SKILL.md Update security guidance to reflect esbuild bundling.
.github/copilot-instructions.md Update Copilot instructions to reflect esbuild bundling.
Files not reviewed (1)
  • pnpm-lock.yaml: Generated file
Comments suppressed due to low confidence (1)

docs/adr/0010-github-action-bundler.md:43

  • The reconsideration trigger mentions a Node.js 22 runtime requirement, but the action currently runs using the runner-provided node without enforcing a specific version. This should be phrased in terms of the actual runtime contract (either enforce Node 22 in the action, or describe the supported Node baseline).
Reconsider if esbuild no longer bundles a GitHub Action dependency correctly,
or if GitHub Action runtime requirements change from Node.js 22.

Comment on lines +6 to +13
platform: 'node',
format: 'esm',
target: 'node22',
minify: true,
outfile: 'github-action/dist/index.js',
banner: {
js: "import { createRequire } from 'node:module'; const require = createRequire(import.meta.url);",
},
Comment on lines +18 to +21
The `build:gha` command compiles the TypeScript source first, preserving
decorator metadata required by Inversify. The esbuild configuration emits an
ES module targeted at Node.js 22 and provides `createRequire` for dependencies
that dynamically load Node.js built-ins.
@macalbert
macalbert merged commit 5f4e6ab into main Jul 23, 2026
30 of 31 checks passed
@macalbert
macalbert deleted the fix/typescript-7-esbuild-bundle branch July 23, 2026 07:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Something isn't working documentation Improvements or additions to documentation e2e End-to-end tests (Playwright) iac Infrastructure as Code (AWS CDK) npm Pull requests that update npm/pnpm packages shell Shell / PowerShell scripts size/XL Very large change — 400+ lines / 25+ files; should be split skills Changes to .github/skills guidance

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants