Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
Custom Nx workspace schematic to build a custom 'state' library.

Scenario

We want to build a custom schematic for company Aero that will internally do two things:

  • build a new ngrx library using Nx workspace naming conventions
  • generate ngrx state-management files; include the *.facade.* files

Important: This example is valid ONLY for Nx v6.2.x or higher!


Steps to Build/Use Custom Schematics

  1. Use the following command to generate a custom schematic called ngrx-lib.

This custom workspace schematic will:

  • Generate a Nx library
  • Generate NgRx files inside a folder called +state.
  • Generate NgRx Facade files for the new NgRx state management files
ng g workspace-schematic ngrx-lib
  1. Then open the new empty schematic at /tools/schematics/ngrx-lib/index.ts and replace the contents with your own custom logic.

nx-custom-schematic

The schematic code for our requirements is here :

/tools/schematics/ngrx-lib/index.ts
import {
  chain,
  externalSchematic,
  Rule
} from '@angular-devkit/schematics';
import * as path from 'path';

/**
 * Build a new custom Nx library with ngrx files.
 * Using Nx workspace conventions, these custom libraries are 'state' libraries since 
*  they will manage ngrx state, REST endpoints, etc.
 */
export default function(schema: any): Rule {
  const PREFIX = 'state-';
  if (!schema.name.startsWith('state-') && (schema.name != 'state')) {
    // custom libraries managing state must have name conventions: 'state' or 'state-<name>'
    schema.name = PREFIX + schema.name;
  }

  const name = schema.name.substring(PREFIX.length);
  const libPath = schema.directory ? path.join(schema.directory, schema.name) : schema.name;
  const moduleName = schema.directory ? `${schema.directory}-${schema.name}` :  schema.name;
  const module = path.join('libs',libPath, 'src/lib', `${moduleName}.module.ts`);

  return chain([
    externalSchematic('@nrwl/schematics', 'lib', {
      name: schema.name,
      directory : schema.directory,
      tags :  schema.directory ? `state, ${schema.directory}` : 'state, aero'
    }),
    externalSchematic('@nrwl/schematics', 'ngrx', {
      name,
      module,
      directory: '+state',
      facade : true
    })
  ]);
}
  1. Now you can use the custom workspace schematic (in your workspace).

In our example, we want a new state library called for airports and we want to group that library in a directory called trip-planner:

npm run workspace-schematic ngrx-lib airports -- --directory=trip-planner
# or 
yarn  workspace-schematic ngrx-lib planes --directory=trip-planner

Note the extra -- when using npm. This is required so these options are considered options for the workspace-schematic instead of npm itself.

This would output to the console something similar to:

create libs/trip-planner/state-planes/karma.conf.js (508 bytes)
create libs/trip-planner/state-planes/tsconfig.lib.json (828 bytes)
create libs/trip-planner/state-planes/tsconfig.spec.json (283 bytes)
create libs/trip-planner/state-planes/tslint.json (252 bytes)

create libs/trip-planner/state-planes/src/index.ts (205 bytes)
create libs/trip-planner/state-planes/src/test.ts (700 bytes)

create libs/trip-planner/state-planes/src/lib/trip-planner-state-planes.module.ts (720 bytes)
create libs/trip-planner/state-planes/src/lib/trip-planner-state-planes.module.spec.ts (445 bytes)

create libs/trip-planner/state-planes/src/lib/+state/planes.actions.ts (727 bytes)
create libs/trip-planner/state-planes/src/lib/+state/planes.effects.spec.ts (1158 bytes)
create libs/trip-planner/state-planes/src/lib/+state/planes.effects.ts (833 bytes)
create libs/trip-planner/state-planes/src/lib/+state/planes.facade.spec.ts (2848 bytes)
create libs/trip-planner/state-planes/src/lib/+state/planes.facade.ts (606 bytes)
create libs/trip-planner/state-planes/src/lib/+state/planes.reducer.spec.ts (1130 bytes)
create libs/trip-planner/state-planes/src/lib/+state/planes.reducer.ts (960 bytes)
create libs/trip-planner/state-planes/src/lib/+state/planes.selectors.spec.ts (1596 bytes)
create libs/trip-planner/state-planes/src/lib/+state/planes.selectors.ts (962 bytes)

Notice how trip-planner-state-planes.module.ts has export class TripPlannerStatePlanesModule and uses the <grouping-folder>-<library-name>.module.ts convention. This allows developers to easily determine the folder and library associated with that ngModule.

@CharlieGreenman

This comment has been minimized.

Copy link

commented Sep 6, 2018

Does the above support camelCase?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.