Context
Test runs are currently coupled to the contributor's host platform. Native bindings in node_modules (@rolldown/binding-*, @rollup/rollup-*, @esbuild/*, etc.) are resolved at yarn install time based on the installer's OS/arch. That works fine for a contributor running tests on their own machine — Mac contributors get Mac bindings, Linux contributors get Linux bindings — but breaks down for three real-world cases:
- Agentic tooling running in sandboxed Linux containers (the case that prompted this issue). A sandbox session with the repo mounted can't run
npx vitest because the Mac-installed bindings don't load on Linux ARM64. Attempting an additive install of the missing Linux bindings mid-session is risky: the sandbox has a 45-second-per-command timeout, and a partial install leaves node_modules in a corrupt half-state with dozens of empty package directories, requiring the contributor to rm -rf node_modules && yarn install on their Mac to recover.
- CI pipelines on Linux runners that inherit a contributor's macOS-installed lockfile without re-installing from scratch.
- Remote contributors / new joiners who want a zero-setup "clone and go" environment that matches what everyone else runs.
A standard .devcontainer/devcontainer.json (VS Code) + Dockerfile solves all three. Contributors and agents running inside the container get a fresh Linux install of node_modules with the right bindings; contributors running tests on their host keep doing what they already do.
Task
Add a reproducible Linux dev-container definition that bootstraps Node, installs dependencies fresh for the container's platform, and runs the same yarn test / yarn build the CI runs.
Scope:
.devcontainer/devcontainer.json — VS Code remote-container config. Pinned Node version matching the one in package.json's engines field. Post-create command: yarn install --frozen-lockfile (installs platform-correct native bindings inside the container, separate from the host's node_modules). Mount the workspace at /workspaces/protvista-uniprot so file edits flow back to the host.
Dockerfile (or reuse a Microsoft-published devcontainer base image like mcr.microsoft.com/devcontainers/javascript-node:20). Keep it minimal — Node, yarn, git, and whatever else the test run needs (jsdom dependencies are pure JS, so no extra system packages).
- README section: "Running tests in a devcontainer" with a 3-line reproduction (open VS Code, click "Reopen in Container", run
yarn test). Mention that this is the supported path for agentic tooling and for contributors without a local Node install.
.gitignore: .devcontainer/data (or similar) to keep any container-generated state out of the repo.
- CI (optional): consider adding a second CI job that runs inside the same container image so "it works in CI" and "it works in the devcontainer" mean the same thing. Out of scope for the minimum deliverable, but noted.
Notes:
Isolation of node_modules: use a named volume for the container's node_modules so it doesn't overwrite the host's install. Pattern:
This keeps the host's macOS-bindings node_modules untouched — contributors who usually run tests on their host don't notice the container unless they reopen in it.
The trigger for this issue is one specific pain point, but the payoff is broader: any future sandbox / CI / remote setup inherits a reproducible Linux toolchain. Worth doing even if the immediate agentic-tooling case isn't a priority.
Out of scope: migrating the host-side dev loop to run inside a container by default. This issue is strictly about providing the option, not mandating it.
Context
Test runs are currently coupled to the contributor's host platform. Native bindings in
node_modules(@rolldown/binding-*,@rollup/rollup-*,@esbuild/*, etc.) are resolved atyarn installtime based on the installer's OS/arch. That works fine for a contributor running tests on their own machine — Mac contributors get Mac bindings, Linux contributors get Linux bindings — but breaks down for three real-world cases:npx vitestbecause the Mac-installed bindings don't load on Linux ARM64. Attempting an additive install of the missing Linux bindings mid-session is risky: the sandbox has a 45-second-per-command timeout, and a partial install leavesnode_modulesin a corrupt half-state with dozens of empty package directories, requiring the contributor torm -rf node_modules && yarn installon their Mac to recover.A standard
.devcontainer/devcontainer.json(VS Code) +Dockerfilesolves all three. Contributors and agents running inside the container get a fresh Linux install ofnode_moduleswith the right bindings; contributors running tests on their host keep doing what they already do.Task
Add a reproducible Linux dev-container definition that bootstraps Node, installs dependencies fresh for the container's platform, and runs the same
yarn test/yarn buildthe CI runs.Scope:
.devcontainer/devcontainer.json— VS Code remote-container config. Pinned Node version matching the one inpackage.json'senginesfield. Post-create command:yarn install --frozen-lockfile(installs platform-correct native bindings inside the container, separate from the host'snode_modules). Mount the workspace at/workspaces/protvista-uniprotso file edits flow back to the host.Dockerfile(or reuse a Microsoft-published devcontainer base image likemcr.microsoft.com/devcontainers/javascript-node:20). Keep it minimal — Node, yarn, git, and whatever else the test run needs (jsdom dependencies are pure JS, so no extra system packages).yarn test). Mention that this is the supported path for agentic tooling and for contributors without a local Node install..gitignore:.devcontainer/data(or similar) to keep any container-generated state out of the repo.Notes:
Isolation of
node_modules: use a named volume for the container'snode_modulesso it doesn't overwrite the host's install. Pattern:This keeps the host's macOS-bindings
node_modulesuntouched — contributors who usually run tests on their host don't notice the container unless they reopen in it.The trigger for this issue is one specific pain point, but the payoff is broader: any future sandbox / CI / remote setup inherits a reproducible Linux toolchain. Worth doing even if the immediate agentic-tooling case isn't a priority.
Out of scope: migrating the host-side dev loop to run inside a container by default. This issue is strictly about providing the option, not mandating it.