today, we're going to talk about library and Nx (...and much more)

What is Nx?

What is Nx?

A task runner

What is Nx?

A task runner

that can orchestrates and executes tasks efficiently

What is Nx?

A task runner

that can orchestrates and executes tasks efficiently

What is Nx?

A task runner

that can orchestrates and executes tasks efficiently

because it knows about your projects

What is Nx?

It is also a collection of tools

What is Nx?

It is also a collection of tools

Disclaimers

...or pre-talk FAQ

Disclaimers

...or pre-talk FAQ

1. The demo is in Nx 19. What about Nx 20?

Disclaimers

...or pre-talk FAQ

1. The demo is in Nx 19. What about Nx 20?

2. The demo uses Angular. Why?

Libraries with Nx

Angular Libraries w/ Nx

Chau Tran

twitter.com/@nartc1410

github.com/nartc

Agenda

  • Create an Nx Workspace
  • Create an Angular library
  • Create a playground application
  • Entry Points
  • Custom Plugin
  • Release
  • Optimize the library workspace
  • Documentations

Create Nx Workspace

Create Nx Workspace

npx create-nx-workspace <name_of_workspace>

Create Nx Workspace

npx create-nx-workspace <name_of_workspace>
	--package-manager=npm,yarn,pnpm

Create Nx Workspace

npx create-nx-workspace <name_of_workspace>

Create Nx Workspace

Create Nx Workspace

npm i -D @nx/angular

Create Angular Library

Create Angular Library

npx nx generate @nx/angular:library libs/core
	--publishable
    --import-path="@js-day-demo/core"
    --standalone

Create Angular Library

Demo

Create Angular App

Create Angular App

npx nx generate @nx/angular:app apps/playground

Create Angular App

Demo

Entry Points

Entry Points

@angular/core

Entry Points

@angular/core

@angular/core/testing

Entry Points

@angular/core

@angular/core/testing

https://unpkg.com/browse/msw@2.5.1/package.json

Entry Points

npx nx generate @nx/angular:entry-point

Entry Points

Demo

Custom Plugins

Custom Plugins

npx ng add <name-of-library>

Custom Plugins

npm i -D @nx/plugin

Custom Plugins

npx nx generate @nx/plugin:plugin libs/plugin

Custom Plugins

npx nx generate @nx/plugin:generator

Custom Plugins

Demo

Release

Release

A smart release tool because it has information about the Project Graph

Release

Demo

Optimize the Workspace

Demo

Conclusion

Agenda

  • Angular library
  • Angular CLI
  • Nx
  • Example

Angular Library

Angular Library

Angular Library

Angular Package Format

Angular Library

https://angular.dev/tools/libraries/angular-package-format

Angular Library

Ensure seamless integration with other tools

Angular Library

Ensure seamless integration with other tools

Secondary Entry Points

Angular Library

Ensure seamless integration with other tools

Secondary Entry Points

@angular/core  -- @angular/core/testing

@angular/material  -- @angular/material/button

Angular Library

Ensure seamless integration with other tools

Secondary Entry Points

Optimization w/ Partial Compilation

Angular Library

Ensure seamless integration with other tools

Secondary Entry Points

Optimization w/ Partial Compilation

Angular Library

Ensure seamless integration with other tools

Secondary Entry Points

Optimization w/ Partial Compilation

Angular Library

Ensure seamless integration with other tools

Secondary Entry Points

Optimization w/ Partial Compilation

Angular Library

Angular CLI

Angular CLI

Angular CLI

ng new my-workspace --no-create-application

https://angular.dev/tools/libraries/creating-libraries/

Angular CLI

ng new my-workspace --no-create-application

Angular CLI

ng new my-workspace --no-create-application
cd my-workspace

Angular CLI

ng new my-workspace --no-create-application
cd my-workspace
ng generate library my-library

Angular CLI

ng build my-library

Angular CLI

ng build my-library

Angular CLI

Angular CLI

Secondary Entry Points

Angular CLI

karma

Angular CLI

karma

Angular CLI

Scalability

Angular CLI

Scalability

Angular CLI

Other details like docs, storybook, e2e ...

Angular CLI

Schematics

Angular CLI

Angular CLI

Nx

Nx

Nx

Monorepo

Nx

Monorepo

nx build
nx serve
nx test

CLI

Nx

Monorepo

nx build
nx serve
nx test

CLI

Performance

Nx

Nx

npx create-nx-workspace@latest my-nx-workspace 

Nx

npx create-nx-workspace@latest my-nx-workspace 
		--preset=apps # we'll set up Angular later

Nx

npx create-nx-workspace@latest my-nx-workspace 
		--preset=apps # we'll set up Angular later
        --workspace-type=integrated # we'll use apps/libs convention

Nx

npx create-nx-workspace@latest my-nx-workspace 
		--preset=apps # we'll set up Angular later
        --workspace-type=integrated # we'll use apps/libs convention

Nx

npm install --save-dev @nx/angular

Nx

npx nx generate @nx/angular:library my-library

Nx

npx nx generate @nx/angular:library my-library --help

Nx

npx nx generate @nx/angular:library my-library
	--publishable 
    --import-path=my-library

Nx

npx nx generate @nx/angular:library my-library
	--publishable 
    --import-path=@my-library/core

Nx

npx nx generate @nx/angular:library my-library
	--publishable 
    --import-path=my-library

Nx

npx nx generate @nx/angular:library my-library
	--publishable 
    --import-path=my-library
    --unit-test-runner=jest

Nx

npx nx generate @nx/angular:library my-library
	--publishable 
    --import-path=my-library
    --unit-test-runner=jest
    --directory=libs/my-library

Nx

npx nx generate @nx/angular:library my-library
	--publishable 
    --import-path=my-library
    --unit-test-runner=jest
    --directory=libs/my-library

Nx

npx nx test my-library

Nx

npx nx test my-library

Nx

npx nx test my-library

Nx

Secondary Entry Points

Nx

Secondary Entry Points

npx nx generate @nx/angular:entry-point first-entry-point
		--library=my-library

Nx

Secondary Entry Points

npx nx generate @nx/angular:entry-point first-entry-point
		--library=my-library

Nx

Secondary Entry Points

npx nx build my-library

Nx

Secondary Entry Points

npx nx build my-library

Nx

Secondary Entry Points

npx nx build my-library

Nx

Secondary Entry Points

Nx

Secondary Entry Points

Nx

Secondary Entry Points

Nx

Secondary Entry Points

npx nx graph

Nx

Secondary Entry Points

npx nx graph

Nx

Secondary Entry Points

Nx

Secondary Entry Points

Each entry point should be a Nx "project"

Nx

Secondary Entry Points

Each entry point should be a Nx "project"

with their own lint and test targets

Nx

Secondary Entry Points

Nx

Secondary Entry Points

Nx

Secondary Entry Points

Nx

Secondary Entry Points

Nx

Secondary Entry Points

npx nx generate @nx/angular:entry-point first-entry-point
		--library=my-library

Nx

Secondary Entry Points

npx nx generate @nx/angular:entry-point first-entry-point
		--library=my-library

the plugin name

Nx

Secondary Entry Points

npx nx generate @nx/angular:entry-point first-entry-point
		--library=my-library

the generator

Nx

Secondary Entry Points

npx nx generate my-workspace-plugin:entry-point first-entry-point
		--library=my-library

What if?

Nx

Secondary Entry Points

npm i --save-dev @nx/plugin

Nx

Secondary Entry Points

npx nx generate plugin my-workspace-plugin 
		--directory=libs/my-workspace-plugin

Nx

Secondary Entry Points

npx nx generate plugin my-workspace-plugin 
		--directory=libs/my-workspace-plugin

Nx

Secondary Entry Points

npx nx generate generator entry-point
		--project=my-workspace-plugin
		--directory=libs/my-workspace-plugin/src/generators/entry-point

Nx

Secondary Entry Points

npx nx generate generator entry-point
		--project=my-workspace-plugin
		--directory=libs/my-workspace-plugin/src/generators/entry-point

Nx

Secondary Entry Points

npx nx generate generator entry-point
		--project=my-workspace-plugin
		--directory=libs/my-workspace-plugin/src/generators/entry-point

Nx

Secondary Entry Points

npx nx generate generator convert-to-project
		--project=my-workspace-plugin
		--directory=libs/my-workspace-plugin/src/generators/convert-to-project

Nx

Secondary Entry Points

Project == project.json exists

Nx

Secondary Entry Points

export async function convertToProjectGenerator(
  tree: Tree,
  options: ConvertToProjectGeneratorSchema
) {

  await formatFiles(tree);
}

export default convertToProjectGenerator;

Nx

Secondary Entry Points

export async function convertToProjectGenerator(
  tree: Tree,
  options: ConvertToProjectGeneratorSchema
) {
  const projectRoot = `libs/my-library/${options.name}`;

  if (!tree.exists(projectRoot)) {
    return logger.error(`Entry point ${options.name} does not exist`);
  }

  const isProjectJsonExist = tree.exists(`${projectRoot}/project.json`);
  if (isProjectJsonExist) {
    return logger.info(`Entry point ${options.name} is already a Project`);
  }


  await formatFiles(tree);
}

export default convertToProjectGenerator;

Nx

Secondary Entry Points

export async function convertToProjectGenerator(
  tree: Tree,
  options: ConvertToProjectGeneratorSchema
) {
  const projectRoot = `libs/my-library/${options.name}`;

  if (!tree.exists(projectRoot)) {
    return logger.error(`Entry point ${options.name} does not exist`);
  }

  const isProjectJsonExist = tree.exists(`${projectRoot}/project.json`);
  if (isProjectJsonExist) {
    return logger.info(`Entry point ${options.name} is already a Project`);
  }

  const projectConfiguration = readProjectConfiguration(tree, 'my-library');

  addProjectConfiguration(tree, `my-library/${options.name}`, {
    root: projectRoot,
    projectType: 'library',
    sourceRoot: `${projectRoot}/src`,
    targets: {
      test: {
        executor: '@nx/jest:jest',
        outputs: [`{workspaceRoot}/coverage/{projectRoot}/${options.name}`],
        options: {
          jestConfig: `${projectConfiguration.root}/jest.config.ts`,
          testPathPattern: [options.name],
          passWithNoTests: true,
        },
      },
      lint: {
        executor: '@nx/eslint:lint',
        outputs: ['{options.outputFile}'],
      },
    },
  });


  await formatFiles(tree);
}

export default convertToProjectGenerator;

Nx

Secondary Entry Points

import {librarySecondaryEntryPointGenerator} from '@nx/angular/generators';
import {formatFiles, Tree,} from '@nx/devkit';
import convertToProjectGenerator from "../convert-to-project/generator";
import {EntryPointGeneratorSchema} from './schema';

export async function entryPointGenerator(
  tree: Tree,
  options: EntryPointGeneratorSchema
) {
  await librarySecondaryEntryPointGenerator(tree, {
    name: options.name,
    library: 'my-library'
  });
  await convertToProjectGenerator(tree, {
    name: options.name
  })

  await formatFiles(tree);
}

export default entryPointGenerator;

Nx

Secondary Entry Points

Nx

Secondary Entry Points

Nx

Secondary Entry Points

Nx

Secondary Entry Points

npx nx generate convert-to-project first-entry-point
npx nx generate convert-to-project second-entry-point

Nx

Secondary Entry Points

Nx

Secondary Entry Points

Nx

Secondary Entry Points

Nx

Secondary Entry Points

Nx

Secondary Entry Points

Nx

Secondary Entry Points

Nx

Secondary Entry Points

Nx

Secondary Entry Points

Nx

Secondary Entry Points

Nx

Secondary Entry Points

npx nx graph --affected

Nx

Secondary Entry Points

npx nx graph --affected

Nx

Secondary Entry Points

Nx

Secondary Entry Points

Nx

Secondary Entry Points

Nx

Secondary Entry Points

Nx

Applications

Nx

Applications

Nx

Applications

Application to test your UI components

Nx

Applications

Application to test your UI components

An e2e application to test your test application

Nx

Applications

Application to test your UI components

An e2e application to test your test application

Nx

Applications

Application to test your UI components

An e2e application to test your test application

An application for your documentation

Nx

Applications

Application to test your UI components

An e2e application to test your test application

Nx

Applications

Application to test your UI components

An e2e application to test your test application

npx nx generate app test-app 
		--directory=apps/test-app
		--bundler=esbuild
        --e2e-test-runner=playwright
		--style=css # you can pick whatever
		# --...other options...

Nx

Applications

Application to test your UI components

An e2e application to test your test application

Nx

Applications

Application to test your UI components

An e2e application to test your test application

Nx

Applications

Application to test your UI components

An e2e application to test your test application

Nx

Applications

An application for your documentation

Nx

Applications

An application for your documentation

https://starlight.astro.build/

Nx

Applications

An application for your documentation

npm create astro@latest -- --template starlight

Nx

Applications

An application for your documentation

Nx

Applications

An application for your documentation

Nx

Applications

An application for your documentation

npx nx dev docs

Nx

Applications

An application for your documentation

npx nx dev docs

Nx

Applications

An application for your documentation

npx nx dev docs

Nx

Schematics

Nx

Schematics

ng add, ng update

Nx

Schematics

Nx

Schematics

npx nx generate plugin my-plugin --directory=libs/my-plugin

Nx

Schematics

npx nx generate plugin my-plugin --directory=libs/my-plugin
npx nx generate generator init 
  		--project=my-plugin 
        --directory=libs/my-plugin/src/generators/init

Nx

Schematics

npx nx generate plugin my-plugin --directory=libs/my-plugin
npx nx generate generator init 
  		--project=my-plugin 
        --directory=libs/my-plugin/src/generators/init

Nx

Schematics

touch libs/my-plugin/src/generators/init/compat.ts

Nx

Schematics

touch libs/my-plugin/src/generators/init/compat.ts

Nx

Schematics

{
  "generators": {
    "init": {
      "factory": "./src/generators/init/generator",
      "schema": "./src/generators/init/schema.json",
      "description": "init generator"
    }
  }
}

Nx

Schematics

{
  "generators": {
    "init": {
      "factory": "./src/generators/init/generator",
      "schema": "./src/generators/init/schema.json",
      "description": "init generator"
    }
  },
  "schematics": {
    "ng-add": {
      "factory": "./src/generators/init/compat",
      "schema": "./src/generators/init/schema.json",
      "description": "Init generator"
    }
  }
}

Nx

Schematics

npx nx generate migration rename-first-entry-point 
		--project=my-plugin
		--directory=libs/my-plugin/src/migrations/rename-first-entry-point

Nx

Schematics

npx nx generate migration rename-first-entry-point 
		--project=my-plugin
		--directory=libs/my-plugin/src/migrations/rename-first-entry-point

Nx

Schematics

{
  "name": "my-plugin",
  "$schema": "../../node_modules/nx/schemas/project-schema.json",
  "sourceRoot": "libs/my-plugin/src",
  "projectType": "library",
  "tags": [],
  "targets": {
    "build": {
      "executor": "@nx/js:tsc",
      "outputs": ["{options.outputPath}"],
      "options": {
        "outputPath": "dist/libs/my-library",
		...
      }
    },
    "test": {
	   ...
    }
  }
}

Nx

Schematics

{
  "name": "my-plugin",
  "$schema": "../../node_modules/nx/schemas/project-schema.json",
  "sourceRoot": "libs/my-plugin/src",
  "projectType": "library",
  "tags": [],
  "targets": {
    "build": {
      "executor": "@nx/js:tsc",
      "outputs": ["{options.outputPath}"],
      "options": {
        "outputPath": "dist/libs/my-library/plugin",
		...
      }
    },
    "test": {
	   ...
    }
  }
}

Nx

Schematics

{
  "name": "my-library",
  "version": "0.0.1",
  "peerDependencies": {
    "@angular/common": "^17.3.0",
    "@angular/core": "^17.3.0"
  },
  "sideEffects": false
}

Nx

Schematics

{
  "name": "my-library",
  "version": "0.0.1",
  "peerDependencies": {
    "@angular/common": "^17.3.0",
    "@angular/core": "^17.3.0"
  },
  "sideEffects": false,
  "generators": "./plugin/generators.json",
  "schematics": "./plugin/generators.json",
  "nx-migrations": {
    "migrations": "./plugin/migrations.json"
  },
  "ng-update": {
    "migrations": "./plugin/migrations.json"
  }
}

Nx

Schematics

{
  "name": "my-library",
  "$schema": "../../node_modules/nx/schemas/project-schema.json",
  "sourceRoot": "libs/my-library/src",
  "prefix": "lib",
  "projectType": "library",
  "tags": [],
  "targets": {
    "build": {
		...
    },
    "test": {
		...
    },
    "lint": {
		...
    }
  }
}

Nx

Schematics

{
  "name": "my-library",
  "$schema": "../../node_modules/nx/schemas/project-schema.json",
  "sourceRoot": "libs/my-library/src",
  "prefix": "lib",
  "projectType": "library",
  "tags": [],
  "targets": {
    "package": {
      "executor": "nx:run-commands",
      "options": {
        "commands": [
          "nx build my-library",
          "nx build my-plugin"
        ],
        "parallel": false
      }
    },
    "build": {
		...
    },
    "test": {
		...
    },
    "lint": {
		...
    }
  }
}

Nx

Schematics

Nx

Release

Nx

Release

{
  ...,
  "release": {
    "projects": [
      "my-library"
    ],
    "version": {
      "preVersionCommand": "nx package my-library"
    },
    "releaseTagPattern": "{version}",
    "conventionalCommits": {}
  }
}

Nx

Release

{
  ...,
  "release": {
	"version": {
      "generatorOptions": {
        "packageRoot": "dist/{projectRoot}",
        "currentVersionResolver": "git-tag"
      }
    }
  },
  "targets": {...}
}

Nx

Release

npx nx release --first-releast

Nx

Release

npx nx release --first-releast

Nx

Release

npx nx release --first-releast

Nx

Release

npx nx release --first-releast

https://monorepo.tools/conf

https://monorepo.tools/conf

https://github.com/ngxtension/ngxtension-platform

Structure

Structure

nx g @nx/angular:lib ngxtension

Structure

nx g @nx/angular:lib ngxtension
nx g @nx/plugin:plugin local-plugin
nx g @nx/plugin:plugin plugin

Structure

nx g @nx/angular:lib ngxtension
nx g @nx/plugin:plugin local-plugin
nx g @nx/plugin:plugin plugin
nx g @nx/plugin:plugin local-plugin

Structure

nx g @nx/angular:lib ngxtension
nx g @nx/plugin:plugin local-plugin
nx g @nx/plugin:plugin plugin
nx g @nx/plugin:plugin local-plugin
npm create astro --template=starlight

Structure

Structure

nx g @nx/angular:entry-point

Structure

nx g @nx/angular:entry-point

Thank you

nx angular library

By Chau Tran

nx angular library

  • 260