Loading
Tutorial

"Two years ago, I embarked on a journey to build my own custom CMS and Page Builder. Instead of relying on cloud solutions like Builder.io, I challenged myself to create a flexible and scalable solution tailored to my needs. Today, I’m excited to share this project with the community as an open-source tool, available for anyone to clone and explore from here Github Repository 👈. Dive in and see how you can leverage this platform for your projects!" 

A. El Kaimouni

Building High-Performance Websites with Custom CMS and Visual Page Builder 

Creating a high-performance, dynamic website from a static HTML, CSS, and JavaScript template can be a challenging task. However, with my custom CMS and visual page builder, this transformation becomes not only achievable but also highly efficient. This powerful framework is designed to streamline your web development process, ensuring optimized performance and ease of use.

Powered by React and Next.js, and utilizing TypeScript and MongoDB, my custom CMS and visual page builder provide a robust foundation for developing high-performance sites. What sets this framework apart is its ability to convert traditional static templates into dynamic, React-based templates, enhancing both functionality and user experience.

In this tutorial, I will guide you through the process of converting a static template into a dynamic React template. You'll learn how to integrate my custom CMS, which allows for effortless content management, and the visual page builder, which enables real-time, visual editing of your website. These tools are designed to simplify your workflow, allowing you to focus on creativity and optimization.

By following these steps, you’ll discover how easy it is to bring modern web technologies into your projects, creating websites that are not only visually stunning but also exceptionally performant. This guide is perfect for developers looking to enhance their web projects with advanced content management and visual editing capabilities.

Join me as we explore the practical steps of leveraging my custom CMS and visual page builder to elevate your web development projects to new heights.

Benefits of Using My Custom CMS and Visual Page Builder Framework

Using my custom CMS and visual page builder framework brings numerous benefits to your web development projects. Here are some key advantages: 

  • Enhanced Performance: Built with React and Next.js, my framework ensures your website runs smoothly and efficiently, providing a high-performance user experience.
  • Effortless Content Management: The custom CMS allows you to manage your content with ease, enabling quick updates and seamless integration of new content without diving into the code.
  • Visual Editing: The visual page builder empowers you to make real-time changes to your website’s layout and design, allowing for instant feedback and rapid iterations.
  • Modern Technology Stack: Utilizing React, Next.js, TypeScript, and MongoDB ensures your website is built on a robust, future-proof foundation.
  • Time Efficiency: Streamlining the development process, the framework reduces the time and effort required to convert static templates into dynamic, React-based templates.

Project Structure Overview

When using my framework, the project structure focuses on simplicity and efficiency, emphasizing key elements essential for building and managing your website. Here's a breakdown of the main components you'll interact with:

  • Interface Folder: This folder acts as the foundation of your project, structured as a Next.js 12 project. It includes:
    • Sections Folder: Contains all defined components used within our visual page builder. These components form the building blocks for constructing your web pages.
    • builder.config.js: This configuration file centralizes settings and configurations for our visual page builder. It defines how components interact and behave within the builder interface.
  • Models Folder: Here, you define data models that are editable via the CMS dashboard. These models facilitate dynamic content management, allowing you to structure and organize data as per your website's requirements.
  • Templates Folder: Provides predefined page structures that serve as templates for building new pages. These templates offer a starting point, helping you expedite the creation of consistent and structured web pages.

This streamlined structure ensures that you focus on essential components necessary for building and managing your website effectively using my custom CMS and visual page builder framework. 

Project Setup

Setting up your project with my custom CMS and visual page builder framework is straightforward. Follow these steps to get started:

1. Install Dependencies: Begin by installing the necessary dependencies. You can do this by running: 

npm install

2. Setup Cloudinary: create a cloudinary account and obtain your cloud name and api key and secret and put them in .env file. Cloudinary is the cloud that we gonna use store and optimize our media, its an ideal option to serve media in optimzed way.

CLOUD_NAME= YOUR_CLOUD_NAME CLOUD_API_KEY= YOUR_API_KEY CLOUD_API_SECRET= YOUR_API_SECRET

3. Setup MongoDB Connection: Connect with your mongoDB database locallty if you have it installed on your computer or use a remote one, specify the host and database name in .env file

DB_HOST= YOUR_DB_HOST DB_NAME= YOUR_DB_NAME

3. Start the Development Server: Once the dependencies are installed, start the development server with: 

npm run dev

4. Create Your First Admin User:

  • Open your browser and navigate to http://localhost:2002/admin.
  • Follow the prompts to create your first admin user.

5. Create a Domain:

  • In the admin panel, create a new domain. A domain represents your website, encompassing a collection of pages.
  • Refresh the admin panel after creating the domain.

6. Configure Your Next.js App:

Point your Next.js app to the created domain to fetch the necessary data by opening the browser’s console and looking for a status request that contains information about your domain. Grab the domain ID from this request and configure it in your environment variables file (.env) by adding the following line, replacing YOUR_DOMAIN_ID with the actual ID. 

NEXT_DOMAIN_ID= YOUR_DOMAIN_ID

7. Create and Associate Pages:

  • With your domain set up, you can now create pages in the admin panel.
  • Associate these pages with your domain to ensure they are part of your website. 

Importing Your HTML, CSS, and JS Template

After setting up the project and configuring your domain, the next step is to import your existing HTML, CSS, and JavaScript template into the project. Follow these steps:

Import CSS/SCSS Files:

  • Import your CSS or SCSS files into the Next.js _app.tsx file for global styles or into the _document.tsx file using the classic <link> tag. This ensures that your styles are properly applied throughout the application.
  • I recommend the second method to enable the laze loading of your styles to enhance your website performance

Handle JavaScript Files:

  • It is recommended to rewrite the document manipulation logic with React to ensure functionality and performance. This approach leverages React’s lifecycle methods and state management, providing a more robust solution.
  • If you choose to import JavaScript files directly, you can do so like CSS files. However, be aware that this may cause issues due to the lifecycle of React apps.

Convert and Import HTML Files:

  • Convert your HTML files to JSX format using tools like HTML to JSX.
  • Import the converted JSX components as needed into your project. This step is crucial for integrating static HTML content into your React components effectively.

By following these steps, you can successfully integrate your existing HTML, CSS, and JavaScript templates into your Next.js project, ensuring a smooth transition to a high-performance, React-based application. 

Importing Components into the Visual Page Builder

To integrate your HTML, CSS, and JS template with the visual page builder, you need to create a section file in the sections folder of your Next.js project. Here’s a detailed explanation of how to set up and use this section file:

Create a Section File:

In the sections folder, create a new file for your component. The structure of this file will include defining the props, setting up the schema, and converting the HTML to JSX.

Define the Props Interface:

Use TypeScript to define an interface for your component’s props. The props interface specifies the data types and structure of the component's properties using generic types WC<Type> and WCList<Type>.

  • WC<Type>: Used for single data types.
  • WCList<Type>: Used for lists of data. 

1 2 3 4 5 6 import { WC, WCList } from '../builder/types'; interface Props { title: WC<string>; items: WCList<string>; }

Set Up the Schema:

  • Define a props variable to describe the schema and types of each field. Use predefined functions for different data types. 

1 2 3 4 5 6 7 8 9 import { StringField, BooleanField, NumberField, ListField, ModelField } from '../builder'; const props = { title: StringField({ type: 'short', default: 'Default Title' }), items: ListField({ props: StringField({ type: 'short' }), default: ['Item 1', 'Item 2'] }) };

Convert HTML to JSX:

  • Convert your HTML template to JSX format using tools like HTML to JSX.
  • Replace static values with dynamic values from the page builder. Note that each data piece comes with two props: the data itself and its address. For thet we used the WC and WCList interfaces to describe our schema.
  • There also some extra props come with our section data to specify its address and type, for that we get thos props using ...props syntax and use them with c function to make a reference to our section

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 import { useBuilderContext } from '../builder'; const MyComponent = ({ title, items, ...props } : Props) => { const { c } = useBuilderContext(); return ( <div {...c(props)}> <h1 {...c(title)}>{title[0]}</h1> <ul {...c(items)}> {items[0].map((item, index) => ( <li key={index} {...c(item)}>{item}</li> ))} </ul> </div> ) };

Export the Component Information:

Finally, export an object containing the component's name, JSX component, and its props. 

1 2 3 4 5 6 7 import { BuilderComp } from "../builder/types"; export const componentInfo : BuilderComp = { name: 'My Component', comp: MyComponent, props };

Importing Components to builder.config.ts

To complete the integration of your components into the visual page builder, you need to configure the builder.config.ts file. This file contains the main configurations for your page builder, including sections, components, and elements. Additionally, it defines schemas for important data, such as page information and theme settings, and specifies the devices supported by your website.

Here’s a step-by-step guide to setting up the builder.config.ts file:

Import Your Created Component:

First, import the component you created in the sections folder into the builder.config.ts file. 

1 import MyComponent from './sections/MyComponent';

Define Sections, Components, and Elements:

  • Split your website components into three groups: sections, components, and elements.
  • Sections include large parts of the website, like headers or footers.
  • Components and elements are smaller and can be integrated into sections using DynamicZones. 
  • each componenet must belong to a group.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 const sections = { group: [ MyComponent, // Add other sections here ] }; const comps = { // Add smaller components here }; const elements = { // Add elements here };

Define Info and Theme Props:

  • The pageProps prop defines the schema for important data that each page should have, such as meta titles and descriptions.
  • The themeProps prop defines the schema for data that affects the entire website, such as theme colors and website mode. 

1 2 3 4 5 6 7 8 9 10 11 12 const pageProps = { metaTitle: StringField({ type: 'short', default: 'Default Meta Title' }), metaDescription: StringField({ type: 'long', default: 'Default Meta Description' }) }; const themeProps = { colors: { primary: StringField({ type: 'short', default: '#000000' }), secondary: StringField({ type: 'short', default: '#FFFFFF' }) }, mode: StringField({ type: 'enum', enums: ['light', 'dark'], default: 'light' }) };

Define Supported Devices:

The devices prop describes the media devices supported by your website and provides information about their sizes. 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 import { BuilderDevice } from "./builder/types"; const devices : BuilderDevice[] = [ { name: "mobile", range: [320, 575], icon: "mobile" }, { name: "tablet", range: [575, 993], icon: "tablet" }, { name: "flipped phone", range: [993, 1200], icon: "tablet2" }, { name: "laptop", range: [1200, Infinity], icon: "laptop" } ];

Export the Configuration:

Export the configuration object that includes the sections, components, elements, info, theme, and devices props. 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 const builderConfig : BuilderProps = { api: { baseURL: `${config.env.SERVER_HOST}/cms/`, headers: { authorization: config.env.SERVER_SECRET } }, info: { elements, comps, sections, pageProps, themeProps, devices, locales: locales.locales, defaultLocale: locales.locales.find(locale => locale.id === locales.defaultLocale).id, } }; export const builder = new Builder(builderConfig); export default builderConfig;

Adding Locale Configurations

In addition to the component and theme configurations, your visual page builder also supports locale configurations. These can be edited in the global config folder located at /config/data/locales.config.json. Here’s how you can include locale settings in your setup:

This file contains the locale configurations for your page builder. You can define the supported languages and their respective settings here. 

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 { "locales": [ { "name": "English", "ext": "en", "id": "en" }, { "name": "French", "ext": "fr", "id": "fr" } ], "defaultLocale": "en" }

Data Types and Their Properties

When defining the schema for your component’s props in the visual page builder, you’ll use various data types provided by the framework. Here’s a detailed explanation of each data type and their respective properties:

StringField({ type, default, enums? })

Defines a string field with specific rendering options.

  • type: Controls the way the field is rendered in the page builder.
    • short: A short input field.
    • long: A long input field.
    • styled: A rich text editor.
    • enum: A select input with multiple values specified by the enums prop.
  • default: Specifies a default value for the field. 

1 StringField({ type: 'short', default: 'Default Text' })

BooleanField({ default })

Defines a boolean field.

  • default: Specifies a default value (true or false). 

1 BooleanField({ default: true })

NumberField({ type, default })

Defines a numeric field with options for integer or float values.

  • type: Specifies whether the number is an integer or a float.
    • integer
    • float
  • default: Specifies a default value.
  • min: Minimum value allowed.
  • max: Maximum value allowed. 

1 NumberField({ type: 'int', default: 10, min: 0, max: 100 })

ListField({ props, default })

Defines a list of items, each with its own props.

  • props: Object of props, using the same field functions as defined previously.
  • default: Specifies a default list of values. 

1 2 3 4 ListField({ props: StringField({ type: 'short' }), default: ['Item 1', 'Item 2'] })

ModelField({ model, query, default })

Fetches data from the CMS for a specific model.

  • model: The target model to extract data from.
  • query: Specifies the fields to fetch, using a syntax similar to GraphQL.
  • default: Specifies a default value. 

1 ModelField({ model: 'Post', query: '{ id title }', default: { id: '1', title: 'Default Title' } })

Conclusion

In this blog, we've taken a significant step towards leveraging my custom visual page builder framework to convert a static HTML, CSS, and JavaScript template into a dynamic React-based template powered by a custom CMS. We covered the project setup, including the necessary configurations and the integration of your first component. We also delved into defining component props and integrating these components into the builder configuration.

However, our journey doesn’t end here. In the next blog, we'll explore the intricacies of working with data models, utilizing Dynamic Zones for even greater flexibility, and finally, the process of building and deploying your project. Stay tuned for more insights and detailed guides to fully harness the power of this framework. 

"Two years ago, I embarked on a journey to build my own custom CMS and Page Builder. Instead of relying on cloud solutions like Builder.io, I challenged myself to create a flexible and scalable solution tailored to my needs. Today, I’m excited to share this project with the community as an open-source tool, available for anyone to clone and explore from here Github Repository 👈. Dive in and see how you can leverage this platform for your projects!" 

A. El Kaimouni

0 Comments

    Leave a Comment

    Your email address will not be published, Your image will be extracted from your linkedin account