DEV Community

John Peters
John Peters

Posted on

Angular Library Folder Structures : Schematics

What if our library were to include a schematic?

Angular CLI: 9.0.7
Node: 12.14.1
OS: win32 x64

Angular: 9.0.7
... animations, cli, common, compiler, compiler-cli, core, forms
... language-service, platform-browser, platform-browser-dynamic
... router
Ivy Workspace: Yes

Package                            Version
------------------------------------------------------------
@angular-devkit/architect          0.900.7
@angular-devkit/build-angular      0.900.7
@angular-devkit/build-ng-packagr   0.900.7
@angular-devkit/build-optimizer    0.900.7
@angular-devkit/build-webpack      0.900.7
@angular-devkit/core               9.0.7
@angular-devkit/schematics         9.0.7  <= Must exist
@ngtools/webpack                   9.0.7
@schematics/angular                9.0.7
@schematics/update                 0.900.7
ng-packagr                         9.1.5
rxjs                               6.5.5
typescript                         3.7.5
webpack                            4.41.2
Enter fullscreen mode Exit fullscreen mode

We started...

cd projects
// this requires an environment variable 
// pointing to global node_modules bin folder
schematics blank --schematics --name=schematic

Enter fullscreen mode Exit fullscreen mode

Make sure the outer package.json file and the schematics.json have
same versioning.

Alt Text

Auto-Generated Code

Alt Text

ng build schematics
An unhandled exception occurred: Project 'schematics' does not support the 'build' target.
See "C:\src\AppData\Local\Temp\ng-WJqucJ\angular-errors.log" for further details.
Enter fullscreen mode Exit fullscreen mode

Set up a console.log

Alt Text

ng build schematics
{
  archtectCommand: {
    projectName: 'schematics',
    targetProjectNames: [ 'projecty', 'demo' ]
  }
}
// ok, the target project names does not include our schematics project.
// the angular.json file had no entry for this project!
Enter fullscreen mode Exit fullscreen mode

This doesn't work either

// moved it inside the library
C:\src\projectx\projects\projecty\src\lib> schematics blank --schematics --name=schematics
Enter fullscreen mode Exit fullscreen mode

Back Up

// we tried this command again in different folder.
// the same folder as first try
C:\src\projectx\projects> schematics blank --name=schematics
cd .\schematics
npm install
npm run build

Enter fullscreen mode Exit fullscreen mode

This worked because we were calling the build in the schematics folder, using npm instead of ng. But there was a compiler error.

src/schematics/index_spec.ts:12:25 - error TS2339: Property 'runSchematic' does not exist on type 'SchematicTestRunner'.

12     const tree = runner.runSchematic('schematics', {}, Tree.empty());
Enter fullscreen mode Exit fullscreen mode

Never argue with a compiler...

Alt Text
There it is; the new async version. This means the schematic itself is wrong... The angular/cli doesn't generate schematics correctly. Easy to fix.

Alt Text

This fixes the error:

import { Tree } from '@angular-devkit/schematics';
import { SchematicTestRunner } from '@angular-devkit/schematics/testing';
import * as path from 'path';

const collectionPath = path.join(__dirname, '../collection.json');


describe('schematics', () => {
  it('works', async() => {
    const runner = new SchematicTestRunner('schematics', collectionPath);
    const tree = await runner.runSchematicAsync('schematics', {}, Tree.empty());
    tree.subscribe(tree=>{
      console.log(tree);
      expect(tree.files).toEqual([]);
    });

  });

});

Enter fullscreen mode Exit fullscreen mode

Our first glimpse into a schematic tree!

UnitTestTree {
  _other: HostTree {
    _backend: Empty { capabilities: [Object] },
    _id: -1,
    _ancestry: Set {},
    _dirCache: Map {},
    _record: CordHost {
      _cache: [Map],
      _watchers: Map {},
      _back: [SafeReadonlyHost],
      _filesToCreate: Set {},
      _filesToRename: Map {},
      _filesToRenameRevert: Map {},
      _filesToDelete: Set {},
      _filesToOverwrite: Set {}
    },
    _recordSync: SyncDelegateHost { _delegate: [CordHost] }
  }
Enter fullscreen mode Exit fullscreen mode

Top comments (2)

Collapse
 
xiongemi profile image
Emily Xiong • Edited

I think this code snippet will not render. you need either add toPromise() to the runSchematicAsync:

describe('schematics', () => {
  it('works', async() => {
    const runner = new SchematicTestRunner('schematics', collectionPath);
    const tree = await runner.runSchematicAsync('schematics', {}, Tree.empty()).toPromise();
    expect(tree.files).toEqual([]);
  });
Enter fullscreen mode Exit fullscreen mode

or remove async/await:

it('works', () => {
    const runner = new SchematicTestRunner('schematics', collectionPath);
    const tree = runner.runSchematicAsync('schematics', {}, Tree.empty());
    tree.subscribe(tree=>{
      console.log(tree);
      expect(tree.files).toEqual([]);
    });
  });
Enter fullscreen mode Exit fullscreen mode
Collapse
 
jangelodev profile image
João Angelo

Hi John Peters,
Your tips are very useful
Thanks for sharing