NX Generators

Wed Jan 15 2025 - 7 min read

Using NX generators to enforce architectural patterns

NX Generators

NX

angular

architecture

Streamlining Your Workspace with NX Generators: Crafting a Custom Solution for Consistent Architecture

In the ever-evolving landscape of software development, maintaining a consistent architecture and folder structure across projects can often pose a challenge. As projects grow, gaps in folder structures and architecture practices can lead to messy codebases that are hard to navigate and maintain. Enter NX, a smart and extensible build framework that provides powerful development tools for Angular, React, and more. Today, I’ll guide you through the process of creating a custom NX generator for your Angular monorepo to ensure a consistent architecture and folder/file structure.

What Are NX Generators?

NX Generators allow you to automate repetitive tasks, enforcing consistent patterns and reducing manual overhead. They are especially useful in creating standardized libraries and applications within your monorepo, injecting best practices into developer workflows.

Why Create a Custom NX Generator?

Custom NX Generators provide several benefits, including:

Setting Up a Custom NX Generator

Let’s dive into creating a custom NX generator tailored to establish consistent architecture within our Angular project libraries. Below, you’ll find a generalized walkthrough based on the generator I’ve successfully implemented in my monorepo.

Core Components of the Generator

  1. Setup Default Options:

    function setDefaultOptions(options: LibraryGeneratorSchema) {
      options.linter = Linter.EsLint;
      options.unitTestRunner = UnitTestRunner.Vitest;
      options.style = 'scss';
      options.buildable = true;
      options.publishable = false;
      options.changeDetection = 'OnPush';
      options.standalone = true;
      options.flat = true;
      options.setParserOptionsProject = true;
      options.projectNameAndRootFormat = 'as-provided';
      options.skipPackageJson = true;
    }

    This function initializes the default settings for generated libraries, ensuring consistency across all projects.

  2. Dynamic Directory Management:

    function cleanDirectoryPath(options: LibraryGeneratorSchema) {
      // Normalize directory paths
      options.directory = options.directory.replace(/\\/g, '/').replace(/^\/+|\/+$/g, '').replace(/\/+/g, '/').replace(/\s/g, '_');
    }

    A clean directory path is crucial for avoiding path issues and achieving a predictable library layout.

  3. Types and Tags Implementation:

    const allLibraryTypes: LibraryType[] = ['feature', 'ui', 'data-access', 'util'];

    By categorizing libraries into distinct types, this generator helps define clear boundaries and responsibilities within your codebase.

  4. Project Configuration and Generation:

    for (const type of options.type) {
      await libraryGenerator(tree, options);
      const projectConfig = readProjectConfiguration(tree, options.name);
      const libraryRoot = projectConfig.root;
    
      // Generate relevant library type files
      generateFiles(tree, joinPathFragments(__dirname, `./files/${type}`), joinPathFragments(libraryRoot, 'src/lib'), {
        template: '',
        fileName: baseFileName,
        className: className,
      });
    }

    This segment ensures that libraries are generated with pre-defined configurations, including types and styles, while facilitating custom files based on library types.

  5. Post-Generation Enhancements:

    await formatFiles(tree);

    Applying formatting automatically to ensure all generated code meets styling guidelines.

Reusing with NPM Packages

Once you’ve successfully implemented and tested your custom generator, you can further abstract its benefits by publishing the setup as an NPM package within your GitHub registry. This makes the generator reusable across different projects, promoting best practices without redundancy.

Conclusion

Whether you’re managing a small project or an extensive codebase, consistency and automated workflows will always enhance your productivity and maintainability. NX Generators offer a robust way to achieve this, with the flexibility to tailor the architecture to your needs. By following the steps above, you can create a streamlined development environment that eases your team’s workload and ensures code quality.