Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a custom schematic to build a new angular project

I'm trying to create a new schematic that can run without first doing an "ng new project-name" and then running "ng g my-schematic"

When I even run my schematic locally, I have to first set my defaultCollection of my CLI to my schematic, which doesn't make sense and I'm unsure why that's occurring.

The error I get is "cannot find my-schematic in @schematics/angular"

My schematic is very simple, and I'd like it to be run and generate the entire scaffolding of a project when ran.

export function nextGen(options: any): Rule {
  return (tree: Tree, _context: SchematicContext) => {
    const rule = mergeWith(apply(url('./files'), [
      template({
        ...options
      }),
      forEach((fileEntry: FileEntry) => {
        console.log(fileEntry.path);
        if (tree.exists(fileEntry.path)) {
          tree.overwrite(fileEntry.path, fileEntry.content);
          return null;
        }
        return fileEntry;
      })
    ]))
    return rule(tree, _context); 
  }
};

Is there a known and simple way to accomplish this? I'm not sure if attempting to "extend" the "new" schematic or to use a "ng new project-name collection=my-schematic could work?

If either of these options are possible, what would it mean in terms of the tree passed in, and how could you manipulate it to produce the files contained in the "./files" library?

Thanks!

like image 536
saulgoodman Avatar asked Nov 01 '25 20:11

saulgoodman


1 Answers

There's a few different schematic related questions in your ask, so I'll try to answer as many as I can. First, it sounds like you want to run a single Angular CLI command to generate your base project. I have never used the option you suggest to change the default schematic collection for the global CLI install and instead run ng new project-name --collection collection-name.

Now, let's talk about the two options you've considered: extending vs. overwriting. If you were to extend the default ng new schematic, your schematic rule might look something like this:

const ruleChain = chain([
                    externalSchematic('@schematics/angular', 'ng-new', options),
                    mergeWith(apply(url('./files'), [
                    template({
                        ..options
                    }), ...

You execute the Angular schematic ng-new command and then add any new files that your application requires that aren't part of the Angular default, e.g., a new component file that your application requires, overwrite any files in the Angular default where you need to substantially change the behavior, e.g., an updated app.module.ts that imports your custom component, or modify any files that differ slightly, e.g., add a new dependency to package.json (As a general rule, I will modify JSON files and overwrite .ts files.

Regarding your question about the file tree, it will be empty when the rule starts, have the default set of ~30 Angular files after the ng-new schematic executes, and have your configured application when the remaining rules in your chain have executed. You can chose to name this schematic however you please in collection.json, either calling it ng-new, which will hide the default Angular behavior or ng-new-custom, which will allow it to to live side-by-side with the default new application schematic.

One other schematic behavior I've found to be helpful is to specify in the schematic collection.json that the schematic extends the Angular schematic, i.e., "extends":"@schematics/angular" and then in the rule chain for the new application, modify angular.json to use my custom schematic as the default. In my experience, this creates a more unified and seamless experience for peers who aren't as familiar with specifying a schematic collection.

like image 66
ericksoen Avatar answered Nov 04 '25 08:11

ericksoen