In a plain normal Next.js application you would place your markdown processing logic somewhere within a folder insider your Next application. We could do the very same in an Nx monorepo, however, we get much more benefits by moving it into a dedicated library in the libs
folder.
Nx workspace libraries allow you to nicely encapsulate your functionality as well as to easily share it with other apps that might potentially live in our workspace. In this lesson, we learn how to generate a new library with Nx generators and how to import the library into our Next.js application.
Prefer to read along as well? Here's the accompanying article.
Instructor: [0:00] So far, we are able to read all the articles in that Articles folder, pass them out here, take the file name and pass that on to our Page component, which then just visualizes the filename itself.
[0:13] Obviously, the end goal, what we want to do, is actually parse this markdown document, separate it out into the front matter piece and the actual content, and then obviously convert that content into HTML and render it within our Page component.
[0:27] Normally, what you would do is create that logic either inside that Page component, which is probably not a great idea, or add the logic inside your Next.js application, because in a normal setup, that is what you have.
[0:41] In an Nx application, or an Nx workspace or monorepo scenario, you have multiple applications, potentially, and then you might have multiple libraries down here. The suggestion is to put as much logic as possible into that Libs folder, such that the applications are really just a container that links to various libs down in that Libs folder and, basically, binds together a set of functionality, for then being deployed to some production site.
[1:09] Similarly, in our case, the whole logic of parsing the markdown and rendering it as HTML is not really something that is tied to our specific use case of that blog article or portfolio site. Maybe tomorrow, we are adding some other application in here, and we might want to use the very same logic there as well.
[1:27] What I'm going to do here is generate such a library. I'm using Nx console because it's the easiest way to generate that, especially if you don't know the command. If I type in library, I can filter all these generators to just the library generators.
[1:41] Here, you have three different options. The first two are more specific to the actual framework, so either Next or React. What it does is simply preset your library setup, your tsconfig, and babel configuration, such that it best fits either Next or React.
[1:56] The workspace library, on the other hand, is more bare-bones, in the sense that it sets you up with the bare minimum you need for creating TypeScript libraries and TypeScript code. We are going with that because we don't have any components or Next.js-specific things living in there. We're calling this Markdown. I can leave all the other settings as is for now.
[2:16] You can see here, we get a preview of what would be generated when the executor runs. Notice, you can also see the command that is executed here. You could copy that, and later on, reuse that by pasting it into the console. You can also copy it by clicking this button here.
[2:33] Let's click the Run button, which now would actually generate the code for us. If you go back into our file structure here, we see now the library, which is that Markdown library, which has already some pre-generated code for us in here. Let's go to our Page component and look at the implementation. We get the path of our file, which we want to parse in the end from that slug. This is being passed to our getStaticProps.
[2:59] Here, we would want to have two different functionality. First of all, we want to parse the content of our Markdown and separate it into the front matter and content. Then, as the second piece, we want to convert the Markdown content into HTML and then pass everything onto our Page component.
[3:19] Let's create these two methods in our actual library for the Markdown parsing. First of all, we can export here, const getParsedFileContentBySlug. We would get here, the file name, which is a string. Also, we would not need the actual Post Path, which is also a string, to be able to read the file.
[3:41] Once we have that information, we can then implement that and return the result. For now, let's just create a skeleton and return NULL here. Similarly, here, let's call this renderMarkdown, make it a bit more explicit. This one just returns Markdown for now, so we can leave this as is.
[3:57] Both of these functions are being exported directly by that index.ts file. As you can see here, the main libmarkdown file is being exported. This is basically the public API of our library. We can have hidden things within our library, which might be implementation details, which we don't export here, and the export orders, which we might want to reuse outside.
[4:17] The interesting part is also, that once we have generated that library, we also got a new path mapping generated in that tsconfig.base by Nx. You can see here that this namespace, which is basically a composition of our workspace prefix -- which is yuri.dev in my case -- /, an extra library name. That maps, then, to the index.ts file of our library which we've created.
[4:40] This allows us, in our Page component, for instance, to import these methods. I can go ahead here and from yuri.dev.markdown, can now import the actual getParsedFileNameBySlug, and the renderMarkdown function. With both of those imported, we can go ahead and reuse them.
[5:00] Basically, here, I am having then the article, Markdown Content, which I get from that parsedFileContentBySlug, which we just created, which takes the perms.slug, which is basically the file name as an input, and also needs that Post Path. That would return me the content.
[5:19] Then, once I have that content, I can also then render the HTML by invoking the renderMarkdown function and pass in the article, markdown content into this here.
[5:31] Now, obviously we need to see, once we implement a specific function, what the return type of this is. Basically, a return type that just gives us the content, would then be passed on to that renderMarkdown function.