I'm trying to replace an old angular-devkit schematic with a new nx generator using nx-devkit.
I'm following the guide here: https://nx.dev/generators/composing-generators
We should be able to await the nx generators, however when I do, the generator does not complete before await finishes.
Expected:
this should happen before
...application is created
this should happen after
Actual:
this should happen before
this should happen after
...application is created
export default async function(tree: Tree, schema: SchemaOptions) {
logger.info('this should happen before');
await applicationGenerator(tree, {...}); // this returns before the files are created
logger.info('this should happen after');
}
This is probably too late to help the OP, but as I recently ran into a similar problem myself and searching for an answer led me here, I hope this will help someone in the future.
The general problem is this: We want to use an existing generator that creates some files, for example the @nx/js library generator. But following that creation we want to then do something further with those files, within the same run. The problem, as the OP and I discovered, is that the files are not immediately written to disc. This is intentional and happens for two reasons:
This "transaction" behavior is very desirable, so the authors of Nx have built that in. The generators don't interact directly with the file system, unless they do so by directly calling on Node's
fs
module methods, which would not be advisable. Instead what happens is the following:tree.write
or by calling other methods that do so. These are all stored for later processing.It has nothing to do with the await, which is needed anyway just so that the library generator actually queues these file changes up, but all to do with the fact that you are interacting with a virtual file system tree.
You have two ways to work around it:
tree.read
to read a file, even if that file only exists virtually at the time. The virtual tree will return either the pending changes if it is a newly created or updated file, or else it will fall back to the actual file on the real file system. You can similarly make changes to a "pending" file this way. In my instance I wanted to add to the contents of one of the files created by the libraryGenerator. So I had to usetree.read
to read the pending contents, then combine those with my new contents before writing it all back withtree.write
.flushChanges
to immediately commit the changes. This prevents the dry-run functionality offered by the system, and would also still create those files even if the generator throws an error later on. Neither of these behaviors would be expected from users of your generator.