Frontend npm Registry
Overview
Section titled “Overview”The @granit/* packages are published on the GitHub Packages npm registry.
A hybrid strategy keeps local development performant (hot-reload) while
supporting Docker builds and standalone CI/CD.
graph LR
subgraph "Local development"
DEV["guava-admin / guava-front"]
DEV -->|"link:"| SRC["granit-front source<br/>(TypeScript)"]
end
subgraph "Docker / CI"
CI[Dockerfile]
CI -->|"npm install"| REG["GitHub Packages<br/>(compiled packages)"]
end
subgraph "Publication"
TAG["Tag vX.Y.Z"] -->|CI pipeline| BUILD["tsup build<br/>(ESM + .d.ts)"]
BUILD -->|"pnpm publish"| REG
end
Hybrid strategy
Section titled “Hybrid strategy”| Context | Resolution | Source | Hot-reload |
|---|---|---|---|
| Local development | link: + Vite aliases | TypeScript source | Yes |
| Docker / CI | GitHub Packages npm registry | Compiled JavaScript + .d.ts | No |
Local development
Section titled “Local development”Applications use link: in package.json to point to TypeScript sources:
{ "dependencies": { "@granit/logger": "link:../../../granit-front/packages/@granit/logger" }}Combined with Vite aliases, this provides instant hot-reload when modifying framework code.
Docker / CI
Section titled “Docker / CI”In Docker, the granit-front directory does not exist. The Dockerfile:
- Copies
.npmrc(scope@granit→ GitHub Packages registry) - Replaces
link:dependencies with*(registry resolution) - Injects the authentication token via
--build-arg NPM_TOKEN - Installs compiled packages from the registry
Publication
Section titled “Publication”Versioning
Section titled “Versioning”All packages share the same version, aligned with Git tags on the
granit-front project. Semantic versioning (vMAJOR.MINOR.PATCH).
Automatic publication (CI)
Section titled “Automatic publication (CI)”Publication is triggered by a Git tag matching vX.Y.Z:
git tag v0.1.0git push origin v0.1.0The CI pipeline runs:
quality— lint + typechecktest— unit testsbuild—tsup(ESM +.d.ts) for each packagepublish—pnpm -r publishto the GitHub Packages registry
Authentication uses GITHUB_TOKEN (automatic, no secret to configure).
Manual publication
Section titled “Manual publication”For manual publication (not recommended in production):
# Create a personal access token (PAT) in GitHub > Settings > Personal access tokens# Scope: write:packages
pnpm buildpnpm -r publish --no-git-checks --access restrictedConsumer configuration
Section titled “Consumer configuration”.npmrc
Section titled “.npmrc”Each consuming application needs an .npmrc:
@granit:registry=https://npm.pkg.github.comConditional Vite aliases
Section titled “Conditional Vite aliases”The @granit/* aliases in vite.config.ts are conditional — they only
apply when the local granit-front directory exists:
import fs from 'fs';
const GRANIT = path.resolve(__dirname, '../../../granit-front/packages/@granit');const useLocalGranit = fs.existsSync(GRANIT);
// Local dev: aliases → TypeScript source (hot-reload)// Docker/CI: no aliases → resolved via node_modules (registry)Docker build
Section titled “Docker build”docker build \ --build-arg NPM_TOKEN=<pat-or-github-token> \ -t guava-admin .In CI, GITHUB_TOKEN is used automatically.
Package build configuration
Section titled “Package build configuration”Each package is compiled with tsup:
- Format: ESM only
- Output:
dist/index.js+dist/index.d.ts - Externals:
@granit/*(inter-packages),peerDependencies
publishConfig
Section titled “publishConfig”The package.json of each package uses publishConfig to separate local
exports (source) from published exports (compiled):
{ "exports": { ".": "./src/index.ts" }, "publishConfig": { "exports": { ".": { "types": "./dist/index.d.ts", "import": "./dist/index.js" } }, "registry": "https://npm.pkg.github.com" }}- Locally:
exportspoints to TypeScript source - Published:
publishConfig.exportsoverrides and points todist/
Troubleshooting
Section titled “Troubleshooting”Package not found on the registry
Section titled “Package not found on the registry”npm view @granit/logger \ --registry=https://npm.pkg.github.comOr check in GitHub: granit-fx/granit-front > Packages.
Authentication error (401/403)
Section titled “Authentication error (401/403)”- Verify
.npmrccontains the correct_authToken - In CI:
GITHUB_TOKENis automatic, no configuration needed - Locally: use a personal access token (PAT) with
read:packagesscope
Docker build fails on @granit/* packages
Section titled “Docker build fails on @granit/* packages”- Verify
--build-arg NPM_TOKEN=xxxis passed todocker build - Verify packages are published on the registry
- Verify
.npmrcis copied in thedepsstage (not excluded by.dockerignore)
See also
Section titled “See also”- Frontend CI/CD — pipeline and release workflow
- Frontend Quick Start — local setup