Adding Uniform to Create Next App

18th Nov 2021

Adding Uniform to Create Next App

I have found it super easy to add Uniform Canvas to a bare-bones NextJs app. I thought I would show you what it takes to go from Zero to Hero with a very basic setup. This will then give a good foundation to add more things on top.

Create Next App

I'll start with the familiar, I'll use yarn create next-app --ts to generate a bare-bones NextJs application with TypeScript.

yarn create next-app --ts
...
✨ Done in 13.16s.
Initialized a git repository.
Success! Created zero-to-hero at /Users/davetayls/projects/test-projects/zero-to-hero
Inside that directory, you can run several commands:

Add some Uniform Packages

There are two packages I need to get started with a React application:

  1. @uniformdev/canvas to use core canvas utilities
  2. @uniformdev/canvas-react to use React specific components

Setup the Uniform Canvas Client

The interaction with the Uniform APIs happens through an instance of CanvasClient so I will need to create that instance as well as setup a Uniform project to connect it to.

I created a new file src/uniform/uniformClient.ts and added the following code.

import { CanvasClient } from '@uniformdev/canvas'
export const uniformClient = new CanvasClient({
apiKey: process.env.UNIFORM_API_KEY,
projectId: process.env.UNIFORM_PROJECT_ID,
})

This same uniformClient can be used across the rest of the codebase.

Uniform Project Environment Variables

You will notice that the CanvasClient needs two environment variables so that it can connect to the right project. It will need UNIFORM_API_KEY and UNIFORM_PROJECT_ID. I have set these in a .env file in the root of the application.

First, I need to create a project and get those values.

Create a new Uniform Project
Create a new Uniform Project

Then I need to create an API key to use locally (don't worry, this project and API key no longer exists!) 🚨

The final .env file now looks like this:

UNIFORM_API_KEY=my-api-key
UNIFORM_PROJECT_ID=my-project-id
Create an API Key
Create an API Key

Basic Empty Enhancers

Uniform doesn't store your data, it just stores pointers and IDs to the various systems you want to integrate with. This simplifies access to the connected systems and keeps the orchestration of them simple.

I still need the actual data within those systems to be able to render components on a website. This is where enhancers come in, they take the raw uniform data and add the values for those pointers from each system you have configured.

I'm not going to connect anything for this example, I can look at that later. What I want to do is setup an empty EnhancerBuilder so that I can add enhancers later.

I will put this into a new file src/enhancers/index.ts.

import { EnhancerBuilder } from '@uniformdev/canvas'
export const enhancers = new EnhancerBuilder()

Convert the Main Section into Components

My next job is to convert the <main> section of the index.tsx page into Uniform components.

This means I will have 3 basic components in my components folder:

  1. Title
  2. ContentBlock
  3. Grid

I have just copied the components exactly, I will look at connecting them to external content at a later date. So the following JSX gives me the exact same page as I started with:

<main className={styles.main}>
<Title/>
<ContentBlock/>
<Grid/>
</main>

But that's not where I want to go, I'll create these components in Uniform Canvas.

btw - these components can also be created in yaml files and synced to a project. I'll want to keep these definitions in the codebase later on.

Add a Grid Component
Add a Grid Component

I can then add a "Composition" which is basically a component which can be used like a layout. I'll add a single "slot" which is a place to put other components. In this slot I will allow all three of my new components.

Add a Composition Component
Add a Composition Component

That deals with the component I will use for my main composition. Now to actually create the composition and add my three components in to it.

Add my components to a new page composition
Add my components to a new page composition

Build the Components from Uniform Canvas

Now for the final piece of the puzzle. I need a function which will return a React component based on the ID.

I'll create a file src/components/resolveRenderer.ts

import { ComponentType } from "react"
import { ComponentProps, RenderComponentResolver } from "@uniformdev/canvas-react"
import { Title } from './Title'
import { ContentBlock } from './ContentBlock'
import { Grid } from './Grid'
const componentMap = new Map<string, ComponentType<ComponentProps>>([
['Title', Title],
['ContentBlock', ContentBlock],
['Grid', Grid]
])
export const resolveRenderer: RenderComponentResolver =
({ type }) => componentMap.get(type) || null

I can then include the composition data in getStaticProps.

import { uniformClient } from "../src/uniform/uniformClient"
import { ComponentInstance, enhance } from "@uniformdev/canvas"
import { enhancers } from '../src/enhancers'
//...
export const getStaticProps: GetStaticProps = async (
context
) => {
const { composition } = await uniformClient.getCompositionBySlug({
slug: '/home',
})
await enhance({ composition, enhancers, context })
return { props: { composition } }
}

And finally I use the Composition component inside the <main> tag to render the components we had before.

import { Composition, Slot } from '@uniformdev/canvas-react'
import { resolveRenderer } from "../src/components/resolveRenderer"
// ...
interface HomeProps {
composition: ComponentInstance
}
const Home: NextPage<HomeProps> =
({ composition }) => {
//...
<main className={styles.main}>
<Composition
data={composition}
resolveRenderer={resolveRenderer}>
<Slot name="main" />
</Composition>
</main>
Zero to Hero
Zero to Hero

Now to build out the app...

That is it, the app is now ready to build. I have all the usual NextJs tools and functionality at my disposal and can inject Uniform Compositions, Personalisation and Testing wherever I want to use them.

This series: