π§ΈοΈ Lab 13 - Workspace Plugins and Generators - Intro
May 31, 2023 Β· View on GitHub
β° Estimated time: 20-25 minutes
π Learning outcomes:
- Understand what an internal plugin is
- Understanding generators in internal plugin, including:
- How to create them
- How to invoke them
- How to use one to simplify usages of other, more powerful generators
ποΈββοΈ Steps :
We just learned how important tags are. But we don't want to constantly and manually
have to maintain them. In this workshop, we'll create an internal plugin called
internal-plugin, and create a library generator for this plugin that knows
about the folders in our workspace and automatically tags the new project with a correct
scope and type tag.
-
Use the
@nx/plugin:plugingenerator to generate a new plugin calledinternal-plugin.
Make sure that theminimaloption is set.
-
Use the
@nx/plugin:generatorgenerator to generate a new generator calledutil-lib.
-
Inspect the files that got generated and then commit everything.
-
Try to run your generator (you can append
--dry-runto avoid reverting using Git)π³ Hint
Run
npx nx listto see your newly created plugin in the list of installed plugins:% npx nx list > NX Local workspace plugins: @bg-hoard/internal-plugin (generators)Run
npx nx list @bg-hoard/internal-pluginto see our generator details:% npx nx list @bg-hoard/internal-plugin > NX Capabilities in @bg-hoard/internal-plugin: GENERATORS util-lib : util-lib generatorYou call generators from this local plugin using the same syntax you would with any plugin:
nx generate <plugin name>:<generator name> [...options]β οΈ The code we generated creates a very bare-bones new library, with only a
project.jsonand asrc/index.tsfile; you will see these files created if you run it. You can use Git to undo those changes (hence why it's recommended to commit before running a generator).
-
We can call other generators inside of our custom generator. Import the
@nx/js:librarygenerator and call it inside of the default exported function oflibs/internal-plugin/src/generators/util-lib/generator.tsπ³ Hint
import { libraryGenerator } from '@nx/js'; export default async function (tree: Tree, schema: UtilLibGeneratorSchema) { await libraryGenerator(tree, schema); // ... } -
In
libs/internal-plugin/src/generators/util-lib/generator.tstry to make itconsole.log()the value of the--nameproperty you passed to it (can use--dry-runagain to test it)
-
Now that we're more familiar with how command line options are passed to the generator, let's revert all locally generated files, as we're about to start making actually useful changes to the generator.
-
The generator should prefix any name you give to your lib with
util-For example:
nx generate @bg-hoard/internal-plugin:util-lib dates- Should generate a lib with the name
util-dates
β οΈ You can keep trying out your changes safely with the
--dry-runflag.οΈ
-
Add a new property to its schema called
directory. It should have only 3 possible values:"store", "api", "shared". If you do not pass--directoryas an option when invoking the schema it should prompt the user to select from the 3 different values (similar to when you got asked about which CSS framework to use when creating Angular libs).π³ Hint
-
The generator should generate the lib in the directory you pass to it.
-
Because it's a
utillib, it should automatically be generated with thetype:utiltags.π³ Hint
Consult the
@nx/js:libdocs for possible options you can pass to it.
-
We also need to add
scopetag to it. We can use thedirectoryvalue for this, since it signifies our scope.
-
Before testing your changes, remember to commit them, in case you need to revert locally generated files again.
-
Invoke your generator and test if the above requirements work
- Let's give it the name
notifications - Select
apias the directory
- Let's give it the name
-
Let's add some functionality to the lib you just created:
- In
libs/api/util-notifications/src/lib/api-util-notifications.ts - Add:
export function sendNotification(clientId: string) { console.log('sending notification to client: ', clientId); }
- In
-
Now try to import the above function in
apps/api/src/app/app.service.ts- Try to lint all the apps
- It should work because everything is in the
apiscope
-
Try to import it in
apps/store/src/app/app.component.ts- It should fail because it's not within the same scope
- It should fail because it's not within the same scope
-
In
libs/api/util-notifications/src/lib/api-util-notifications.ts- Try to import a
featurelib - It should correctly fail because the type hierarchy is not respected
- Try to import a
-
BONUS - A
generator.spec.tsfile was created when we ran our generator. Try writing some meaningful tests for this generator.
-
BONUS BONUS - try to create another similar generator, but for "feature" libs.
-
Commit everything before the next lab.
πIf you get stuck, check out the solution