/next-acms

ACMS with fully or progressively decoupled front-end

Primary LanguageTypeScriptMIT LicenseMIT

Next.js for Acquia CMS

This is a starter template for building a headless site powered by Acquia CMS and Next.js.

This project is built on the following technologies:

Installation (Acquia CMS)

Start by creating a new Acquia CMS project:

(If you have an existing Acquia CMS project, you can skip this step)

composer create-project acquia/drupal-recommended-project acms-demo
cd acms-demo && ./vendor/bin/acms acms:install

From the wizard, select the acquia_cms_headless starter kit and proceed to install Acquia CMS. We recommend using the default Content Model and the demo content so you can quickly see the content coming through your Next.js application.

Note: next-acms requires Acquia CMS 2.0 or later.

Login to Acquia CMS and go to Tour > Get started. From the Headless section on the CMS Dashboard, select the Next.js starter kit and click "Save". Acquia CMS should print a message with your Node environment variables. Copy these and proceed to the next step.

For more information on Acquia CMS setup please see the tutorial.

Installation (Next.js)

Run the following command to create a new Next.js project:

npx create-next-app -e https://github.com/acquia/next-acms/tree/main/starters/basic-starter

This will create a new starter project. See project structure.

Connect Drupal

To connect the Next.js site to Drupal, we use environment variables.

  1. Copy .env.example to .env.local.
  2. Paste in the credentials generated by Acquia CMS and save.

Start Development Server

To start the Next.js development server, run yarn dev. This starts the development server on http://localhost:3000.

Visit http://localhost:3000 to view the headless site.

Project Structure

This project is a monorepo structure using yarn workspaces. This project has a packages directory for next-acms and a starters directory for next-acms starter kits.

starters/basic-starter has a dependency on packages/next-acms which currently has a dependency on next-drupal.

.
|── node_modules
|── packages
  |── next-acms
  |  |── node_modules
  |  |── package.json
|── starters
  |── basic-starter
    ├── components
    │   ├── layout.tsx
    │   ├── media--image.tsx
    │   ├── menu--footer.tsx
    │   ├── menu--main.tsx
    │   ├── node--article.tsx
    │   └── node--page.tsx
    ├── lib
    │   └── format-date.ts
    ├── node_modules
    ├── pages
    │   ├── api
    │   │   ├── exit-preview.tsx
    │   │   ├── preview.tsx
    │   │   └── revalidate.ts
    │   ├── _app.tsx
    │   ├── [...slug].tsx
    │   ├── articles.tsx
    │   └── index.tsx
    ├── public
    │   ├── favicon.ico
    │   ├── logo.png
    │   └── robots.txt
    ├── styles
    │   └── globals.css
    ├── .env.local
    ├── next.config.js
    ├── package.json
    ├── tailwind.config.js
    └── tsconfig.json
|── .gitignore
|── package.json
Path Description
components Place your React components here.
lib For utility or helper functions.
pages Learn more about the pages directory here
public For static files.
styles Directory for CSS files.
.env.local File for local environment variables.
next.config.js Configuration file for Next.js.
tailwind.config.js Configuration file for Tailwind CSS.

Routing

The starter ships with static routes for building collection of content: pages/articles and an entry point, [...slug].tsx, for entity routes.

The [...slug].tsx route is called a catch-all route.

When you create an entity on Drupal, and visit the route on your headless site, this is the file that handles data fetching and rendering for the entity.

You can read more about routing in Next.js on the official docs.

Preview Mode

To enable the inline content preview inside Drupal, we need to configure a site resolver for the content type.

A site resolver tells Drupal how to resolve the preview URL for an entity.

Configure preview mode for article

  1. Visit /admin/config/services/next/entity-types
  2. Click Configure entity type
  3. Select Article from the the entity type list
  4. Select Site selector as the Site resolver
  5. Select the Next.js site under Next.js sites
  6. Click Save

If you visit an article from the Drupal administration, you should now see an inline preview inside an iframe.

Repeat the same steps for other content types.

Data Fetching

To build pages from Drupal content, data is fetch in getStaticProps and passed to the component.

See the documentation on data fetching in next-drupal.

Adding a new entity type.

To create headless pages for a new content type:

  1. Start by creating the content type, say News, on Drupal.
    • Define the fields: title, field_teaser and body.
    • Add a path alias for the content type: news/[node:title].
  2. On the Next.js site, edit [...slug].tsx to fetch news from Drupal.
  3. Add node--news to CONTENT_TYPES:
// List of all the entity types handled by this route.
const CONTENT_TYPES = [
  "node--page",
  "node--article",
  "node--event",
  "node--person",
  "node--place",
+ "node--news",
]
  1. In getStaticProps, build the query for fetching the node--news with the fields:
+ if (type === "node--news") {
+ 	params
+ 		.addFields("node--news", ["title", "path", "field_teaser", "body])
+ }
  1. Add a news on Drupal and visit the path on your Next.js site: http://localhost:3000/news/title-of-news.
  2. If you add a console.log(node) in the NodePage component you should see the node--news data.
export default function NodePage({ node, menus }: NodePageProps) {
  if (!node) return null

+ console.log(node)
  1. You can now use this node--news object to create the <NodeNews /> component.
export default function NodePage({ node, menus }: NodePageProps) {
  if (!node) return null

  return (
    <Layout title={node.title} menus={menus}>
      {node.type === "node--page" && <NodeBasicPage node={node} />}
      {node.type === "node--article" && <NodeArticle node={node} />}
      {node.type === "node--event" && <NodeEvent node={node} />}
      {node.type === "node--person" && <NodePerson node={node} />}
      {node.type === "node--place" && <NodePlace node={node} />}
+     {node.type === "node--news" && <NodeNews node={node} />}
    </Layout>
  )
}

Reporting a Security Issue

If you believe you have found a security vulnerability in an Acquia product or service, we encourage you to responsibly disclose this and not open a public issue. We will investigate all legitimate reports. Please email the details to our security team at security@acquia.com.

https://www.acquia.com/why-acquia/industries/security