DEV Community

JWP
JWP

Posted on

4 1

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

👋 Kindness is contagious

Engage with a wealth of insights in this thoughtful article, valued within the supportive DEV Community. Coders of every background are welcome to join in and add to our collective wisdom.

A sincere "thank you" often brightens someone’s day. Share your gratitude in the comments below!

On DEV, the act of sharing knowledge eases our journey and fortifies our community ties. Found value in this? A quick thank you to the author can make a significant impact.

Okay