feat: ship npm artifacts alongside pnpm in the app template (2/3) - #598
atilafassina wants to merge 9 commits into
Conversation
Flip the `databricks apps init` app template from npm to pnpm as the default package manager so scaffolds deploy to Databricks Apps with native deps intact. - ship template/pnpm-lock.yaml (pnpm@11.0.8) plus a single-app pnpm-workspace.yaml carrying the migrated overrides, allowBuilds (esbuild, @ast-grep/napi, ...) and supportedArchitectures for linux/x64/glibc, so @ast-grep/napi-linux-x64-gnu materializes on install - set packageManager to pnpm@11.0.8 and make every script sibling call an explicit `pnpm run <script>` (pnpm 11 shadows bare `pnpm <script>`) - enable pre/post scripts via template/.npmrc so prebuild (typegen) fires - render app.yaml `command: ['pnpm', 'run', 'start']`; template README to pnpm - validate template/pnpm-lock.yaml in the leak validator (format-dispatch by filename) and drop the npm package-lock.json (returns in Phase 2) Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: Atila Fassina <atila@fassina.eu>
Guard the deploy shape the pnpm-first template depends on: a fresh `pnpm install --frozen-lockfile` on the scaffolded app must materialize the linux native dep and run its build. - tools/smoke-test-template.ts scaffolds the committed template into .smoke-test/app (renders the mustache placeholders, no tarball rewrite) so the frozen install runs against the committed pnpm-lock - new `template-deploy-shape` CI job installs --frozen-lockfile on linux-x64, asserts @ast-grep/napi-linux-x64-gnu materialized, and runs build:client/build:server (typegen/boot need a live workspace, so are out of CI scope) - gitignore the .smoke-test scratch dir and exclude it from oxlint/oxfmt This closes the long-standing deploy-shape CI gap; it caught the allowBuilds mis-encoding fixed in the previous commit. Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: Atila Fassina <atila@fassina.eu>
Signed-off-by: Atila Fassina <atila@fassina.eu> Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: Atila Fassina <atila@fassina.eu> Co-authored-by: Isaac <no-reply@databricks.com>
Signed-off-by: Atila Fassina <atila@fassina.eu> Co-authored-by: Isaac <no-reply@databricks.com>
Bring back first-class npm support in the pnpm-first app template so a scaffold selected as npm (`databricks apps init --package-manager npm`) installs and deploys with native deps intact. The committed default stays pnpm-shaped. - ship template/package-lock.json (lockfileVersion 3, public registry only) - re-add top-level npm `overrides` in template/package.json, mirroring the pnpm-workspace.yaml overrides - pin @ast-grep/napi-linux-x64-gnu as a root optionalDependency (os/cpu guarded by the package itself) as a defensive edge against npm/cli#4828 style lock regeneration dropping the linux binary; regenerate pnpm-lock.yaml for the new edge - check-template-deps: fail when the npm and pnpm override placements drift, or when the linux pin is missing or skews from @ast-grep/napi Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: Atila Fassina <atila@fassina.eu>
- check-template-lock-registry validates template/pnpm-lock.yaml and template/package-lock.json by default, fail-closed if either is missing - parse pnpm-lock.yaml with `yaml` instead of a URL regex so tarball, git, directory and missing resolutions fail closed, at parity with the npm handler; the npm handler now fails on non-root/link/bundled entries with no `resolved`; each .npmrc is checked once - add template-deploy-shape-npm: bare `npm install` from the committed lock on linux-x64, assert @ast-grep/napi-linux-x64-gnu materializes and loads, build client and server - load @ast-grep/napi at runtime in the pnpm deploy-shape job too - smoke-test-template: --package-manager selects which lock the scaffold keeps - pr-template-artifact regenerates both locks against the PR tarballs (npm install, then pnpm install --lockfile-only) and rewrites and validates both before zipping, so the artifact no longer ships a stale pnpm-lock.yaml Co-authored-by: Isaac <no-reply@databricks.com> Signed-off-by: Atila Fassina <atila@fassina.eu>
Signed-off-by: Atila Fassina <atila@fassina.eu>
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Unresolved lockfile validation, release-artifact regeneration, and Windows path portability issues remain.
Get a fresh assessment by requesting another Copilot review.
Review effort: Lite
Findings: 1
Open (3)
What changed in this PR
Restores npm support alongside pnpm for the app template, including dual lockfiles, native dependency handling, artifact generation, and CI smoke coverage.
Changes:
- Adds npm overrides, lockfile support, and native dependency pinning.
- Expands lockfile validation and package-manager smoke tests.
- Updates template generation, artifacts, documentation, and CI.
| File | Summary |
|---|---|
vitest.config.ts |
Adds tooling test coverage. |
tools/template-smoke-runner.ts |
Runs npm and pnpm install, build, and runtime checks. |
tools/template-artifacts.ts |
Manages package-manager artifacts. |
tools/template-artifacts.test.ts |
Tests artifact behavior. |
tools/smoke-test-template.ts |
Adds package-manager smoke options; Windows path portability issue remains. |
tools/prepare-template-artifact.ts |
Prepares release artifacts; dual-lock regeneration and registry rewriting need correction. |
tools/generate-app-templates.ts |
Preserves package-manager files in generated templates. |
tools/check-template-lock-registry.ts |
Validates npm and pnpm registries; malformed or missing package maps can currently pass. |
tools/check-template-deps.ts |
Checks override and native dependency parity. |
tools/check-template-artifact.ts |
Validates bundled dependency resolutions. |
template/README.md.tmpl |
Documents package-manager commands. |
template/pnpm-workspace.yaml |
Updates pnpm configuration. |
template/pnpm-lock.yaml |
Records native dependency resolution. |
template/package.json |
Adds npm overrides and native optional dependency pinning. |
template/app.yaml.tmpl |
Selects package-manager startup behavior. |
pnpm-lock.yaml |
Locks tooling dependencies. |
package.json |
Adds YAML tooling dependency. |
docs/docs/development/templates.md |
Documents package-manager templating. |
.github/workflows/ci.yml |
Adds dual package-manager smoke and artifact validation. |
Files not reviewed (2)
- pnpm-lock.yaml: Generated file
- template/pnpm-lock.yaml: Generated file
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| const workspacePath = join(STAGING_DIR, "pnpm-workspace.yaml"); | ||
| const workspace = parseDocument(readFileSync(workspacePath, "utf-8")); | ||
| if (workspace.errors.length) throw workspace.errors[0]; | ||
| workspace.setIn( | ||
| ["overrides", "@databricks/lakebase"], | ||
| pkg.overrides["@databricks/lakebase"], | ||
| ); | ||
| writeFileSync(workspacePath, workspace.toString()); |
| const yamlStr = readFileSync(path, "utf-8"); | ||
| const lockfile = parseYaml(yamlStr) as Record<string, unknown>; | ||
|
|
||
| const packages: Record< | ||
| string, | ||
| { resolution?: Record<string, unknown> | string } | ||
| > = (lockfile.packages ?? {}) as Record< | ||
| string, | ||
| { resolution?: Record<string, unknown> | string } | ||
| >; |
| // If there's no type and no tarball, it must be registry-derived (integrity only) | ||
| if (!res.tarball) { | ||
| // Registry-derived resolutions have only integrity, which is OK | ||
| continue; | ||
| } |
🤖 AppKit PR bot🔬 Run evalsStart an eval for this PR from the evals-monitor app: Go to Evals Monitor → 📦 Try this PR's app templateScaffolds a new app from this PR's SDK build. Run it in any folder (requires the GitHub CLI — gh run download 35978478952 -R databricks/appkit -n appkit-template-0.76.1-pr.23f8611-pnpm-template-2-npm-artifacts-598 -D appkit-pr-598 \
&& unzip -o "appkit-pr-598/appkit-template-0.76.1-pr.23f8611-pnpm-template-2-npm-artifacts-598.zip" -d "appkit-pr-598" \
&& databricks apps init --template "appkit-pr-598"The template pins |
Signed-off-by: Atila Fassina <atila@fassina.eu>
| "test": "vitest run", | ||
| "clean": "rm -rf client/dist dist build node_modules", | ||
| "prebuild": "pnpm run sync && pnpm run typegen --wait", | ||
| "prebuild": "pnpm run sync && appkit generate-types --wait", |
There was a problem hiding this comment.
why do we change this one?
|
Superseded by #593 — the pnpm-template stack has been consolidated into a single PR targeting This comment was written by Isaac. |


What & why
Phase 2 of the pnpm-first app-template initiative (stacked on #593). Restores first-class npm support so a scaffold selected as npm (
databricks apps init --package-manager npm) installs and deploys with native deps intact, while the committed default stays pnpm-shaped. Both lockfiles ship and both are leak-validated in CI, fail-closed.Stacked PR — base is
pnpm-template/1-pnpm-first(#593), notmain. Review only the commits above #593.Changes
npm artifacts (
template/)template/package-lock.json(lockfileVersion 3, public registry only)overridesintemplate/package.json, mirroring thepnpm-workspace.yamloverrides@ast-grep/napi-linux-x64-gnuas a rootoptionalDependency(os/cpu guarded by the package) — a defensive edge against [BUG] Platform-specific optional dependencies not being included inpackage-lock.jsonwhen reinstalling withnode_modulespresent npm/cli#4828-style lock regeneration dropping the linux binarycheck-template-deps: fail when the npm/pnpm override placements drift, or when the linux pin is missing or skews from@ast-grep/napiDual-lock validation + CI
check-template-lock-registryvalidates bothpnpm-lock.yamlandpackage-lock.jsonby default, fail-closed if either is missing; the pnpm handler now parses YAML (tarball / git / directory / missing resolutions fail closed, at parity with the npm handler)npm installon linux-x64, assert@ast-grep/napi-linux-x64-gnumaterializes + loads at runtime, build client & server (runtime-load check added to the pnpm path too)tools/template-artifacts.ts+tools/template-smoke-runner.tswith atemplate-artifacts.test.tssuitepr-template-artifactregenerates both locks against the PR tarballs and rewrites/validates both before zipping, so the artifact no longer ships a stalepnpm-lock.yamlTesting
pnpm build,pnpm -r typecheck,pnpm check,pnpm test,check-template-lock-registry,check-template-deps— all green.Notes
@ast-grep/napi-linux-x64-gnuroot pin is defensive, not load-bearing: on npm 11.8 the binary materializes with or without it (including the #4828 reinstall-with-node_modules shape). Kept per the phase's acceptance criteria; comments say so.This pull request and its description were written by Isaac.