Manual setup

Manually integrate Makeswift with your Next.js app.

AnchorBefore you start

The fastest way to get started with Makeswift on a new Next.js project is to follow our getting started guide. If you have an existing Next.js application or want to set things up yourself, continue with the rest of this guide.

AnchorCreate a project

First, we need a Next.js project. If you don't already have one, the easiest way to get one set up is with Create Next App. Feel free to change the name from makeswift-app to something else.

npx create-next-app makeswift-app
cd makeswift-app

AnchorInstall Makeswift dependencies

Then, let's install the @makeswift/runtime package. This package contains all of the necessary code to integrate Makeswift into your Next.js app.

npm install @makeswift/runtime

or

yarn add @makeswift/runtime

AnchorAdd the Makeswift Next.js plugin

Add the Makeswift Next.js plugin to next.config.js. This is necessary to configure next/image with Makeswift domains, support Makeswift's integration with Next.js Preview Mode, and support code-splitting via next/dynamic for builtin components.

// next.config.js
const withMakeswift = require('@makeswift/runtime/next/plugin')()

const nextConfig = {
  /* Your Next.js config... */
}

module.exports = withMakeswift(nextConfig)

AnchorAdd the Makeswift API handler

We'll then add the Makeswift API handler. If you're familiar with NextAuth.js, this works in a similar way. Create the file pages/api/makeswift/[...makeswift].js. It's important that the file has that exact name, excluding the extension, which can be ts if you're using TypeScript.

import { MakeswiftApiHandler } from '@makeswift/runtime/next'

export default MakeswiftApiHandler('<makeswift_site_api_key>')

This API route will add support for Preview Mode, On-demand Revalidation, and other features that make Makeswift work seamlessly with your Next.js app.

You need to provide your Makeswift site API key as the first argument to the API handler function. You can get your API key from your Makeswift site settings. We recommend using environment variables for your site API key.

Site API key

AnchorSet up custom Document

Next we'll add a custom Document. The custom document will properly handle styles during server-side rendering and use Next.js' Preview Mode when opening your pages in the Makeswift builder.

Create the _document.js page and export Document from @makeswift/runtime/next.

// pages/_document.js

export { Document as default } from '@makeswift/runtime/next'

If you already have a _document.js, you can update it to extend the Document from @makeswift/runtime/next.

AnchorAdd a route for Makeswift pages

Let's create a new optional catch-all route named [[...path]].js. In this route we'll fetch and render your Makeswift pages.

We'll use the Makeswift API to fetch page data in getStaticProps and getStaticPaths. The Makeswift Page component will take care of rendering your pages.

// pages/[[...path]].js

import { Makeswift, Page as MakeswiftPage } from '@makeswift/runtime/next'

export async function getStaticPaths() {
  const makeswift = new Makeswift('<makeswift_site_api_key>')
  const pages = await makeswift.getPages()

  return {
    paths: pages.map((page) => ({
      params: { path: page.path.split('/').filter((segment) => segment !== '') },
    })),
    fallback: 'blocking',
  }
}

export async function getStaticProps(ctx) {
  const makeswift = new Makeswift('<makeswift_site_api_key>')
  const path = '/' + (ctx.params?.path ?? []).join('/')
  const snapshot = await makeswift.getPageSnapshot(path, { preview: ctx.preview })

  if (snapshot == null) return { notFound: true }

  return { props: { snapshot } }
}

export default function Page({ snapshot }) {
  return <MakeswiftPage snapshot={snapshot} />
}

There's a lot going on here, so let's unpack it.

First, we import the Makeswift API client and Page React component to use in our Next.js page. We alias Page to MakeswiftPage to avoid naming conflicts.

import { Makeswift, Page as MakeswiftPage } from '@makeswift/runtime/next'

Then, we define our getStaticPaths function. You can read more about getStaticPaths in the Next.js documentation.

export async function getStaticPaths() {
  const makeswift = new Makeswift('<makeswift_site_api_key>')
  const pages = await makeswift.getPages()

  return {
    paths: pages.map((page) => ({
      params: { path: page.path.split('/').filter((segment) => segment !== '') },
    })),
    fallback: 'blocking',
  }
}

There's a couple of important things to note here:

  1. You need to provide your Makeswift site API key to the Makeswift constructor. This is the same API key you used when configuring the Makeswift API handler.

  2. We use fallback: 'blocking'. This is important so that your Next.js app doesn't need to be re-deployed whenever a new Makeswift page is created.

We then fetch our page's data with getStaticProps.

export async function getStaticProps(ctx) {
  const makeswift = new Makeswift('<makeswift_site_api_key>')
  const path = '/' + (ctx.params?.path ?? []).join('/')
  const snapshot = await makeswift.getPageSnapshot(path, { preview: ctx.preview })

  if (snapshot == null) return { notFound: true }

  return { props: { snapshot } }
}

Things to note here:

  1. You'll need to provide your Makeswift site API key again. Just like we did for getStaticPaths and the Makeswift API handler.

  2. The path param is defined by the filename. If the file was named [[...slug]].js instead of [[...path]].js then the param would be named slug. Because this is an optional catch-all route, there will be no params when visiting the index (i.e., /) path so we have to default it to an empty array.

With this setup, your pages will be rendered using Incremental Static Regeneration. We don't need to add a revalidate field to the returned value of getStaticProps because Makeswift pages are automatically revalidated using On-demand Revalidation by levaraging the Makeswift API handler.

AnchorRegister components with Makeswift

We'll register components in a centralized file that we'll import in our Makeswift catch-all route. You can place this file wherever you want and give it any name you want. For this guide, we'll do lib/makeswift/register-components.js.

// lib/makeswift/register-components.js

import { ReactRuntime } from '@makeswift/runtime/react'
import { Style } from '@makeswift/runtime/controls'

function HelloWorld(props) {
  return <p {...props}>Hello, world!</p>
}

ReactRuntime.registerComponent(HelloWorld, {
  type: 'hello-world',
  label: 'Hello, world!',
  props: {
    className: Style(),
  },
})

Don't forget to import this file in your Makeswift page route.

  // pages/[[...path]].js

+ import '../lib/makeswift/register-components'
+
  import { Makeswift, Page as MakeswiftPage } from '@makeswift/runtime/next'

You can learn more about registering components here.

AnchorStart your local dev server

Run the local development script. This will start the Next.js app at http://localhost:3000.

npm run dev

or

yarn dev

If port 3000 is already in use, Next.js will try port 3001, then 3002, and so forth until an unused port is found. Take note of this port for the next step.

AnchorAdd your app's URL to Makeswift

Finally, you'll just need to add your app's URL to your Makeswift site settings. If you haven't changed anything in the example and it's running on port 3000, the value should be http://localhost:3000.

Preview URL

When you're ready to deploy, you'll probably set up a separate site and use your deployment URL instead of localhost. You can keep this site for local development.

AnchorStart building!

That's it! You should be able to create a page in Makeswift and start dropping in registered components.

You will find your registered components in the toolbar of the Makeswift builder. Drag and drop your components into your page and start building!

Registered components

You can learn more about registering components here.