@atlasng/nx-plugin
v0.0.3
Published
Nx plugin with shared generators, executors, inferred targets and presets for AtlasNG and related Nx workspaces
Readme
@atlasng/nx-plugin
Nx plugin for AtlasNG and other Nx Angular workspaces. It sets up the shared tooling packages, infers Compodoc targets, provides release executors and ships an nx.json preset.
Installation
npx nx add @atlasng/nx-pluginnx add installs the plugin and runs its init generator.
Init generator
npx nx g @atlasng/nx-plugin:init sets up a new or existing workspace:
- adds
@atlasng/eslint-plugin,@atlasng/prettier-config,@atlasng/commitlint-configand@atlasng/tsconfigas devDependencies, using the version ranges in the plugin's own optionalpeerDependencies(nx releasekeeps them in step with the released config packages) - writes a thin root
eslint.config.mjsbuilt on the@atlasng/eslint-pluginconfigs, with the Angular selector prefix and an@nx/enforce-module-boundariesblock to adjust - sets the
prettierkey inpackage.jsonto@atlasng/prettier-config(a default Nx.prettierrcthat only setssingleQuoteis removed) - writes
commitlint.config.mjsextending@atlasng - makes
tsconfig.base.jsonextend@atlasng/tsconfig/angular.json(ornode.jsonwith--tsconfigPreset=node) - registers the plugin in
nx.json - registers the sync generator under
sync.globalGenerators(storing--prefixin its options) and runs it
It never overwrites existing custom configuration: an existing ESLint, Prettier or commitlint config, or a different extends in tsconfig.base.json, is kept and a warning explains what to change by hand. Running it again changes nothing.
| Option | Default | Description |
| ----------------- | ---------------------------------------- | ------------------------------------------------ |
| prefix | the nx.json generator prefix, or app | Angular selector prefix for the ESLint rules |
| tsconfigPreset | angular | The @atlasng/tsconfig preset to extend |
| skipPackageJson | false | Do not add the config packages to package.json |
| skipFormat | false | Do not format the changed files |
Sync generator
@atlasng/nx-plugin:sync is a global sync generator that keeps the files every workspace shares up to date. init registers it; to add it by hand:
{
"sync": {
"globalGenerators": ["@atlasng/nx-plugin:sync"],
"generatorOptions": {
"@atlasng/nx-plugin:sync": {
"prefix": "ang",
"extraScopes": ["release"],
"exclude": []
}
}
}
}npx nx sync applies the changes and npx nx sync:check fails when a managed file has drifted, which makes it a good CI step.
| Option | Default | Description |
| ------------- | ---------------------------------------- | ------------------------------------------------------------------------------------ |
| prefix | the nx.json generator prefix, or app | Angular selector prefix used in the managed files and the Angular generator defaults |
| extraScopes | [] | Commit scopes added to the project names in conventionalCommits.scopes |
| exclude | [] | Managed-file ids or paths to leave alone; a directory skips everything below it |
| Id | File | Strategy |
| ---------------------- | ---------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------- |
| editorconfig | .editorconfig | Whole file |
| gitattributes | .gitattributes | Whole file |
| nvmrc | .nvmrc | Whole file |
| husky-commit-msg | .husky/commit-msg | Whole file, executable |
| husky-pre-commit | .husky/pre-commit | Whole file, executable |
| testing-instructions | .github/instructions/testing.instructions.md | Whole file |
| angular-instructions | .github/instructions/angular.instructions.md | Whole file with the prefix filled in |
| skills | .agents/skills/atlasng-* | Whole files; atlasng-* skills and files the plugin no longer ships are removed. Other skills, such as the Nx ones, are never touched |
| vscode-extensions | .vscode/extensions.json | JSON merge: union of recommendations |
| vscode-settings | .vscode/settings.json | JSON merge: Nx Console generator allow and block lists; conventionalCommits.scopes is set to the sorted project names plus extraScopes |
| mcp | .mcp.json | JSON merge: the angular-cli MCP server |
| claude-settings | .claude/settings.json | JSON merge: the Nx Claude Code marketplace and plugin |
| nx-json | nx.json | JSON merge: namedInputs, targetDefaults and generators from presets/nx.json, plus prefix for the Angular generators |
| agents-md | AGENTS.md | Marker block between <!-- atlasng configuration start --> and <!-- atlasng configuration end -->, appended when missing |
A JSON merge keeps every local key:
- Objects are merged key by key.
- Arrays keep every local entry and get the missing shared entries appended. An object entry counts as present when a local entry has the same identity keys:
plugin,type,name,id,glob,input,target,projects,dependencies,fileset,runtime,envanddependentTasksOutputFilesare compared by value, andexternalDependenciesby presence. The matched local entry keeps its values and only gets the keys and array items it lacks. A customised entry, such as an Angular budget{ "type": "initial", "maximumWarning": "600kb" }, is therefore kept and the preset'sinitialbudget is not added next to it. - Other values, such as strings, numbers and booleans outside array entries, are always set to the shared value, so preset updates reach every workspace. A local change to one of them, for example
targetDefaults.test.options.coverageThresholds, is reverted bynx syncand reported bynx sync:check. Override such values in the project'sproject.json, which takes precedence overtargetDefaults, or excludenx-json.
A file is only rewritten when its parsed value changes, so comments survive a run with nothing to do. Removing a shared entry from every workspace, or changing a value inside an existing array entry, therefore needs a migration.
Nx caches sync results in the daemon and does not see a file mode change on its own. If only the executable bit of a hook was lost, run NX_DAEMON=false npx nx sync.
Inferred Compodoc targets
When the plugin is registered in nx.json, every project with an ng-package.json, a tsconfig.lib.json and a project.json or package.json gets two targets:
| Target | Description |
| ---------------- | ---------------------------------------------------------------- |
| build-compodoc | Builds the static API docs to dist/compodoc/<project> (cached) |
| compodoc | Serves the API docs and rebuilds them on change (continuous) |
Projects that also have a .storybook directory get a third target:
| Target | Description |
| -------------------------- | ------------------------------------------------------------------------------- |
| build-storybook-compodoc | Builds the Compodoc JSON that Storybook reads to .storybook/compodoc (cached) |
ng-packagr secondary entry points are skipped. The targets run npx compodoc, so the workspace needs @compodoc/compodoc installed. The target names are options:
{
"plugins": [
{
"plugin": "@atlasng/nx-plugin",
"options": {
"buildCompodocTargetName": "build-compodoc",
"compodocTargetName": "compodoc",
"buildStorybookCompodocTargetName": "build-storybook-compodoc"
}
}
]
}Executors
release-notes
Combines the CHANGELOG.md sections of a fixed release group into one set of GitHub release notes. Projects whose section only records a version bump are left out, and projects without a section for the version are left out with a warning. Version headings may carry a date (## 1.2.3 (2026-01-02)), no date (## 1.2.3) or a compare link (## [1.2.3](...)). The group's projects come from nx.json and may be names, globs, directories or tags.
| Option | Default | Description |
| -------- | ----------- | ----------------------------------------------------------------------------------- |
| group | libraries | Release group name in nx.json |
| tag | (required) | Release tag, for example v1.2.3; the version is read with the group's tag pattern |
| output | | File to write the notes to, relative to the workspace root |
{
"targets": {
"release-notes": {
"executor": "@atlasng/nx-plugin:release-notes",
"options": { "group": "libraries" }
}
}
}Use --output in CI: without it the notes go to stdout, mixed with the Nx task header and summary.
npx nx run @atlasng/monorepo:release-notes --tag=v1.2.3 --output=tmp/release-notes.md
gh release create v1.2.3 --notes-file tmp/release-notes.mdbootstrap-npm-packages
npm trusted publishing can only be configured for packages that already exist on the registry. This executor builds every project with an nx-release-publish target that is not on npm yet, publishes each one with npm publish (dependencies first, attached to the terminal so npm can wait for two-factor authentication), then runs npm trust github so later releases can be published from CI.
- Packages already on npm are skipped. Only an
E404fromnpm viewcounts as "not published"; any othernpm viewfailure, such as a network or authentication error, stops the executor before anything is built or published. - A failed
npm publishstops the executor, because later packages may depend on the package. - A failed
npm trustdoes not stop the remaining packages, but the executor fails and prints thenpm trust githubcommand for each affected package. A rerun skips these packages because they now exist on npm, so run the printed commands by hand. - On Windows,
npmandnpxare run through the shell, because they are.cmdscripts.
| Option | Default | Description |
| ------------ | ------------------- | --------------------------------------------------- |
| repository | the origin remote | GitHub repository (owner/name) allowed to publish |
| workflow | publish.yml | Workflow file that publishes the packages |
| dryRun | false | Only print the commands that would run |
npm login
npx nx run @atlasng/monorepo:bootstrap-npm-packages --dryRun
npx nx run @atlasng/monorepo:bootstrap-npm-packagesNx preset
presets/nx.json holds the shared namedInputs, targetDefaults and generators defaults (without a selector prefix). It is not meant to be used through nx.json "extends".
Nx merges an extended nx.json with a shallow, top-level spread ({ ...preset, ...nxJson }), which was confirmed with Nx 23.2:
- a top-level key present in both files, such as
targetDefaults,namedInputs,generatorsorplugins, is taken entirely from the localnx.json; nothing from the preset's copy survives, not even entries the local file does not mention - a key only in the preset is used as is
updateNxJsonin generators writes back every top-level key that differs from the preset, so the first generator that adds a target default copies the whole preset key into the local file
Every real workspace needs local targetDefaults, namedInputs and generators, so extends would drop the preset's values. The sync generator merges these keys into nx.json instead.
Migrations
migrations.json is registered through nx-migrations in package.json, so breaking changes can ship as migrations that run with npx nx migrate @atlasng/nx-plugin@latest. There are none yet.
