Angular Schematics : How to create an empty folder ?

Angular Schematics are so powerful to automate some tree actions on your project. But creating new empty folder is not that easy… In fact, it is!

Quoting the Angular doc :

A schematic is a template-based code generator that supports complex logic. It is a set of instructions for transforming a software project by generating or modifying code.

You can find more info about schematics here :

I really like schematics to scaffold my project. Here is my minimal structure for Angular projects :

It’s very explanatory and you can notice I’m using the Atomic Design Pattern.

Atomic Design Pattern (ADP)

is a powerful way of composing your components into several levels of usage. You can find a deeper article dealing with it here :

TL;DR : It helps to decouple your components to increase testability, readability. The top level components use the lowest ones.

However this pattern may have some “detractors” because this hierarchy is not feature-oriented. It means that if you have components dealing with user-related parts of your app, they will be drowned among all other components.

To overcome this obstacle, you have several options:

  1. Add a shared folder containing the most generic (common) components decomposed according to ADP.
  2. Add a feature-named folder which will contain all the feature-related components, still decomposed according to ADP.
  3. Finally if you prefer, you can keep the ADP architecture and separate the featured components inside each ADP level.

As you can see, it’s opinionated and your choice should answer to this question:

Do I prefer to look for a component by its functionality, its feature (options #1 and #2) or its granularity (option #3) ?

Back to schematics

0 — Structure explanation

All components will be declared in the components.module.ts file. It will export the pages components (and others necessary components) which will be used, for example, in the routing file.

No need to explain the data folder and its content, I guess you get it 😉. Of course, the routing module could be integrated in the main project.module.ts file.

Note : I have intentionally omitted the creation of the routing module, to ease understanding. But it can be a challenge for you to improve it 😉 !

There are many empty folders but how to create them you may ask. Let’s start the journey to schematics world!

1 — Creating a schematic

First, we need to install the dependency to access the schematic API:

npm install -g @angular-devkit/schematics-cli

The, we can create our own schematic, let’s name it scaffold-schematics :

schematics blank --name=scaffold-schematics

Suggestion:

I recommend you to add a new npm task to build the schematic locally in watch mode.

The created index.ts contains a set of rules which will interact with the tree folder. We can create several functions defining a specific action. We will need a function to :

  • Create the data folders (A)
  • Create the ADP components folders (B)
  • Optionally, add the store folder (C)
  • Create our module files : components and global (D)

2 — Exploring the Schematic API

The Schematic API provides a lot of utility functions and objects to manipulate files and folder. Initially, the index.ts file looks like this:

The tree object has a create method, but only to create a file (Github). How to turn this into our advantage to create a folder. Well…

Good news : Git to the rescue !!!

Do you know the .gitkeep file ? When you create an empty directory, Git does not version it. Adding this .gitkeep file will notify git to version it. So, this is our trick: creating a .gitkeep is the key to generate an empty folder!

Now, we need to finalize the configuration :

  1. Add a schema.json and a schema.d.ts to define the options
  2. Specify the schema into collection.json

3 — Coding the tasks

We’re going to use the normalize function from @angular-devkit/core to ensure the path is valid (no // for instance).

Create the data folders (A)

Create the ADP components folders (B)

Optionally, add the store folder (C)

We will see later how to conditionally trigger this method :

Create our module files : components and global (D)

In order to create a file from template, we need to use several methods :

import { apply, url, applyTemplates, mergeWith, renameTemplateFiles, move, filter } from '@angular-devkit/schematics';import { normalize, strings } from '@angular-devkit/core';

Then, the common way is to create a files folder which holds the template files (suffix with the .template extension, not mandatory).

The strings import provides functions which are injected in template, you can find them here:

4 — All-in-one execution

The Schematic API provides the chain function to execute sequentially the tasks. Therefore, in our input function (defined in the collection.json file) we just need to chain all the functions defined above.

As you can see, we can trigger a function conditionally (ie: option.useStore). The noop() helps to indicate nothing should be done.

5 — Run the schematic

Just a simple command is necessary to run the schematic :

schematics .:scaffold-schematics --dry-run=false

The --dry-run=false option specifies that we are not in debug mode.

The . indicates where you want to run the command.

You can find all the code on my git repository :

Web Engineer stacking and sharing his experiences

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store