Appearance
Projen Template
@wbce/projen-d9 is a projen template for d9 projects. It scaffolds a local development setup with Docker Compose (Postgres + Redis), extension management, and GitHub PR and issue templates, and allows you to produce a Docker image you can deploy to any environment.
Companion package: @wbce/projen-d9-extension for authoring extensions.
Just want to run d9?
If you only need to run d9 (no extensions, no customization), the Docker Guide is the easier and faster path: one docker run command, no project scaffolding.
Bootstrap a new project
sh
npx projen new --from @wbce/projen-d9This creates a .projenrc.js and synthesizes the project.
Integrate into an existing project
When you're adopting the template inside an existing d9 repo, projen needs to take ownership of package.json and a handful of other files. The cleanest path is to delete package.json and let projen new regenerate everything, then reconcile the diff against your old config:
Start a feature branch. Run
git checkout -b add-projen. You want a clean working tree so the post-synth diff is meaningful.Delete
package.jsonThey'll be reconstructed from.projenrc.js.shrm package.json Dockerfile docker-compose.yml .gitignore tsconfig.jsonBootstrap with
--no-git. The flag stops projen from runninggit initor making an initial commit on top of your existing history, so you keep full control of when to commit.shnpx projen new --from @wbce/projen-d9 --no-gitReconcile the diff. Compare the regenerated files against the previous commit (
git diff HEAD). Anything missing from your old setup (extra deps, custom env vars indocker-compose.yml, extra Dockerfile steps, custom scripts) needs to be expressed in.projenrc.js, not patched into the generated files. Iterate: edit.projenrc.js, re-runnpx projen, diff again.Commit once the diff is clean.
Don't commit until the diff is right
Every npx projen run overwrites the managed files, so partial commits are easy to clobber. Keep iterating on .projenrc.js until the generated output matches what you need, then commit the whole set together.
Usage
.projenrc.js:
js
import { D9Project } from '@wbce/projen-d9';
import { D9ExtensionType } from '@wbce/projen-d9-extension';
const project = new D9Project({
name: 'my-d9',
defaultReleaseBranch: 'main',
eslintOptions: {
dirs: ['src', 'test'],
prettier: true,
},
});
// A shared package other extensions can depend on
project.addExtension('shared', []);
// A hook extension that depends on the shared package
const myHook = project.addExtension('my-hook', [D9ExtensionType.HOOK]);
myHook.addDeps('shared@workspace:');
project.synth();Then synth and start it:
sh
npx projen
npx projen first-run # boot stack + create admin user
npx projen run # start d9 (port 8055)The default admin user is admin@example.com / totototo.
Default credentials
The default admin password (totototo) is intentionally weak so you remember to change it. Rotate it before exposing the instance to anything beyond localhost.
The Docker container sets EXTENSIONS_AUTO_RELOAD=true, so editing an extension and re-running npx projen build-extensions is enough. No restart, no redeploy.
Extension types
D9ExtensionType values: INTERFACE, DISPLAY, LAYOUT, MODULE, PANEL, ENDPOINT, HOOK, OPERATION. Pass an empty array for a shared (non-extension) package.
Extensions live under ./plugins/ (configurable via extensionsFolderName) and are built by the build-extensions task.
js
// Single-type extension: a standalone `directus:extension` package
project.addExtension('audit-log', [D9ExtensionType.HOOK]);
// Multiple types: bundled under one `directus:extension` of type 'bundle'
project.addExtension('reporting-suite', [
D9ExtensionType.ENDPOINT,
D9ExtensionType.MODULE,
]);Sharing code across extensions
The plugins/ folder is a pnpm workspace, so the usual pnpm sharing mechanisms work across extensions:
workspace:protocol to depend on a sibling package. The empty-types scaffoldaddExtension('shared', [])is the canonical case (see Usage for the full example).pnpm-workspace.yamlcatalogs to pin shared dependency versions in one place, then consume them ascatalog:from each extension'sdeps/devDeps.
Generated tasks
| Task | Description |
|---|---|
first-run | Boot the stack, create admin, start d9 |
run | Start d9 (docker compose up directus) |
build-extensions | Install and build all extensions |
create-an-admin | Create the default admin user |
What gets generated
docker-compose.yml: d9, Postgres (PostGIS), Redis with healthchecksDockerfile: Node 22 + pnpm, builds extensions.env.local: sample for local environment overrides- GitHub PR and issue templates via
@wbce/projen-shared(setgithubConfig: falseto disable)
Deploying
The generated Dockerfile is meant for deployment. Build and push it to your registry, then run it against your target database and cache:
sh
docker build -t <registry>/<image>:<tag> .
docker push <registry>/<image>:<tag>Configure the deployed instance via environment variables (database, cache, secrets, keys) the same way you would any other d9 container. See the Config Options page for the full list.
Options
The full D9ProjectOptions reference lives in the package's API docs. Highlights:
extensionsFolderName: folder for extension packages (default:plugins)packageVersions.d9: version of@wbce-d9/directus9(default:12.0.1)githubConfig:GitHubConfigOptionsorfalseto disable
Any option from the projen TypeScriptProjectOptions interface is also accepted.
Source
- npm:
@wbce/projen-d9 - Repository: LaWebcapsule/projen-templates