In this workshop, I’ll first show you how to create a new project in a headless CMS, fill it with data, and use the content in your project. Then, we’ll spend the rest of time in code, we will:
- Generate strongly typed models and structure for the fetched content.
- Use the content in components
- Resolve content from rich text fields into React components
- Touch on deployment pipelines and possibilities for discovering content-related issues before hitting production
You will learn:
- How to work with content from headless CMS
- How content model can be leveraged to generate TS types and what benefits it brings to your project
- How not to use string literals for content in code anymore
- How to do rich text resolution into React components
- How to minimize or avoid content-related issues before hitting production
This workshop has been presented at React Summit 2022, check out the latest edition of this React Conference.
FAQ
TypeScript is a programming language that builds on JavaScript by adding static type definitions. In this workshop, TypeScript is used to show participants how to work with content in TypeScript and React components, particularly focusing on how to integrate and manipulate content from a Headless CMS in a TypeScript-based project.
Participants can clone the project repository to their local machine, install dependencies, and follow the steps demonstrated by the facilitator. The workshop also includes live coding sessions, and participants are encouraged to code along and ask questions in real-time.
A Headless CMS is a content management system that provides a way to author content, but instead of having a built-in front-end, it provides content via an API. In this workshop, a Headless CMS is used to manage and import content into a new project, demonstrating how developers can leverage such systems for more flexibility and control over their content delivery.
The workshop covers several tools and frameworks, including Next.js, TypeScript, React components, and the Headless CMS used for content management. It focuses on using these technologies to build dynamic web applications efficiently.
The workshop is recorded, allowing participants to revisit any part of the session later. Additionally, the pace is kept slow to accommodate all participants, and direct assistance is available during the workshop to address any issues or questions that arise.
Participants will import content into a new project, create and manipulate a project in the CMS, and work extensively with code, particularly focusing on Next.js and TypeScript. They will also generate TypeScript models from content types and learn how to fetch and resolve content in Next.js.
Let's start with the workshop, importing content into a new project, working on the content, and spending most of the time in code. We'll discuss the content model and component limitations, generating TypeScript models, fetching content, and adjusting components. We'll also cover creating slug pages, implementing getStaticPaths, rendering landing pages, and resolving content items as React components. Additionally, we'll address the implementation of the nav component and deployment pipelines for tracking content model changes.
Let's start with the workshop. We'll import content into a new project, work on the content, and spend most of our time in code. I'll show you the implementation in Next.js and how to generate TypeScript models from content types. Then we'll fetch the content in Next.js and resolve rich texts into React components. We'll also discuss how to implement deployment pipelines to avoid production errors. First, clone the project repository and install the dependencies.
Let's go! Let's start with the workshop. First of all, let me greet you all here. It's a great pleasure for me to be here to show you some things TypeScript-related. I'm joining you from Czech Republic, Brno, where we have our headquarters. I'm Andrey, I'm a developer evangelist for content. We are a vendor of Headless CMS. I'm sure you know the company. I will show you a bit of the CMS as we work on the content and as we go through the workshop, but today is not a product pitch, I want to show you how to work with content in TypeScript and React components, right?
So, first of all, a little bit of housekeeping. The workshop is being recorded, so you can get to anything back in time, if you miss something, or if you get stuck on something. I'll try to go slow. But you can always get back or you can just ask me directly if something's not clear.
What we're going to do, and, oh, I hope you see my screen. Yeah, I think you do. So, what is the timeline of the workshop today? I know it's designed for three hours. I always try to be a bit quicker because it's really hard to keep your concentration for that long. What we're going to do in this workshop is first we're going to import content into a new project. So, we're going to create a new project in the CMS. We are going to import some content in there. If you're signed up for content, that's great. I'll show you how to import it. If you're not signed up and if you don't want to sign up, that's also fine. I'll give you the project ID of my project and you can work with the content that way anyway. So, you don't have to sign up anywhere. We're probably going to work a bit on the content. But not so much. We're going to spend most of our time in code. So, that should be fine. Then I'm going to show you the implementation in Next.js. I'm going to use Next.js because it's, to be honest, the closest to my heart currently. We have our whole website built with Next.js. I really like its flexibility and ease of use. So, I'm going to use Next.js, but the principles can be used in any framework if you're using Vue.js or if you're using Gatsby. Gatsby depends, but I think they support TypeScript as well now, so it should be good as well. So, I'll show you how the code looks like. I'll show you how the website looks like. And then we're going to move on to actually generating TypeScript models from content types. So, I'll show you how to bring the content from the headless CMS into your project and generate not only the TypeScript models, but also the project structure. That means code names and all the other things. Then I'll show you how to fetch the content in Next.js. That's quite straightforward as we have an SDK in TypeScript. And then I'll show you how to resolve rich texts into React components. That's what it's all about. To tie the React components to their respective content models. So, it's easy to maintain everything. And at the end, there is a little place for discussion how to implement deployment pipelines in a way that the content changes on the headless CMS side don't cause any production errors. So, we've implemented a way to check the content model with every build so that you can avoid the production errors in terms of missing content or misconfigured content to a minimum. So, that's about the workshop timeline. Yeah. And yeah, let's get to it.
First, we're going to import the stuff in the CMS. Then we're gonna open Visual Studio Code and stay there for the rest of the workshop. So, first of all, I'm gonna do that, too. The first step for you is to clone the project repository. Now, I don't want to give you any blank spots where you would be working on your own. I prefer actually going rather slowly and let you work on the tasks as I'm speaking. So, feel free to just do the steps as I'm doing them. And if you get stuck on something, then let me know directly in the chat window or just jump into the workshop and tell me. I'll repeat anything if something is not clear, yeah?
So, first of all, we're gonna clone the project repository. I hope that you have the link, but if you don't, I'm gonna put it in the chat window, right? So, there we go. So, this is the repository. It's a nice JS boilerplate that has a few pages in it. So, let me do the same thing. I'm actually gonna switch to Visual Studio. Can you still see my screen? Can you see the Visual Studio now? Perfect. Yes. Because I lost the green border, all right, perfect. So, I'm gonna put here a new terminal, and I'm gonna just git clone the URL. And let's go, CD Workshop. Now, first of all, I'm gonna do npm i. So, I'm gonna use NPMI to install the dependencies, because I have a bad experience from one of the previous workshops where NPMI took 25 minutes.
2. Importing Content Package and Checking Data
Short description:
To import the content package, go to the content template manager, paste the project ID, and drag and drop the package. Click prepare for import and import data. After a few seconds, the content should appear in the repository. To check if the data is successfully imported, go to deliver.content.ai and enter the project ID followed by /items. You can see the JSON data from the CDN. The plugin used to format the JSON is Firefox.
So, I'd rather just do this when I'm talking about other stuff. So, feel free to do that too when you clone it. It's gonna, it's a fairly small project, so it shouldn't take long. And we should have, okay, I'm gonna open the folder, and we should be, should be here.
Now, the important thing here in this project is this package, content-workshop-import-package.zip. How this works is, in the CMS, if you have a project, you can always do an export of the project which creates a zip package, then you can take that package and import it into another project easily through the content template manager. So, this is not just a backuping tool, it's also when you want to do or you want to give a real project to a colleague or anything.
Now, this is at kentico.github.io.com slash content template manager. I'm going to, again, put this in the chat for everyone. And what we actually want to do now is import that in the CMS. Now, if you haven't signed up for the CMS, you can either go to content.ai, click on for developers, click on get the free developer plan, and this is going to take you to a signup page. If you click on get the free developer plan, you're going to get a free trial. Then after the trial, you can switch to a free developer plan, which is forever free, and it's quite generous. But again, if you don't want to join, if you don't want to create a new project, that's also fine. I'll just share the project ID with you, and you can use mine. That's fine. So I'm going to log in, and that takes me right into the project. If you create a new project in the CMS, if you sign up, then this is what you're going to see, initially. This is an empty project, nothing is here. This is the home car, but on the content and assets, it's kind of lonely here, there is no content here, which is fine if you're looking at the same thing. What we are interested in now is the project settings and we wanna go into API keys. Now, this is the project ID, you're gonna find the same ID also in the readme of the GitHub repo. So this is this ID here. So that's the idea of my project where I'm gonna import the data now. For the import, you're gonna need a project ID and you're also gonna need the management API key. So they are on the same screen over here. And on the content template manager I'm just gonna go and click on import and paste the project ID here. There's a field for target project ID so that's the first thing and the content management API key is on the right card here. Just gonna copy that over. I'm gonna click here on publish language after import. That's because otherwise all the content items would stay in their drafts. So I wanna have it published and delivered to the CDM. Now I talked about the content package so that's this thing right here. We wanna take that and we wanna drag and drop it on the template manager. So let me just put this here and I'm gonna drag and drop it here and then we can click prepare for import and then import data. It's just a few content items. Yeah, this section is not reversible continue. It's just a few content items, a bunch of images nothing too big. It should be done in just a couple of seconds. And when it's imported, you should see the content in the repository. So see, there should be three items. We have three items here, two landing pages, one component and we should also see some assets here. So three images. So I'll give you a second to get here. Let me know if someone got it working like this. Otherwise, you can always use the project ID that is in the GitHub repo. Can I send API keys as well? Yeah, this is the API key. Like if you go here, the project ID is the API key. I don't wanna give you the management API cause that would allow you to delete all the data for my project or do some funny stuff. So I'm not gonna share that with you but you can create your own project and you're gonna have it right here. So David says, I have it but the workflow step is draft. If you have everything in draft, that's because on the import, okay let's go back here. There's the checkbox that you probably didn't check but that's perfectly fine. The only thing you need to do is just click here and do a publish on all these items. So select everything and here via the three dots just do publish and just confirm it and everything is gonna be published in a second. If content is only in draft, it's not gonna be available for our content delivery. If it's in a published step, then we're gonna have everything on the CDN, so you should have everything published. Where can we import file? Okay, the import file is in the GitHub repo. So this is the repository and there it is. This is the zip package that you should import. It's right in the root of the repository. Okay, now when you have the content in place and when you have the project ID, the first thing you can check is if the data are actually making it through. So for that, you can go to deliver.content.ai, put there the project ID and do slash items. Again, I'm gonna put this in the chat so you don't have to type it. So if you click on this, you should see the JSON that is coming from the CDN, right? These are our content items. This is the landing page. We have another one here and we have untitled content item components ETA. So if you change the project ID with the one that you have you should be seeing the same content here. So again, I'll give you a few moments to check that. What is the plugin that formats that JSON? Oh, this is just Firefox.
3. Content Model and Component Limitations
Short description:
I'm not using any plugin. If you're just using a raw JSON that's perfectly fine. If you're seeing the items here, that's a first accomplished step and a first step towards victory. The landing page consists of a title, a rich text element called content, and a URL slack. The rich text settings only allow text and components. The components are limited to specific ones, such as CTA, hero, and text with image. The CTA component has a headline, sub headline, button, and link. The link is limited to a specific pattern, such as web URLs. The hero and text with image components only allow text and one image. Be careful about giving too much freedom to editors, as it can lead to more maintenance for developers. Now let's address some questions.
I'm not using any plugin. If you're just using a raw JSON that's perfectly fine. If you're looking at something like this, it's okay. It's just a JSON. So if you're seeing the items here, that's a first accomplished step and a first step towards victory.
First of all, I wanted to go through the content model here. It's a very simple one that consists of the landing page. And this is something that we provide to marketers, to editors that are working on the website. The landing page is generally any kind of page that they want to put components on that they want to create it without the help of us as developers. So on this page, there are a few elements. The first one is title. It's the name of the page. Then there is a rich text element which is called content that essentially is for any components and a text that the editors want to have on the page. And there is a URL slack. So that tells us developers on which path the page should be generated.
Now, when you look at the settings of the rich text, you see we're only allowing text and components. So if you want, you can also allow the marketers to use images, tables and potentially other things. In the components, I'm also allowing only specific components here, right? So I'm kind of limiting what the editors can do with the landing page. They can only use these three components. And when we look at how the components look like, so let's take a look at the CTA, for example, there is a headline, which is text and is required. There is a sub headline, again, required text. There is a button, the same thing, and there is a link, which is also a text, but this one is limited to a specific pattern. I assume that the editors can only put here the text that matches specific pattern. In this case, it's a web URL, right? So in the button link, there can only be URLs, nothing else. If you want, you can also use things like a custom pattern where you just define a regular expression and provide a nice validation message. It's also possible, but I'm showing you this just so you know that you can limit the boundaries of what editors can do to a necessary minimum because the more freedom editors get, the more maintenance for us. So be careful about that. And idealize everything the way it should be. Now that's what it was the CTA. We also have two more, hero and text with image. Let's take a look at this one. It's very similar. It's a headline text, again, a rich text here. And here you see that we only have text available. So not even components. So editors cannot add more components into this text. They can only add text like headlines and bold text and those things, but otherwise they won't be able to do anything else. And they can add an image here, but only one asset. So only one image. Right? So in the implementation, we know that there will always be at most one image in this field. So let's check some of the questions.
Can you show the page which we should import the zip? Sure, yeah, that's the GitHub repository. So if you go to this URL, it's in the chat. I can send it once again in the chat. Oh no, we actually wanted the... All right, we wanted the Template Manager and the URL is already in the chat. Fine. So this is the zip package and this is the Template Manager and import. Right? So we can drop the file here and provide the project ID and the content management API key. Perfect. So there's the CMS. Now I also wanted to show you the content. So we're talking about the same stuff. This is the Market Test landing page. That's the first page that was built on the landing page content type. And you see that right now, this page is published. So I cannot make any changes. I can create a new version if I wanted to do changes. But what I wanted to show you is the content here mainly. This is the rich text field that contains currently three components. Hero, text-to-image, and a CTA. And the thing is, you can take a look at what is in the components, but you cannot change anything. It's already published. If you wanna change something and create a new version, then you can start changing this. But the thing is, some of the components actually live in scope of this landing page. You'll see them without any additional information. So that means they live in the scope of this page. But this component, this CTA, for a CTA, you typically want to have a CTA button on multiple pages. You don't have as many CTA buttons as you have landing pages. So, this component is actually reused on multiple pages.
4. Content Structure and Code Implementation
Short description:
We have a type component CTA that is reused, while other components are specific to this page. Now, let's move on to the code implementation. First, create a new.env file and copy the project ID into it. Then, open the index TSX file in Visual Studio to see the code for the landing pages. Run the site using npm run dev and check if the landing pages are listed correctly. If everything works, you've set up the project correctly. Save the.env file and install the necessary packages.
That's why we see here that it's published. It's a type component CTA. And we will also see it in the repository here. So that's this one, this component. But otherwise the other components live only in scope of this page. So you see, there's a headline, text and an image. I'll explain what this means in terms of implementation in a moment. But just so you know that some of the components are actually reused and some of them are specific.
Now that we know the content structure, I think we can move on to the code. Unless there are some questions. I have the file but I don't have import page in content-ai. Oh, found it. Okay, perfect. So let's switch to the Visual Studio. And let's take a look at what's happening here.
Now, first of all, we're going to need to create a new file. That file will be.env. And we need to copy the project ID in there. So I'm just going to open the readme file and just copy it over. That's on line 14. And the ID should match, I hope. So let's just put that there and save the file. And you can see the file. And when we have that, we can take a look at the actual implementation. So under pages, typically under pages, you have the code for every single page that's in the site. You see there's only one page called index TSX. We're going to add one page later. But right now this page only lists all the landing pages. So when you look at this, we're getting the data somehow and we're listing the pages here.
Now, I'll probably just run the site. So to show you how it looks like. So npm run dev. We'll run the site on localhost 4,000. So let's take a look. So we see there is just a simple page and it has two landing pages here listed only their titles. And it contains the link to the URL slugs of those pages. Now, when I click on that, I'll get a 404 because the page is not implemented. You should be getting the same behavior. If you can run the site and see the landing pages here, that means you've set up everything correctly and you're consuming the content. So let me know if this works for you as well. If you just do npm run dev from the code, I think it works. And the only thing you need to do is just save the end file and install all the packages.
5. Implementation and Component Usage
Short description:
The environment file contains one thing copied from the README. The content service is used to get data from the CMS. We use the dot items to define the specifics of the content item. The components in the CMS correspond one-to-one to the components used in the project. These components take elements and system fields. The components are implemented in plain JavaScript. The next step is to generate TypeScript models using the content model generator.
Sure, yeah. So the environment file contains just one thing that is copied from the README. Yeah, in the README on line 14. Just copy it to the environmental variables file and you should be good. Yeah, perfect. I see thumbs up, nice. So if this works, that's perfect. So I'll stop that for now and explain the rest of the implementation.
So, there's an index page that takes data from the CMS. Now, what you see here is a content service. We actually have the content service in this implementation because you could create the delivery client which comes from the SDK, but the delivery client initialization comes with a configuration. When we look at the content service, you see here that it takes a project ID, it takes property name resolver, it can potentially take a lot of other configuration. So this is something that you don't want to do on every page. This is something you want to have a globally for the whole project. That's why there is a service for it that in the end is just a singleton that wraps around the configuration options for the delivery client, and the delivery client is essentially the SDK. But the good thing is you don't need to learn all the specifics of how to get data from content. Just know that the delivery client is there and we'll use the content service to get its instance everywhere. And today we can actually live with only a few simple things. That is the dot items, which will take any kind of content item from the CMS. And here we can define the specifics of the content item. So we're saying we're only interested in landing pages that's the content type code name and we only want the title and URLs like fields from the landing page, right? So this is kind of a projection that is designed to save some bandwidth and let us get all the data that we're interested in. And as a result, when we await this we get all the page data. We provide that from get static props to the React component and the React component has a simple mapping function. I call this for each because it essentially is a for each that that only displays list item for every landing page. And here, this is a link building. We only put the slash and the URL slug and the name of the page, right? So this simple thing just takes data from content provides that to the React component and renders all the items in a simple unordered list. So I hope this is clear. I'm not sure if we have an index.js experts here. So that's why I'm trying to go a bit slower. Not that I would be an index.js expert, but I'm trying. Perfect. So if this is clear, then let's move on to the components. Like right now on the page, we don't have any components used, but we're gonna need them in a moment. So let's quickly jump through those. I showed you the content types for the components. There was a CTA. There was a hero. There was some navigation or navigation wasn't there, but there was a text with image. So these components, they actually correspond one-to-one to the content types in the CMS, right? The HTML code here is not really that important. I just downloaded it from some tail end template, so nothing interesting or important here. The important thing is that every component takes elements and system. These two fields, elements are the elements that we defined on the content type. System are the system data, like IE, code name, the time when it was published, other things that are essentially there for every content item. And here at the bottom of the component you see, we're using some of these. Mainly the headline value, the sub headline value. We're using the button link. We're using the button text and so on to actually build the component. But right now we don't use any typescript here. This is a plain JavaScript, even though it's called TSX. If you have an error here, it will fire on runtime. It's not gonna give you any errors before that. And the same actually applies to all the other components. If you look at the hero component, it's very simple, very similar one. Has elements and system. And again, some elements that are rendered here in the scope of their HTML tags. That's the hero component. We're gonna see the HTML implementation in a moment when we actually implement it in the rich text resolution. But for now, it's enough to know that there are some components here that are implemented that we can use. There is an navigation here that will also fill the data later. That we're gonna use at the top of the page. Otherwise, there's nothing more really. There is only the service for content fetching and the simple index dot CSX page. So let's go back here and let's check the steps. Like import content into new project. We already did that, I think. We got the project ID and we got the content management API key and imported everything. And so now the next step is to generate the TypeScript models. Now what this does is there is an automatic tool that you can include in your project that will take all the content type definitions and it will generate a strongly typed models for your content. What you're gonna need for that is to install the content model generator. Now if you're using the boilerplate you don't have to do that because it's already implemented or already installed in the project.
6. Generating Models and Project Structure
Short description:
This is open source available on GitHub. Add a script to package.json that will generate the models. Run npm run generate to start the model generator. It will generate delivery models and export types. The models are strongly typed and the project structure is automatically generated. The workshop will be recorded and available for later viewing.
But just so you know, this is open source available on GitHub. And if you get and PMI today then you already have it in your project. So the only thing you're gonna need is to add a script to package.json that will actually generate the models. Now you're also find the... Let me actually share the link in the chat. You're also find the script to generate the models here in the ReadMe of the repo along with all the configuration. But we're just gonna use the easy one to generate everything. Jonathan asks if I'm gonna be sharing the slides. Yeah, definitely. I can share the slides. No worries.
So let's add the script in the package.json and let's see how we can generate the models. So let's jump here into package.json and again, you're gonna find the script in the ReadMe of this repo. I just shared the the link in the chat. So I just took the one, the most simple one in here. So I'm gonna put that in the package.json file. So let's call that generate and we're gonna call content-generate and the project ID. This I'm just gonna copy whatever I have in the environmental file. So this one, I'll just copy it here and we should be good to go. When we have the script in the package.json like this, I'm just gonna run this, npm run generate and feel free to do the same. You should see pretty much the same output. So I see the model generator started. It started generating delivery models. It found four content types, which directly corresponds to the content types that I have in the CMS. It found one language and it generated these four files. So components, cta, ts, hero, ts, text with image ts and landing page ts. Yes. When you do want to run the command every time the data changes in content. Yes. I'm gonna get to that in a few moments. But essentially, yes. Can you copy-paste that line for the script? Yes, I definitely can. So I'll put that in chat. Right? Now, this is just keep in mind that this is my project ID. Yeah. If you have your own project, then feel free to change that. And... Yeah. So this actually generates the models. Now, when you look at it, it generated models in the root of the project. So it's not ideal. But we're gonna fix that in a moment. First, I want to show you what it actually generated. So when we look at the landing page, for example, you see that there is an export type, landing page. So we're using the type. We're not using classes. Because classes in JavaScript have a bit of a problem with serialization. And it causes problems with the way how Max handles data between get static paths, get static props, and the React component on the front end. So it's much easier and much safer to use types. So we're using export type. And it has all the fields of the content type in the CMS. Right, so we had a content there, which is rich text element. We had a title there, that was a text element. And we had a URL slug, which essentially is URL slug element. So this strongly types whatever is coming from the CMS. Now, apart from the strongly type models, we also get a file called underscore project. And this file will contain all the codenames and all the specifics of the configuration of your project in the CMS. So you see that this is a project model. It contains all the language codenames. It has content types. So we have a cta component. We have the hero component and everything. But important here is the landing page and the codename of the landing page. Now, we're gonna use this in a second. I just wanna show you that we did not only get the TypeScript models, but we also got a project structure here. So we can essentially get rid of all the string literals in our code. This is automatically generated. Right? Some questions here, I'm a bit late. Does this record will be available for download? Yeah, I hope so. The workshop should be recorded and it should be available for later viewing.
7. Generating and Managing Models with TypeScript
Short description:
Let me know if this method of generating models works for you. We can move on to a nicer way of generating them using a script. We'll configure additional settings in the script, such as removing all files in the models folder before generating new models. This ensures that only content changes appear in the source control. If your application consumes content from a headless CMS, having this in place is valuable.
Perfect. So let me know if you guys see this, if it works for you. So this will work for you. If it does, we're going to move to having this generated in a bit nicer way.
Okay, perfect. Thank you. Perfect. So when you have it this way, I'm just going to clear the terminal. And first, I'm going to delete all these generated files because to be honest, they're generated in the root. So I'm just going to move this to trash. And this was the most simple usage of the generator, but it can also generate it using a script. Yeah. When we configure some additional things, which is nice because, for example, in our production project, we always clear the whole models folder before we are generating new models. So it's beneficial to have everything in a script rather than to run it directly from a package.json. So if you go back to Visual Studio and open the scripts folder, there's already a generate models TypeScript file. Just need to rename it and remove the backup suffix and uncomment. Uncomment everything. And what you see, this actually also calls the generate models async. So this is the same thing as we have in the Read Me, but it has some additional configuration. Like first of all, it takes the project ID from the dotN file, yeah? When you already have the dotN file in the project, it's beneficial to use it everywhere, so we can change the project ID only in a single place. And then what it does is it actually removes all the files in the specific directory and it generates the models right away. So first what you want to do before you actually run this script is you want to get into a specific directory that is used for your scripts, for your models. For that, I'm going to create a new folder in the root of the project, which will be called models. So feel free to do the same. It's just a simple folder here, and then I'm going to... First of all, I'm going to save this file when it's uncommented. And then we're going to add this to the package.json. Ravi asks, is this for more content-based apps, rather form-based apps. I would say this is very beneficial for both if you're having the content in the CMS. Like if something changes on the CMS side, you know right away that something changed, that your application is not prepared for. But of course, if your application only is a single page app or is a very specific and you already, you know, we have the content in the markdown files or something, then it might not be that beneficial. But if there is something that consumes content from a headless CMS, I think it's definitely valuable to have this in place.
So let's move on. And let's adjust this script. Like this was a generate script to generate the content models. Now, I'm gonna delete that because we now have the script, right? We have the script under, under scripts, the call generate models. So what we're gonna do first is we're gonna move under the models folder. So I just created the folders. So that's sitting models. And then we cannot just run the script because the script is in type script. And it's generate models.ts. So we're actually gonna use a TS node which is already here in the developer dependencies. So we're gonna do TS node. And because we are in the models folder we need to figure out the whole path to the script. So we're gonna go one level up. This is now the route of the project. And then we're gonna go into script or scripts slash generate-models.ts All right, so first of all, we're changing directory to models. This is where we want the models to be generated. This is where we want to store the code files. Then we're gonna run TS node and provide the path to the script file. Is that the autopilot that is giving you suggestions of what you previously typed? Yes, that's a GitHub copilot. And it actually does a pretty good job which you'll see in a moment. It actually works much better in the code files than in Package.json. Yeah, I'll paste the script, so here you go. So when you have that in place, then you can just go NPM run generate and hopefully we'll get all the model generated in the models folder. There we are. Now you see that the models look a bit different. The names look a bit different. This is because there is some additional configuration I removed timestamp because when you have a timestamp on every model, then usually you want these models to be committed to your Git repository. And when the timestamp changes with every regeneration, then the timestamp change might be the only one that will cause you to commit that change in the Git. Yeah, so we actually want only content changes to appear in the source control, which is why I'm removing timestamp and then there are some initial configurations that define a camel case, because I want to use camel case for the element names, this is because I'm already using the camel case property name resolver on the delivery client, yeah? So I'm just trying to unify the way how I'm working with the elements. So I'm using camel case for the SDK. I'm also using camel case for the element names, and then for the files, I'm using a Pascal case with the suffix model, so I know when there is a suffix model on the code file, I know that this is generated from the CMS, right? So let me know if everything was generated for you. It's essentially the same piece of code, but now all the models should be under the models folder. Perfect, thank you, guys. So now we have everything generated. The same, it's the content is the same. It's still the project structure. It's still the models.
8. Fetching Content and Adjusting Components
Short description:
We generated TypeScript models and fetched content in XJS to adjust the components. We eliminated string literals and used strongly typed models and constants instead. We fixed the elements parameter by using the project structure and removed unnecessary code. Next, we improved data transfer between GetStaticProps and the component by changing the interface to Lending Page Model. This provides better IntelliSense and prevents errors. Overall, these changes enhance code readability and reduce the risk of mistakes.
It's still the models. It's types, and now the more interesting part. Let's go back to the presentation. Let me just go here. So we generated the TypeScript models, and now we're going to have to fetch content in XJS and adjust the components to use the strong models for content. So let's take a look at how we can do that. The index page that I showed you before contains a lot of these string literals, and it doesn't really look nice. It's really easy to make a typo here. Yeah, if I put a landing page, I put a dash here instead of underscore. Now the page will stop working because there will be no content. So we can get rid of this string literal and use actually a strongly typed model here to cast it. We can also use the constant here. So let me actually start here. So first of all, we want to change the items call to strongly typed model. So we know that we want landing page as a result of this call, right? The only thing we're getting is a tight landing page anyway. So we can cast it to the landing page model. As I edited, you see that there was automatically an import created from dot, dot slash model slash landing page model. So this is the first step. The next step is to get rid of this string literal. And here we can use the project structure. Yeah, that's what was generated in the underscore project file. So I'm just gonna do a project model. And just with the dot notation and with intellisense, I can click through and specify what I want. So I want content type and the content type should be a landing page. And I want code name of the content type, right? So this way I can remove this line and I can get rid of the string literal. So therefore I'm removing the possibility for errors. And this also works the other way around. Like imagine that you want to delete the landing page content type, because it's old, you think that there are no pages that are depending on it. This way when you have it defined in the project file, you can just go here, find the code name that you're interested in and right click it and find all the references. And you see that this is used only in the project file and on the index TSX page. So if this gives you only one result in the project structure, then we can safely delete that content type because your implementation is not using it at all. Of course, that applies only if you're using one channel here. But you can easily find if there are any pages that are depending on this data. So that's one thing. And then we can also fix the elements parameter here where we have also two not ideally looking string literals. So we can, again, go to project model, we can go to content types. And again, we need to start with the landing page. You see that we also have the components here but we only want the landing page now. And we don't want code name, but we are looking for element code names because it's elements parameter. This is the projection that I talked about. So we want elements and here we want the title code name. And we want to do the same for the URL slug. So we want to do content types dot landing page, dot elements, dot URL slug and code name. And again, we can remove these two because we don't need them anymore. All right now, I think that that's all that we can do here. Let's say this and let's check if it still works. So let's run the project and pm run dev. And you'll see the page still still works. Like we didn't change anything functional, we just got rid of the string literals and used the generic, the constants instead. Right? So hopefully this works. Now there's one additional thing that we can do and that is how Next.js actually transfers data between the GetStaticProps and the actual component. You see that here we're using props and the props is an interface that's generated or that's defined on the index.js file that contains IContentItem. Now IContentItem is a very general thing that's a, you know, it's kind of a wrapper around any content item that you get from the CMS. Now in here we're actually getting specific items so we know that we always get Lending Page Model array. There is nothing else that can come here because we are, you know, limiting that by a type. So we can change this from IContentItem to Lending Page Model and delete this import. Now what is really good, like let me put this back. What is really good about this is when you go here in the React component implementation and you're actually building the content here, yeah, there is a list item, there is a link, when you go to page.elements and do a dot here and try to invoke the IntelliSense, you don't get anything here, yeah? This is not helpful at all because Visual Studio has no idea what, you know, what this property can have. So this is a property that is IContentItemElements and that can have pretty much anything. Yeah, it doesn't know. When you do that change, when you change it here to landing page model and try to do the same here under page elements, you now get three element possibilities, content, title, and the URL slug. So you immediately know what elements do you have available so you can say, yes, I want URL slug and the good thing is that if you put here, let's say URL slug four page generation, you see right away that this is something that does not exist on the landing page model. The property URL slug four page gen does not exist on type and that's the landing page model. So you see exactly like the file will turn red. You're gonna see the error here and you see here exactly what's wrong. So this is already one great benefit. First of all you cannot make typos anymore. Second of all, you get strong types here in the component. So it's much harder to make a mistake and if there is a mistake even before build time, this is a statistical analysis while you're coding. So very cool stuff.
9. Creating the Slug Page and Generating Paths
Short description:
Let's move on to the next page and create a code file for the landing page. Create an environment file with the content project id variable. Implement a new file called slug.tsx under pages to generate pages based on the URL slug. Copy and paste the index.tsx file as a base template for the slug page. Add GetStaticProps and export const getStaticPaths functions.
So that's the next page. I would just still keep working, but let's move on. I hope that it works for you guys. If it doesn't, then just post the question in the chat. I'll take a look and we're going to create a code file for landing page, right? That's the next step.
So let me... Oh, I stopped it I think. Let me run this back. Ah, yes. So was I supposed to create an... n file with API key? Yes, exactly. So create an environment file and put there the content project id variable with the value. You're gonna find it in the readme.md on line 14. Yeah, this is exactly what should be in the n file. No worries, it's fine. Cool. So now I have this running again. Let's run this.
Now, what I'm aiming to try and solve now is these pages actually returned 404. So I wanna implement the page that would generate these two pages, right? So the next step is to create a new file here under pages and we're going to call it slug in sharp brackets TSX. Now, if you're new to Next.js, this is the file system route or API or however you want to call it. I think that was a Gatsby term. But the important thing to know is that based on the file name, Next.js will actually determine the target or the path where the page should be generated on. So, if we do an index.tsx, that's gonna be the root page for that folder. If we do the slug in square brackets, then it's gonna take eventually any URL slug and it's gonna try and generate the page on that path.
So, what I'm gonna do, I'm just gonna copy and paste the indexed TSX file. So, feel free to do the same. Just copy the whole implementation of the index page and paste it to the slug. Of course, we're gonna change that but first, it's gonna work to get the base template of the page. Now, in GetStaticProps, we're gonna need one more step here. We're gonna export const get static paths first, which is gonna return get static paths. And that's gonna be, again, an async function that will return something.
10. Implementing getStaticPaths for Landing Page
Short description:
We're implementing getStaticPaths to provide the paths where there should be a page. We use the content service to get the LandingPageModel with the URL slug. Then we return an object with the slug as the parameter. We map the items to the slug value and remove the rest. This ensures we only get the URL slugs from the CMS.
So yeah, I just copied the index page and added here, or export const get static paths that returns get static paths objects. We're gonna probably need to import this. So I'm just gonna update import from next. Yeah, so we're importing get static paths and GetStaticProps from next now. And the way how this works is, Next.js will actually look at this page and it will run, get starting paths first. And get static paths, you're responsible for providing all the paths where there should be a page. So in our case, it's gonna be the slash market there's landing page and slash HoxIroc. But essentially it's any path where there should be a page only a path, nothing else is needed from you in the scope of this function. Then next we'll take all the paths here and it's gonna push that to the getStaticProps. And getStaticProps it's gonna give you the slug. So let's put that here. Constant slug will be params.slug.toString. So we're gonna get the slug in params. And then we're gonna need to implement how we want to get the data for that slug. So if in getStaticPaths we provide two, three, five paths, then the getStaticProps will be called two, three or five times. For every slug it's going to be called once. And this is all at build time. So here we're gonna need to provide the paths. Here we're gonna need to provide the data fetching. And when we have the data then it's gonna go back to the React component that renders the HTML.
So I'm gonna remove this for a second. I'm just gonna keep the navigation there. I'm gonna call this, let's call this landing page. Because we're gonna be working with landing page content types. So I'm just gonna switch this to landing page. And first, I'm gonna implement the getStaticPaths. So what we want here is, let's call those paths. And we're gonna use, are going to use the content service. So we're gonna do, awaitContentServiceInstance and deliveryClient. That's essentially what we always need to do when we want to get some data. And then we want to getItemsLandingPageModel. Again, the same thing as we have here. And we want the same type, so we're gonna again use the project model of content types and LandingPage, because we're trying to build the landing pages, right? That's why we want the LandingPageModel, we want to limit it by the type. And we want to limit the response with the elements parameter. And we only want it to get the URL slug, because again, we're providing only paths. We don't care about any other content. So we're looking for elements URL slug And then we can do just toPromise. This part, the elements parameter is essentially a nice to have. Yeah, you don't need to do that. It just limits the response you're gonna get from the CDN with the data. So you're telling I only want the URL slug, nothing else interests me at this point. Now, when we have that, next.js will actually want us to return a simple object that is called paths. And in the past, there is another object called params where we need to provide the slug. Now, first, I'm trying to show you how the object looks like again, because this is not an easy thing to understand if you're new to next.js. So what next.js actually requires us to do is to provide an object with paths. And I think this should be an array, by the way. Array of objects. I think maybe we'll see in a second. But the important thing is that we currently have on our on the way to our page, we only have one variable in the file name, which is the slug. So that's why we provide a slug here. Over time, you may get into a place where you're going to need multiple variables for a single file on the way to it. So in that case, you would need to provide multiple params here. But here we just need one parameter, which is slug. So we obviously, what we want to do here is, we want to use the data that we got from the CMS, right? Instead of the static array here. So what I'm going to do is put here paths, paths is actually the response. We can actually call this path response to make it clear. So path response. We're looking for data and items. And then we're going to map them because for every item, we're only looking for its slog, right? So we're going to map them to item. And here we're just returning the same object as we had here. So this is going to be params, slog and that's going to be item elements, URL, slug value. And remove the rest. Or at least I hope that I have this correctly. We'll see in a moment. Um, yeah! So, once again we're only returned, we're only interested in getting the URL slugs, at this point from the CMS. And we are returning an object with paths and I think we need to do... Three dots here or something. Something's not right here. Uh, don't you need to return from the map? Yes, there should be this should be an object. Maybe it doesn't take it as an object.
11. Static Props and Fallbacks
Short description:
If you use curly brackets, you need to use the return word. The fallback parameter in getStaticProps determines how Next.js handles paths that are not provided. By setting fallback to false, any path not explicitly defined will result in a 404 error. The equals filter is used to filter landing pages based on the URL slack. Adding a limit parameter to one improves code readability and has performance benefits. The project structure can be used to create a strong type filter for better code clarity.
No, something else is wrong here. Oh, it could... That could be a normal bracket. I always get lost in brackets. Yeah, if you use curly brackets, you need to use the return word. Yeah, yeah, thank you. Yeah, I think that if I use the normal brackets, this should be good. Right? Yeah. Perfect. Thank you.
But the good thing is that we have the object, right? So I think that we should be good. He still doesn't like something. Um, promise pass, promise is not assigned to type. Get static pass. Oh, so maybe here we need to flatten the array. No, what's going on here? Type promises are assignable. You're awaiting that. Probably fullback is missing. Okay. Yeah. So that's so that means we're just not finished yet. So we have the pass here. All the paths are defined. And we need to provide a fallback here. Now I'm just going to put here false. What this does is it tells Next.js that all the paths that you provided here, provided that to get static props, if at the runtime there is a request that is for a different path, that then the one you provided is going to go directly to 404. Yeah. So here, let's say we provided only one path that is slash hello world. In that case, Next.js will only treat the hello world path as the one that this page should render. So if you go to this page from slash hello, it's going to go directly to 404. Yeah. If you do anything else, it's going to go directly to 404. But if you put here anything else like fallback blocking in the quotes, in that case, it's not going to go to 404 directly, but it's going to try to run this anyway. It's going to give you the slack, and in the slack you're going to get the hello, and it's going to try to run your code anyway at runtime. The path that you provide will only be generated statically at a build time, but Next.js will also treat all the other paths as potential paths for the pages, and you are then responsible for redirecting to 404 if something happens. Just to make things easy, for now, I'm just going to keep the fallback to false. In that case, everything else is going to go to 404 directly. So feel free to do it the same way. It is a wait. Yes. Perfect. So I'm just going to keep the fallback false. We're providing all the pass, and in git static props, we are getting the slack. And then, of course, we need to adjust this call. Because we're trying to get the landing page model. That's fine. We can remove the elements parameter. Because on this page, we're going to render everything. We're going to render all the content. But what we're definitely going to need is an equals filter where we need to say, where we need to filter that elements, that URL slack, is the actual slack that we got. So this is a filter that actually filters all the landing pages for the specific slack. Now, what I also like to do is put here a limit parameter to one for one specific reason. Because when you get to this code in three months time, you see exactly from this one single line, you see exactly that this query should always render only one item. Yeah, so this is a readability thing. Mainly. But I always like to include it in case, you know, this might not be that clear from the first glance. And it also has some performance benefits. Now, can't we use strong type on the filter? Yes, that's what I was gonna do next. This is not ideal because we already know that this code name is in the project structure, right? So all we can do, is do this. And instead of the URL Slack, switch the keyboard. We can do project model, we want to do content types, landing page, elements and URL Slack codename. Now, this is a bit too long. You can always shorten it a bit. When you need to do more, you can always put this in a constant and then make it a bit shorter. This is also not ideal that you have elements here. But what we actually do in our projects, we have a util method here that has the elements prefix only at a single place in the whole code base. You can do that, too. The reason why we have it here is because you can always filter on system as well, yeah? So we can say filter by system.type. Or system.codename. Yeah, so you can filter on those as well.
12. Rendering Landing Page and Checking Components
Short description:
We need to include elements and return the prop that the component expects. We only need to provide page data items and the first item. Render the title and check if the page is displayed correctly. If not, let me know.
That's why we need to include elements here. But I think that this way it should work. And then we're going to return return the prop that the component expects. In this case, we have interface props, and the interface props requires one landing page content model array. Now, in this case, we don't need this at all, because we only need to provide in the prop, we only need to provide page data items and the first item. Because we only have one, one landing page as a result of this service call. We, of course, can't return props now because we don't have that defined. So I'm just going to switch that to landing page model. The same will go here, landing page model. And this is going to be in the page where we are going to have the landing page model data. So this is possible when you have only a single, a single item that you want to render or that you want to, you know, move between your static props to the React component. Now, here, we can just continue, you know, rendering whatever content you want. So just render here title and save it. And I think that in this state, we are fine to run the site. And it's actually already running. So we should be good to refresh the page. So when I click on this, we should now get the page. So here it is. This is the page. This is the idle, HuxZiro, can marker this landing page. We have that here as well. So let me know if you can see this. If you can see the same thing, then we will move to the components. Or something's not working. Then let me know. I can explain something further.
13. Implementing Component Resolution and Rendering
Short description:
We created code file for landing page and did the get static paths and props. We resolved Reset fields into React components. The components have corresponding types. We also solved the issue with the DOM node in the rich text element resolver. Now we can move on to the rich text resolution and render components on the Slack page.
It works. Perfect. Let me check. Nice. Good job, guys. So I will just give everyone else a few seconds. Then we are going to switch to components. I think that's the next thing.
What we did is, we created code file for landing page. We did the get static paths and props. So we should be fine. The next thing is to resolve Reset fields into React components. Perfect. All right. So let's move on. Let's move on to the components. This should be quite easy to do. You see here, on the CTA, I opened the first component. That's the CTA. You see that it has elements and system and no type. This should be quite easy because this has a corresponding type. Component CTA has a corresponding type called component-ctamodel. We're just gonna turn this into react functional component and put here... How was it called? Component-ctamodel. It added this import automatically from the models folder. You see, as soon as I do this, I immediately get the types here for elements. The component-ctamodel contains the systems and elements properties. The elements is headline, button, text, subheadline, link, system, system attributes. We get all of that. I don't think we need to do any changes here Because we already implemented it the right way. But when you click again, when you put a dot here after elements, you see all the four available properties. So this is an easy fix. The same goes for hero. Again, I'm just gonna put here react-fc, which is a hero component model or component hero model. And navigation is a bit of a special case. So I'm gonna get to this in a moment. And the last one is component-text-with-image. Which is a RIA functional component and component-text-with-image model. Right, so this way we have strongly type models here as well.
Now there's one thing that we need to solve. That is the DOM node here in the rich text element resolver. I'm gonna get to that in a moment on the landing page. But just so you know, the resolveDOM node provides a DOM node, which is a DOM node type, obviously. But here the DOM node is actually an element. Because we're checking if the DOM node name is P, so this is for a paragraph tag. And if you look at the DOM node. Yeah, the DOM node is of type DOM node and the DOM note type is actually comment, element, node, processing instruction, or text. Now in our case, this is definitely an element. And we can check that by providing here additional check for DOM node dot, I think it's type, node type, And in the node, oh sorry, this is a getter. So no parentheses. So if you do a DOM note dot node type, this is a number, and it actually comes from an RFC specification. So I can take a look at that, but the number one, if you compare it to number one, that's actually an element, right? So if you compare this way, then you can say the DOM note is safely an element. And then it's going to start to work. Of course, this is just a syntactic sugar because we know that it's going to be an element. So this is a bit longer, longer piece of code, but it gets rid of the error. Now this is not a breaking error, yeah. It's just something that we're not sure that the DOM note is going to be an element. So I'm just going to do the same here. And this only adds some class name. So that looks nice, this is something that is a visual thing on the website. So nothing important, but just so you know, we need to do this change. Perfect, so that's the last of these components. And now we can move on to something more interesting. And that is the rich text resolution. Now we have the components in place. Let me collapse this we have the components in place that are already prepared to be TypeScript supported or that you know strongly typed models supported. And we can go back into our Slack page and render something here actually instead of just the page title. So I'm just gonna put here another div and because, as I showed you in the CMS the landing page... Why is it not showing anything? Come on....the landing page is a content type that is prepared for marketers so they can add any kind of components, any combination of components that they want.
14. Rendering Content Items as React Components
Short description:
The landing page is a content type that allows marketers to add various components. To display the content items as React components, we use the reach text element from the content React components library. By importing the reach text element and providing the page's content, we can render the components. We can also use resolvers to customize the rendering of linked items, images, and links between content items. For example, we can render a 'hello world' div for each component on the landing page. Additionally, we can create switch statements to handle different content types, such as the CTA and hero components.
Why is it not showing anything? Come on....the landing page is a content type that is prepared for marketers so they can add any kind of components, any combination of components that they want. So what we need is we need to resolve all these content items into their respective React components.
Let's switch back here. And we're gonna use a specific component for that. It's called reach text element. And the reach text element is coming from a library content React components. This is actually not under content organisation because it's not yet in production. But we're already using the, it's pretty much just the RECT code that we were using on production projects. So it's working well. And I think that the first production version may already be released. I'm not sure. But the important thing is that when you import the component here, what you need to do is provide a reach text element. Which in our case is going to be page elements and not body but content. So I see this is the elements reach text element. When we look at the landing page model, the content is the reach text element. So that's what we want to provide here. And in the end, that's all we need to do if we don't want to change anything, right? If that's all you need for text, for example, it's fine to leave it like this, it's going to work.
But in our case, we want to add a resolver. Resolvers is essentially an object that lets you change a few things. First, depends on the level of abstraction that you're comfortable with. The first thing that we're going to need to do is resolve the linked items. So I'm just going to add the resolver here for linked items. And what we can do here is do a very simple div, hello world. Right? We're returning a JSX. And what this is going to do is, for every component that we have on the landing page, it's going to render a div that has a hello world in it. So if we save this, we can check it out, how it looks like on the site. So you see it rendered hello world twice. Yeah? And then hawk eyes rock. That's probably because I left something in place. Yeah. I left the title here. Yeah? But you see that now on this page, we have two components and both rendered hello world. If we go back and go to the market, this landing page, this one has three times hello world. So this page has three components. So you see, this actually renders the hello world for every component. And essentially, we can render any kind of React component here. But what you can also do here is provide other resolvers, like resolve image. If you want to use the next image, or you want to do some post processing, you want to use your own component for images, perfectly fine. You can resolve links. This is mainly if you have links between content items, then you can resolve those links into URL slugs, you can resolve external links. You know, we can, what some of our customers do is if there's an external link, they put a note that it's an external link below, or behind the text and so on. But it can also resolve with dumb notes. That's something that we did on the components that we just fixed. So you can go all the way down and resolve every single dumb note that you have in the rich text. That's not something that I want to do today, because that is a bit complicated, because everything is a dumb note, right? It's just every piece of text is a dumb note. But what we're gonna do here is we're just gonna do a nice switch statement here for link item, and we're gonna do system dot type switch. Now, in case this is a project model content type, content types, if this is a CTA, code name, then we're gonna return the CTA component and I think that we did it as the main model. So we're just gonna do link item as CTA, component CTA model. And I think here we need the three dots. Oh, I don't think he knows what CTA is. So we're just gonna go to do an import. CTA from a component. CTA. Let's look for properties from I content item. Okay. Something is wrong here. Can I find a link item? Okay. So we need to provide a linked item. Okay. So here we need component CTA model is a component CTA. And here when we have the link item, that's a content item, we need to have it as component CTA model. Do we have the import here? Yeah, we have the important place. So what's there not to like? Headline, button text, sub headline... Yeah, so we need to... Oh, come on, why don't the three dots work here? Oh, thank you. Thank you, Hanke. That's what I was looking for. Perfect, thank you very much. There's always something that I forget. So this is how we get the CTA and we do the same thing for the hero.
15. Component Import and Resolution
Short description:
This is how you can get all the components in place and resolve it with rich text. You can analyze the code name and render React components based on that. It gives you more control and allows for a more detailed resolution.
So this is a component here, a model, of course I need to import it first. And the same goes for the model. And we'll need to do the same one for not navigation. So sometimes get a compiler is not the brightest one but still it does a lot of things very well. And this is a text-to-image. Text-to-image, link item as components, text-to-image model. And again, at an import. And what I always like to do is at the end just put a throw new error unknown linked or we can do linked item, type and put it here. Yeah, so in case there is a component that we're not counting with this can happen quite easily. When you add another component here and you actually let your editors use that component and you forget to add the component here in the resolver then they're gonna get this error or you might get this error during build because when the page is being built during build, during if the page is statically generated during build then Next.js will try to resolve this and we'll get the error. So it's likely that the build will fail and you will know exactly what is wrong. So when you save this and go back here you should hopefully see a nicely looking page. So here we have only one component or two components, the hero with image and the CTA. And here we're gonna have three components. This looks much better where you have to have the hero image, hero text. We have image with text and there is a CTA here. Now what we can always do is check if this, if we can change something, let's say on the market is running page, what we can do is add a new component. So let's place here a new component. Let's put here another CTA we can say, React Summit is coming. Join everyone in Amsterdam. And button text could be visit conference and go to React Summit. Is the URL right? Yeah. And of course, we need to publish it because right now we're only working with the Project ID, which contains only published content. And it's going to take a second before it's on the CDN. So if we go backwards the page here, it is if we refresh this, you see that's nothing changed right now. But if I refresh this in a moment, there we go. So this is the second CTA, right? So this is how you can actually get all the components in place and resolve it with rich text. As I said, this is a simple linked items resolution. Of course, what you can also do is put a code in place that would analyze the code name and check which React component to render based on that only. I prefer to do it this way. I feel like it gives me more control. And if you want to go a bit down and do a more detailed resolution, then you can always do what I did in the text image. And yeah, just to resolve the dumb nodes.
16. Implementing the Nav Component
Short description:
The nav component is missing at the top of the page, and it currently contains null data. We need to provide a type for the data, as the components on the page can be of different types. One way to do this is by defining a set of components that we know will always be there. We can make the nav component a functional component and use an array of icon item types to handle the data. However, we also need to address the issue with the elements headline property. To do this, we can provide a list of the components that can be inserted and ensure they all share the headline property.
Now, one last thing that I wanted to do here is the nav component. When you look at the page now, there is nothing at the top, which is the nav component. That should be at the top here. The problem is, it contains data null. The component actually contains links to a part of the page. This is very common for single-page apps that the elements on the page have anchors. At the top in the menu, in the header, you provide links to the specific parts of the page. That's something we do here in the navigation as well.
The problem is, right now there is data null here as well. We did not actually type script this component yet. So what we can do is provide a type for the data. This is not that easy because the components that are on the page can be of different types. So we need to either find out the the set of components that we know will always be there and define it as a set of components or we need to introduce some kind of a new type. Right? I prefer to do it the first the first way.
So I'm just going to make this react functional component and we can of course do icon 10 item here. This is probably not going to be icon 10 item but icon 10 item array because then we're going to get all the data here. I think this is also fine because we are looking at system code name and system code name. The problem is that we also have elements headline here. If you do the elements and dot, you see again we don't get any help here Because that's the icon 10 item. What we can do in this case is provide here a list of the components that can be inserted here.
17. Implementing Component Resolution and Rendering
Short description:
Now I can provide a component CTA model, hero model, or text to image model and import everything. These components share the 'headline' property. However, it is uncomfortable to define this property in multiple places. It would be better to define props somewhere globally. Let me know if there are any questions. In the meantime, I can move the interface to a new folder called 'interfaces'. The last thing I want to touch on is deployment pipelines, which allow you to commit everything in Git and track changes to your content model.
Now I can of course do it this way to provide here a component CTA model or component hero model or component text to the image model and import everything. And what I'm telling the component is that whatever comes it's gonna be in either of these types. And the thing is when I'm going back here to the elements I'm gonna get only a single property here called headline. This is the only property that all of these types actually share. Yeah and when you look at the model, the components CTA model has a headline, the component hero model has a headline and the component text to image has a headline right? So they all share this property which is why I can safely use it here. Because if I do something else here like a sub headline and then a sub headline again I get an error. Yeah the only thing that is uncomfortable is that you have to define this here and you also need to define it on the page that is actually using the data. So when you see that the type data now is not assignable. So even if we put here the page elements content and we actually cannot provide the rich text element but we need to go one level deeper to linked items. The visual studio is still not happy with it because the icon item that we are providing is called linked elements or linked items is icontentitemenelements, there can be a different component different from the three components that we defined here. Yeah so you would have to do it here as well and then last as component CTA model component hero model or component tested image model and of course, right? In that case, it's gonna be hopefully fine, what's wrong. Data does not exist on type. Oh yeah you'd have to do it this way. Yeah so you can do it this way as well but the better way I think is to just define props somewhere either here interface data, which essentially is this thing, I perhaps and is it here? Here. And ideally put this somewhere globally so that you don't have to repeat this, you know, here as well. So you would just probably put here data equals page. Now I'm just going to leave it as it is right now. But it would be beneficial to have the interface somewhere external like interfaces slash index and use it for both of these places. But, if we save this, then in the navigation, there is still an error here. Date. Yeah. That's because I'm missing from the brackets here. And now it should be good. And now if we go back here, you see that every component has its own item in the menu at the top. And when you click on something, you get to the page where the item is. Or get to the place in the page where the item is. Of course, this is not ordered in any way currently. We would have to do some more implementation to do that. But yeah, that's how it should work. So let me know if there are any questions so far. In the meantime, I can actually take the interface and move it someplace nice. So let's put here a new folder, interfaces. Let's call this one I. Not components. And put that there. And put that there. He doesn't want to let me import it. So I think I need to export it as well, right? Right. This looks much better. We can do the same here. Instead of this one. So, oh, actually, we need to do this here. Now, what's it not, like, conversion of type, type, all right, type and one mistake. Okay, I'm missing something here. So the nav has INF components, data is here. Type must be an array. I think that the data is fine here, but he doesn't like, I'm gonna have to do the same thing here anyway. So I'm gonna have to do this, SS. I think this way he's gonna be happy. Yeah, it's not saving me to write this anyway. But I mean, there's probably better way. Maybe you can help me guys. If offer a better way, how to do this. I'll probably figure out something, but it's late evening here. S props data. I think this is gonna work. I think he's gonna complain anyway. Nope, he doesn't like that. I'm gonna find another props. Never mind, it's fine. Like there's probably a better way how to do this. But the important thing is that the page is working well. And we have everything covered with TypeScript. And it's hopefully working for everyone. If it does, that's great. It should be INF components data. Yeah, let's leave that for now. The last thing I actually wanted to touch on is the deployment pipelines. Now, what this actually lets you do is when you have everything generated in the models, what it can do at least what we do is to commit everything in Git. So you know when there are some changes, you know exactly what's happening with your content model.
18. Generating and Comparing Fresh Models
Short description:
When building your website, always generate fresh models from the headless CMS and compare them to detect changes. Check out our blog article on Avoiding Production Errors Caused by Content Changes. You can follow the same approach here.
And what you also do is when you do a build of your website, we always generate the fresh models from the headless CMS. And we actually compare those two together to see if there are any changes. If you look at our blog, I wrote an article about that, Avoid Production Errors Caused by Content Changes. So what we can do is we can try to, we can try to follow that here. Like if you don't want to, if you don't want to install this now, it's perfectly fine. We have still some time left, so I can check if this is going to work, but the code is here. So it shouldn't be that hard.
Comments