๐งต Lab 14 - Workspace Plugins and Generators - Modifying files
May 31, 2023 ยท View on GitHub
โฐ Estimated time: 25-35 minutes
๐ Learning outcomes:
- Explore some more advanced, real-world usages of generators
- Understand how to modify existing source code with generators
๐๏ธโโ๏ธ Steps :
-
Generate another generator called
update-scope-schema
-
As a start let's make it change the
defaultProjectfromstoretoapiin ournx.jsonfile:๐ณ Hint
- Refer to the docs
- Use this utility:
import { updateJson } from '@nx/devkit';
- As always, the answer is in the the solution. Try a few different approaches on your own first.
โ ๏ธ When you run the above, it might complain that you haven't supplied a
name. Since we don't need this property in the generate, you can remove it from the schema.
-
Now that we had some practice with the
updateJsonutil - Let's build something even more useful:- When large teams work in the same workspace, they will occasionally be adding new projects and hence, new scope tags
- We want to make sure that scope tags specified in our
util-libgenerator are up to date and take into account all these new scopes that teams have been adding - We want to check if there is a new scope tag in any of our
project.jsonfiles and update our generator schema - We can use the
getProjectsutil to read all the projects at once.
โ ๏ธ You can use the function provided in the Hint to extract the
scopes๐ณ Hint
function getScopes(projectMap: Map<string, ProjectConfiguration>) { const projects: any[] = Array.from(projectMap.values()); const allScopes: string[] = projects .map((project) => project.tags // take only those that point to scope .filter((tag: string) => tag.startsWith('scope:')) ) // flatten the array .reduce((acc, tags) => [...acc, ...tags], []) // remove prefix `scope:` .map((scope: string) => scope.slice(6)); // remove duplicates return Array.from(new Set(allScopes)); }
-
It's good practice to have your generator run your modified files through Prettier after modifying them. You might already have this, but just in case you removed it:
- Use
import { formatFiles } from '@nx/devkit'; awaitthis at the end of your generator
- Use
-
The
util-libgenerator also has aschema.d.tswith a Typescript interface that should be updated. For modifying files that are not JSON we can usehost.read(path)andhost.write(path, content)methods.โ ๏ธ You can use the function provided in the Hint to replace the
scopes๐ณ Hint
function updateSchemaInterface(tree: Tree, scopes: string[]) { const joinScopes = scopes.map((s) => `'${s}'`).join(' | '); const interfaceDefinitionFilePath = 'libs/internal-plugin/src/generators/util-lib/schema.d.ts'; const newContent = `export interface UtilLibGeneratorSchema { name: string; directory: ${joinScopes}; }`; tree.write(interfaceDefinitionFilePath, newContent); }
-
So we can test our changes, create a new app and define a scope for it.
๐ณ Hint
nx g app videos --tags=scope:videos
-
Run your generator and notice the resulting changes. Commit them so you start fresh on your next lab.
-
BONUS - As a bonus, if project doesn't have
scopetag defined, we will assume it's the first segment of the name (e.gadmin-ui-lib->scope:admin) and we will go ahead and set one for it. Now run the generator again and see what changed.
-
BONUS BONUS - use a tool like Husky to run your generator automatically before each commit. This will ensure developers never forget to add their scope files.
-
BONUS BONUS BONUS - create a test to automate verification of this generator in
libs/internal-plugin/src/generators/update-scope-schema/generator.spec.ts. **This will be particularly difficult, as you'll need to create a project with the actual source code of yourutil-libgenerator as part of the setup for this test. (Check the solution if you get stuck!)
๐If you get stuck, check out the solution