Part 4 Connecting the CMS and the site PDF

Summary

This document provides a guide for connecting a resume website to a content management system, specifically Storyblok. It details the steps involved in obtaining the necessary code, understanding the codebase, and setting up the website.

Full Transcript

Introduction ============ In the previous part we introduced our data model, and implemented the data model in Storyblok. We now want to connect our resume website to our newly created data model in our content management system. This is a big step. To help you along, you will get the code that yo...

Introduction ============ In the previous part we introduced our data model, and implemented the data model in Storyblok. We now want to connect our resume website to our newly created data model in our content management system. This is a big step. To help you along, you will get the code that you need from me. You will get it from me in the same manner developers get code from each other: by \"forking\" my repository. Next, you will learn what the various pieces of the code mean. Then we will try to get our website running, and integrate it in StoryBlok. Then we will get our site online and finally we will show you how you can change both the code and the content, and see these changes online. Finally, we will provide a recap of the development process. Getting the code ================ The easiest way to get the code of the Resume project is to fork it. What a fork is, is explained here for those interested (not necessary): This is how you get the code: 1. First, make sure you are logged-in to your GitHub account. 2. Now, search for JanMoonsUGent/resume. Graphical user interface, text Description automatically generated 3. Open this result. Now you will see the page as shown below ![A screenshot of a computer Description automatically generated](media/image2.png) 4. Finally, click on the Fork symbol. The Resume code will be forked to your own account (in the example below, I am now using my second GitHub account called jnmoons, that is why the suggested name is jnmoons/resume). Graphical user interface, text, application, email Description automatically generated 5. You should now be at youraccount/resume. A \"fork\" is a complete copy of the code, and although links remain, and there are options to \"merge\" the forked version and the original version again, the fork can, and likely will, be developed independently of the original repo you created the fork from. Do not mistake this for a clone. A \"clone\" is a local copy of your online repo. You \"clone\" a repo to get the code on your own PC. You \"fork\" a repo to get your own version of that repo in your own account. ![](media/image4.png) At this point, the project is forked to your own account. Now it is time to get the project up and running on your own computer. For this, use the GitHub CLI (as described in part 1 in the section \"Alternative version for getting code into GitHub\", starting from step 7) to clone the project from your online GitHub account to your local computer: A screenshot of a computer Description automatically generated The structure of the software ============================= After having cloned the software, open the folder in VSCode (File\>Open Folder). Take a look at the File structure. You are now looking at a Next.js project structure. For those interested (not mandatory), you can take a look at to learn more about Next.js. It is the most used website framework for the most used Javascript library (React). In short, you can use Next.js to create enterprise-grade websites. If you open the File structure (the first tab in your left sidebar in VSCode), you see this: ![Afbeelding met tekst Automatisch gegenereerde beschrijving](media/image6.png) Every folder and file has a purpose. We will introduce the most important ones here: - **Components**: this important folder contains all the javascript files for our various components. A component can be anything that you use in the UI of the website, but in our case if will often be a representation of a content type, a page, or page structures. E.g. the Person.js and Experience.js files are stored here -- files we will use to represent a person and the experience of a person. Consider this the folder you will do the most work in. - **Node\_modules:** You will not have this folder at first, but once we run the project this folder will hold \"node\" modules -- external modules that our website uses and needs in order to function. - **Public:** here you can place images and other assets that need to be available publicly, such as the logo you use in the navigation. - **Styles:** scss (a superset of css) and css styles go here. If they are specific to a component though (such as Person.scss), we will store the style file together with the component in the Components folder. - **Pages:** in a regular NextJS project this would contain actual pages, but since we use a more dynamic way of creating pages using StoryBlok, this folder only contains the (important) files \[\[...slug\]\].js, \_app.js and \_document.js: - **\_app.js**: Next.js uses the App component (\_app.js) to initialize pages. For those interested, more information can be found here (not mandatory):. - **\[\[...slug\]\].js**: (from the official docs) We use dynamic routes in our app (based on information from StoryBlok. Defining routes by using predefined paths is not always efficient for complex applications. In Next.js you can add brackets to a page (\[param\]) to create a dynamic route (a.k.a. url slugs, pretty urls, and others). We use the \"catch all\" route handler. It is a fancy way of saying that this file will always run before opening any page on the site. For those interested, learn more here: Now, let\'s check out some specific files that we will touch upon in our website creation efforts pages/\_app.js -------------- the \_app.js file is used to map component names coming from Storyblok to component names in our Next.js filesystem. The file could also be used to provide additional data to our pages, but we do not use that functionality here. The section in blue in the file presented below is the section that takes care of the mapping: import \'../styles/globals.css\' import { storyblokInit, apiPlugin } from \"\@storyblok/react\"; import Person from \"../components/genericComponents/Person/Person\"; import Experience from \'../components/genericComponents/Experience/Experience\'; const components = {   person: Person,   experience: Experience }; storyblokInit({   accessToken: \`\${process.env.STORYBLOK\_API\_KEY}\`,   use: \[apiPlugin\],   components, }); function MyApp({ Component, pageProps }) {   return \; } export default MyApp; So, anytime our code needs to render a StoryBlok \"person\" component, our code will load the \"Person\" component located in \"../components/genericComponents/Person/Person\" (as can be deduced from the import statement); pages/\[\[\...slug\]\].js ------------------------- The \[\[\...slug\]\].js page will be executed for every request of a visitor to our site. There are three important methods: 1. getStaticPaths: gets all possible paths that might be rendered by the server. Next.js will statically pre-render all the paths specified by getStaticPaths. This will produce HTML, JS and CSS which can be cached by a content delivery network (CDN). getStaticPaths will only run during build in production, or when developing the site, but it will not be called during runtime in the production environment. 2. getStaticProps: gets the data for the current path (URL). This code is used to get the data from your CMS so it can be used for the current page. 3. Page: this function will take care of the connection between the code and the Storyblok Real Time visual editor. The function will also return the HTML that takes care of loading the rest of the page. styles/colors.scss: ------------------- This file contains variables for colors that we could use throughout our website. We will discuss how you can use these variables in other parts of the site later on: /\*General colors\*/ \$color-grey-very-light: \#e1e4ea; \$color-grey-super-light: \#f4f6fc; \$color-grey-super-ultra-light: \#f9fbff; \$color-grey-light: \#9ea8bb; \$color-grey-normal: \#001c54; \$color-blue-ultra-light: \#f5f8fd; \$color-blue-very-light: \#eaf0fd; \$color-blue-light: \#d2e0ff; \$color-blue-mid: \#ccd7f1; \$color-blue-normal: \#1b6bf8; \$color-red-very-light: \#ffe8e8; \$color-red-light: \#ffb5b5; \$color-red-normal: \#ff6868; \$color-yellow-very-light: \#fffae6; \$color-yellow-light: \#ffefad; \$color-yellow-normal: \#ffcf11; \$color-green-very-light: \#e8f9f7; \$color-green-light: \#b5ece5; \$color-green-normal: \#33dfc8; \$color-purple-very-light: \#efecff; \$color-purple-light: \#ccc2ff; \$color-purple-normal: \#705bfe; \$color-white-very-light: \#ffffff; \$color-white-light: \#f3f3f3; \$color-white-normal: \#e4e4e4; \$color-default: \$color-grey-normal; We could define whatever set of colors we like. styles/globals.css ------------------ This file is a regular CSS file that can contain whatever CSS is not bound to a specific module. Don\'t overuse it. CSS files are less powerful than SCSS files. components/genericComponents/Person/Person.js --------------------------------------------- This page represents the person we want to show the resume from. import React, { Component } from \"react\"; import css from \"./Person.module.scss\"; import { storyblokEditable, StoryblokComponent } from \"\@storyblok/react\"; export default class Person extends Component {     constructor(props) {         super(props);     }     render() {         return (             \                 \                     \                         \                             \C.V. {this.props.blok.firstname} {this.props.blok.lastname}\                         \                         \                             \\\                             \                                 \{this.props.blok.title} {this.props.blok.firstname} {this.props.blok.lastname}\                                 \{this.props.blok.dateofbirth}\                                 \{this.props.blok.location}\                             \                         \                         \                             \Experience\                             {this.props.blok.experiences.map((nestedBlok) =\> (                                 \                             ))}                         \                         \                             \© {this.props.blok.firstname} {this.props.blok.lastname} {new Date().getFullYear()}\                         \                     \                 \             \         );             } } The main part of this file is a few things to note: - {\...storyblokEditable(this.props.blok)}: this piece of code makes sure we can view and edit Person information in the Storyblok real time visual editor. - className={css\[\"wrapper\"\]}: instead of using the "class" HTML attribute, we use the "className" attribute. This attribute can be referenced from within linked SCSS files. So, if you use scss, use className instead of class. - C.V. {this.props.blok.firstname} {this.props.blok.lastname}: instead of having only static content such as the content you find in regular HTML files, we have a powerful template language at our disposal (JSX for those interested). The \"C.V.\" text will be shown on screen just like regular HTML content. Any code within curly braces will be replaced with actual data from our content management system. In this case, the actual first name and last name of the person we are looking at. - IMPORTANT: everything in the code we work with is Case Sensitive, meaning "startDate is different from startdate". Make sure the fields in your storyblok and the fields in your code have the exact same name, including the capitalization of letters. {this.props.blok.experiences.map((nestedBlok) =\> (    \ ))} - The code snippet shown above is complicated. The \"map\" function will traverse a list of items contained within the \"experiences\" variable. Every item can be referenced as \"nestedBlock\". Inside of the map method, we return a \"StoryblokComponent\" component, which is handed the nestedBlok as a parameter. NextJS will make sure the StoryblokComponent that is returned, is the actual needed component. In our codebase this could be either Person or Experience, and in this concrete example, it would be Experience, because the experiences variable we created in the person component in Storyblok could only contain experience bloks. - {new Date().getFullYear()}: inside of curly braces we can use whatever Javascript code we want, such as code that returns the current year. components/genericComponents/Person/Person.module.scss ------------------------------------------------------ This is the SCSS page linked to the Person.js page. SCSS pages, or SASS pages, use a superset of CSS. Using SCSS, we can e.g. use variables and mixins. These will be explained later. components/genericComponents/ Experience / Experience.js -------------------------------------------------------- Similar to the Person.js class, this class is loaded whenever we need to render a Storyblok \"experience\" component or \"block\". So, this file will be loaded twice if we link two \"experiences\" to a person in Storyblok. Everytime, the file would be fed different data. import React, { Component } from \"react\"; import css from \"./Experience.module.scss\"; import { storyblokEditable } from \"\@storyblok/react\"; import {RichTextToHTML} from \"../../../functions/storyBlokRichTextRenderer\"; export default class Experience extends Component {     constructor(props) {         super(props);     }     render() {         return (             \                 \                     \                         \{this.props.blok.startdate} - {this.props.blok.enddate}\                         \{this.props.blok.title}\                     \                     \                         {RichTextToHTML({ document: this.props.blok.description })}                     \                 \             \         );     } } We can notice one additional particular piece of code in this file: - {RichTextToHTML({ document: this.props.blok.description })}: whenever we need to render RichText fields, we can use this code snippet. In this case, the description field is a RichText field, so we use this code snippet. If the variable were named e.g. "articlebody" instead of "description", the snippet would be changed to {RichTextToHTML({ document: this.props.blok.articlebody })} components/genericComponents/ Experience / Experience.module.scss ----------------------------------------------------------------- \@import \"../../../styles/colors.scss\"; \@import \"../../../styles/font-mixins.scss\";.experienceitem {   margin: 40px 0; }.experienceheader {   margin-bottom: 10px; }.experiencedate {   background-color: \$color-blue-light;   font-size: 16x;   border-radius: 20px;   padding: 5px 10px;   margin-right: 20px; }.experiencetitle {   \@include very-small-title-font(\$color-grey-normal); } Here we see some of the power of scss: - \@import \"../../../styles/colors.scss\"; : if you want to use features from other files, such as variables or mixins, you have to include the relevant files by importing them. - background-color: \$color-blue-light; : here we use a variable defined in the colors.scss file. - \@include very-small-title-font(\$color-grey-normal); : here we use a font specification defined in the font-mixins.scss file.env.local ---------- this important file contains \"environment variables\". These are variables that are used throughout our code (and that we can keep in one place so it is easier to change them). The most important ones are the: - STORYBLOK\_API\_KEY: the code that allows us to connect to our StoryBlok CMS and get the data we need. This variable is used in the \_app.js file. - STORYBLOK\_PREVIEW\_SECRET: the secret code used for the preview of the site within StoryBlok. This variable is used in the pages/api/preview.js file. It is VERY important to note that we have decided NOT to include this file in our GitHub repo (it is not by default), so you will not have this file, and your site will not work on your local computer because of this (since your site will not have the secrets needed to connect to StoryBlok). Make sure you create this file yourself. In addition, these files will not be provided to Vercel, so your online website will not work either. We will discuss how to include these environment variables in Vercel later on. A screenshot of a computer Description automatically generated with medium confidence You will have to change the values for the KEY and SECRET variables to your own values. We will discuss how later. Running and debugging the site on your local PC =============================================== In order to run our project, we need to install an https proxy (because we can only communicate between our local PC and Storyblok over a secure connection), and some additional modules. Installing Node and NPM ----------------------- Node is a server-side javascript framework. In short, it allows you to use javascript to create server-side programs, such as command-line tools or server scripts. The Node Package Manager (NPM) is a node-based package manager. A package manager can be used to install software packages on a computer. More specifically, we will use it to install packages (additional software) that can enhance our own website. The Node Version Manager (NVM), is a program that allows you to install, and use, versions of node and NPM on your computer. It is helpful in installing node, but becomes even more useful if you need to use more than one version of node, since it will allow you to easily switch between versions of node. - Use one of these handy guides to install nvm-windows (if you are on windows): - [ ] - - If you are on OS X, you have two options. - If you also want to use the node version manager, so that you can switch between node versions if required, you can follow this guide : - If you just want Node and NPM, use this guide : - Now, having installed nvm, it is easy to install the 18.18.2 version of node using a command window as admin - Start a command window as administrator ![A screenshot of a computer Description automatically generated with medium confidence](media/image8.png) - executing the code (does not matter in which folder): nvm install 18.18.2 (on Windows) or nvm \--install 18.18.2 (on Linux of MacOS) - Now you can check which version of node is installed by executing: - Node version or node \--version (there are two dashed in front of the version word) - If you execute nvm list (or nvm ls on Linux or Mac), you can a list the installed node versions (mine are a bit different, but you should see 18.18.2 here) Text Description automatically generated Installing an HTTPS proxy ------------------------- The HTTPS proxy will allow for secure communication between our local development PC and the Storyblok CMS. Follow the steps on these pages, only up until you execute "npm install -g local-ssl-proxy" to install the HTTPS proxy: - Windows: - Mac: Do not execute the rest of the steps, as they will be handled by our VSCode debugging setup automatically Installing supporting modules ----------------------------- Do this by opening the terminal in VSCode, and running \"npm install\" ![Text Description automatically generated](media/image10.png) This will create the node\_modules folder and install everything we need for a running site. Storyblok and the env.local environment variables ================================================= Next, don\'t forget to check if you have created the.env.local file. There are two critical changes to make. 1. Change the value of the STORYBLOK\_API\_KEY to the value you see in your StoryBlok settings: Graphical user interface, application Description automatically generated 2. Create your own STORYBLOK\_PREVIEW\_SECRET variable. Set it to whatever code you want (e.g. 1231efg352536av5124). Now, go to the settings/visual editor page, and create these two \"preview URLs\". Be sure to replace the text "YOUR\_STORYBLOK\_PREVIEW\_SECRET\_GOES\_HERE" with your own value for the preview secret: - Preview: - Exit Preview: Finally, set the Location for the default environment (at the top of the settings/visual editor page) to. Do not forget the ending forward slash. This will allow your StoryBlok instance to show the content of your local dev webserver inside its Real Time visual editor frame. Now, run the website in debugging mode by opening the debug tab in your sidebar in VSCode, and click on the \"Play\" icon at the top. In your right-hand corner, an extra bar should appear that allows you to control the server. ![A screenshot of a computer Description automatically generated with medium confidence](media/image13.png) Now, open your server, and navigate to (or whatever person you added in Storyblok). You should see your resume! Graphical user interface, text, application, chat or text message Description automatically generated If you now navigate to your own person in StoryBlok, you should be able to see the resume in the visual editor window: ![Graphical user interface, application Description automatically generated](media/image15.png) Building your site to prepare for production ============================================ If you run "npm run build" in the terminal, you will build the site in the same way that Vercel will build it when it prepares a new production deployment: Text Description automatically generated If this command finishes without issue, you can be sure that the site will also build on Vercel. Deploying to Vercel =================== Deploy the project to Vercel just like we discussed in Part 1. One change that you will have to make is to set the environment variables before you push the deploy button (I still have to add the second variable in the example below): ![Afbeelding met tekst Automatisch gegenereerde beschrijving](media/image17.png) After hitting the deploy button, your site should be ready after a few moments: Graphical user interface, text, application Description automatically generated If you forgot to set the environment variables, you can still set them after the failed build. Go to Project\>Settings\>Environment Variables for your new project, and add the same variables as the ones we have in our env.local file by entering the NAME and VALUE for each of them: ![Graphical user interface, application, email Description automatically generated](media/image19.png) Now, trigger a new build. You can do this from the \"Deployments\" page. If you select the highest build, you can choose to redeploy to Production. You could also make a small code change and check in the changes -- this also triggers a build. Graphical user interface, text, application, email Description automatically generated Let the build and deployment finish successfully, and then you can visit the site. Notice the URL is now the publicly accessible URL. ![Graphical user interface, text, application, chat or text message Description automatically generated](media/image21.png) Making a small change in the code and have it reflected online ============================================================== Now that we have a perfectly working online version of our resume, make a small change to the code (e.g. change a color in an scss file), check in your changes, and make sure the change is reflected online. In the example below, we used different colors for the experiencedate and the experiencetitle. A screenshot of a computer Description automatically generated with medium confidence ![Graphical user interface, text, application, chat or text message Description automatically generated](media/image23.png) Making a small change in the content and have it reflected online ================================================================= Because our site is statically generated, in order to optimize for speed, we not only need to rebuild our site when code is changed, but also when content is changed. For this, we can use deployhooks and webhooks. A deploy hook in Vercel is a unique URL that is called by external software in order to trigger a new deployment. A webhook is an event that allows software, such as Storyblok, to call certain methods (in this case the deploy hook) in certain instances, in this case by Storyblok when we save and publish content. So there are two parts to this story: 1. The Deploy Hook: in your Vercel admin interface, go to Settings\>Git, and scroll down to \"Deploy Hooks\". Create a Deploy Hook by giving it a name and a branch that you want to deploy when this deploy hook is called. The name is freely chosen (e.g. Content Changed), and the branch should be \"master\", since that is the name of the branch we have in our GitHub. Graphical user interface, text, application Description automatically generated 2. Now, go to StoryBlok, and paste the URL generated by Vercel in the \"Story published and unpublished\" field and save your changes. ![Graphical user interface, application Description automatically generated](media/image25.png) Now, change some data, and make sure the changes are reflected online. In the example below, I changed my name to my proper name again, and changed one of the descriptions of an experience. Save, and publish. Changes on your local site are visible right away. It will take some time for the deployment to finish, so check out your online site after a minute or two. Graphical user interface, text, application Description automatically generated ![Graphical user interface, text, application, chat or text message Description automatically generated](media/image27.png) The order of code execution =========================== If you were wondering how your code will process an incoming request while developing, this is the way: 1. \[\[\...slug\]\].js/getStaticPaths: gets all possible paths that might be rendered by the server 2. \[\[\...slug\]\].js/getStaticProps: gets the data for the current path (URL) 3. \_app.js/MyApp: 4. \[\[\...slug\]\].js/Page: connects the page to the visual editor, and initializes the page. 5. Any other components that are returned from the \[\[\...slug\]\].js/Page function, such as the HeadComponent, and a dynamic StoryblokComponent component that loads whatever component is necessary (such as Person or Experience) If we deploy to Vercel, we are statically generating the site, which means we generate html/css/js files which are presented to the user. This files are blindingly fast and can be cached all over the world in a Content Delivery Network. Notes on the development process ================================ Now that we went through all the steps, the time is right for a recap of the structure of what we are creating, and the process we have been going through to get our website online. First, let\'s take a look at the structure: Graphical user interface, application Description automatically generated **What system do we create?** There are four main parts to the structure: 1. The content repository: we ware using StoryBlok as the Content Management System to manage the content of our website. 2. We are creating a Next.JS website to present this content to the user. 3. Still to come: our website produces data which is captured using analytics tools such as Google Analytics and HotJar. Google Analytics is a generic \"web analytics\" tool, and HotJar is a so called \"session analytics\" tool, that records detailed information about each session, and that will allow you to see exactly how people are using your website. 4. Still to come: Our website will communicate with user communication tools such as SendInBlue and Tawk.to. SendInBlue is an e-mail communication tool, and Tawk.to is a chat tool. **How do we create this system?** We create these pieces of software by developing on our local computer, testing using VSCode or Chrome Developer tools, and finally pusjing to GitHub through the Git system. **How do we present this to the world?** Finally, we use Vercel to present our software to the end user. Vercel is the SAAS hosting service we use as a web server. **How does the development process work?** Looking at the creation process as a whole provides us with this view: ![Graphical user interface, application Description automatically generated](media/image29.png) 1. First, we develop our site in our local environment 2. Second, we test our code in our local environment, using a combination of tools, such as our IDE (Visual Studio Code) and Chrome Developer Tools 3. Third, once we are happy with our changes, we push them to our online repository (GitHub in our case) 4. Fourth, we deploy our changes to a \"production\" environment, so people can actually visit our website online. In our case, this happens automatically when Vercel notices changes to our GitHub repo. Vercel will download those changes, build the software, and store or \"deploy\" it in a location where it can be seen, and hosted, by the webserver. 5. Users can visit, and developers can celebrate. This is a simple version of the development process. In a real-real development environment, you would likely have various levels of deployment, such as an \"integration\" and a \"testing\" environment in addition to a production environment. The \"integration\" environment would be used to test the software in conjunction with other pieces of software it needs for its operation. E.g. if your software needs to collaborate with a financial software package, but you can\'t test this on your local PC, you could use the integration environment to test your changes. The \"acceptance\" environment would than be used so that testers or specifically designated end-users of your software could test your changes before the rest of the world sees them.

Use Quizgecko on...
Browser
Browser