Once we finish our portfolio site, hopefully, one of the main activities we'd be doing with it is to create new content. Thus we want to automate the creation of a new blog article, which includes the creation of a new MDX file in the _articles
folder as well as initialize the article's front matter with the title, author, and creation date.
Nx has a powerful concept, called generators. While many of them come already built into the Nx plugins (e.g. @nrwl/next
, @nrwl/react
,...), we can also define our own, Nx Workspace Generators. This is exactly what we leverage to scaffold new blog articles.
Prefer to read along as well? Here's the accompanying article
Instructor: [0:00] so, one of the strength points of Nx is definitely its generators. When we started creating our Nx workspace right at the very beginning, that was a generator that actually scaffolded out the whole Nx workspaces. It internally launched an auto-generator that created for us the Next.js application with all the setup.
[0:19] We've used a couple of generators to create our various libraries in here. We mostly use them through Nx console. For instance, when we created a library, we choose the library generator. If we want to create a new application, we just can choose application, and we get the options for creating Next, React, and Web applications, based on what we have, basically, installed.
[0:40] The built-in generators is just one way of allowing you to get a lot of automation out of an Nx workspace. It becomes even more interesting if you can create your own generators to automate your local workspace.
[0:54] That is not only useful for our specific scenario here, but also in a bigger enterprise scenario where you might want to generate, for instance, your Next.js components in a specific way. You could totally create your own generator and generate them out as you prefer to have them within your company.
[1:10] In the case of our simple portfolio website what we might want to create is a generator to set up our blog articles. As we create a new blog article, we might want to generate out here, the title, the date, the author, and maybe even some text initially, that gets us very quickly started to write a new article.
[1:29] These generators that are local to workspace are called workspace generators. Let's create a new one. We can go and generate a new workspace generator by using the @nrwl/workspace package, and in there, the workspace-generator. We call it new-article.
[1:46] If we hit Enter, what you will see is, in that Tools folder, it will set up a new generators folder. In there, we get that new-article folder. This comes in two pieces. There's an index.ts file, which is the actual logic of the generator, and then there's the schema file, which defines the metadata of the generator itself.
[2:05] Let's first start with this schema here. The main point here is the properties part. We definitely want to have the name of the article. Let's call it, maybe, title. Here, you can see, by specifying the default here and the argv, which means that the first parameter that is being passed to our generator, on the comment line, would be this title.
[2:28] We also want to make sure that we have a title, so this would be a required property of our generator. Next, we want to create an author. This, again, is of type string. We also might want to add a description. Finally, we also might want to have an excerpt. As a required parameter, we have the title, and we also might want to make sure that we have an author.
[2:52] This is the metadata. Whenever you invoke a generator, Nx uses this metadata to validate the parameters that you to pass to the generator when you invoke it. Whenever you pass, for instance, for a title, a Boolean value, rather than a string, it would complain. If you miss one of the required parameters, it will complain as well.
[3:09] Let's go to the actual implementation of the generator and see what we have here. We have some predefined configuration set up already, that shows an example of invoking an existing library generator within here.
[3:21] This is a useful example if you want to compose different generators together. It shows how you can format the files with [inaudible] within your workspace. Also, if you need, how you can launch and install packages tasks, if, for instance, your generator adds new Node packages.
[3:34] In our case, we don't really need all of this. The only thing we want to keep maybe, is the formatting of the file, since we definitely want to generate new files. That's the first task. Whenever we create a new blog article, we want to generate a new file in here.
[3:50] Let's get started here by creating a Files directory within our new generator, and let's create a new file. If we use two underscores, that denotes a variable name within the file name. Here, let's call this normalizedtitle.mdx, because we want to generate an MDX file.
[4:09] As the content here, let's copy in here some example. Obviously we want to have these placeholders replaced with whatever we pass in as a parameter. Nx generators use AJS as their templating language. It is a simple, yet very powerful language.
[4:25] In order to have placeholders, what we need here is to use the following syntax. We would have here a title, we would have here the excerpt, creation date, and finally, also the author. Below here, we can add some content. With that, we have our template which we want to generate. We need to go back into our generator and actually use that template.
[4:49] Most of the utilities come directly from that @nrwl/devkit package, which comes exported directly from Nrwl. Most of the time, when we compose our generators, we can just use functions from that @nrwl/devkit.
[5:01] For instance, when we are going to generate files, there is a function already handy in there, which is called generateFiles. That takes that tree object. These three object is a special object, which our generators have, which we can use to issue all of our read and write operations against.
[5:20] The reason is that the generators will only really write to the physical file system if we have a successful run. Moreover, when we pass the dry run flag to the generator, it will only simulate the run, which will just happen against this tree object.
[5:33] We give it the path of where the files are in our file system. We want to use the joinPathFragments, and use the current directory and the files folder, where we have based our template. Next, we want to give it a path where we want to have our files generated, which is the Articles folder within our workspace.
[5:54] Finally, we have the variables that we pass, that should be replaced in our template. Variables passed in here would be then, for instance, used to replace the name of our file's name here. Moreover, within a template, it will be used for the title, excerpt, creation date, and so on.
[6:09] The things we have to pass in here is, first of all, a title. We can get that as a parameter. Let's maybe also type our schema options here, which are being passed in here. Let's call these NewArticleSchemaOptions, which gets a title, it gets an author, it gets an excerpt. Excerpt is optional.
[6:28] The schema.title gets passed in here. Then we have the author, we have the excerpt, or just an empty string if that is not defined. Finally, also, we need to have a valid file name that will be replaced here with that normalized title. For that, we need to make sure that the passed-in title is a valid file name.
[6:46] Again, we can use the names function that comes from the @nrwl/devkit where we pass in the schema.title. That has a handy properties attached on it, which has also a file name among them, which you can use in this case. Then, we have the creation date where we can just define new dates. At the moment, we generate this and pass it in this way. With that, we generate our files.
[7:09] Finally, we will run the formatting that will make sure that all the files in our Nx workspace that have been touched are formatted properly. That we have set up everything, let's try and generate a new article. We can now run this by using, nx workspace-generator new-article. We give it a title, my-generated-article.
[7:28] Then, let's hit enter just to test what would happen. Here, you can see it already validates the fact that we forgot the author to pass in. This is based on a schema that we have seen earlier. We need to make sure we pass in the author here, which is Yuri. We can also use the dry run for the first run to see what would get generated.
[7:47] Here, in the dry run, we can see that we got an error in what we pass to our template. It expects an excerpt, but rather, here we specified expect. Let's try again. We can see it would create, inside that article, a new my-generated-article.
[8:02] We can remove the dry run and have this article generated. If you open it up, we can see that we have the title in there. We don't have an excerpt because we didn't pass any. We have a date, which we just generate on-the-fly while generating a new article here, and we have the author set properly.
When I tried to use command create-article, I've got the error: TS5042: Option 'project' cannot be mixed with source files on a command line.