Get started with Next.js
You must first create a project in Plasmic.
Overview
This covers integrating Plasmic into your existing Next.js codebase.
Want to quickly generate a new codebase with Plasmic already integrated? Use create-plasmic-app instead, or just press the Publish button in your project to push a new repo to GitHub!
Want to generate source code into your codebase? Learn about codegen.
Installation
npm install @plasmicapp/loader-nextjs# or yarn add @plasmicapp/loader-nextjs
Initialization
Initialize Plasmic with the project ID and public API token. Define this in its own module to make it available globally.
import { initPlasmicLoader } from "@plasmicapp/loader-nextjs";export const PLASMIC = initPlasmicLoader({ projects: [ { id: "PROJECTID", // ID of a project you are using token: "APITOKEN" // API token for that project } ], // Fetches the latest revisions, whether or not they were unpublished! // Disable for production to ensure you render only published changes. preview: true,})
To find your project’s ID and public API token: open the project in Plasmic Studio.
The project ID is in the URL, like: https://studio.plasmic.app/projects/PROJECTID
.
The public API token can be found by clicking the Code toolbar button.
Auto load all Plasmic pages
To automatically render all Plasmic-defined pages at the routes specified in Plasmic, create a Next.js catch-all page.
Create either:
pages/[[...catchall]].tsx
if you want the/
route to render the corresponding Plasmic page (you must remove any existingpages/index.tsx
), orpages/[...catchall].tsx
otherwise (your Plasmic project must not have a page whose route is/
—change the route to something else if you do).
In all cases, the Plasmic page will only be there if there is no existing page already in pages/...
for that route.
import * as React from 'react';import { PlasmicComponent, ComponentRenderData, PlasmicRootProvider } from '@plasmicapp/loader-nextjs';import { GetStaticPaths, GetStaticProps } from 'next';import Error from 'next/error';import { PLASMIC } from '../plasmic-init';
/** * Use fetchPages() to fetch list of pages that have been created in Plasmic */export const getStaticPaths: GetStaticPaths = async () => { const pages = await PLASMIC.fetchPages(); return { paths: pages.map((page) => ({ params: { catchall: page.path.substring(1).split('/') } })), fallback: 'blocking' };};
/** * For each page, pre-fetch the data we need to render it */export const getStaticProps: GetStaticProps = async (context) => { const { catchall } = context.params ?? {};
// Convert the catchall param into a path string const plasmicPath = typeof catchall === 'string' ? catchall : Array.isArray(catchall) ? `/${catchall.join('/')}` : '/'; const plasmicData = await PLASMIC.maybeFetchComponentData(plasmicPath); if (plasmicData) { // This is a path that Plasmic knows about; pass the data // in as props return { props: { plasmicData },
// Using incremental static regeneration, will re-generate this page // after 300s revalidate: 300 }; } else { // This is some non-Plasmic catch-all page return { props: {} }; }};
/** * Actually render the page! */export default function CatchallPage(props: { plasmicData?: ComponentRenderData }) { const { plasmicData } = props; if (!plasmicData || plasmicData.entryCompMetas.length === 0) { return <Error statusCode={404} />; } const pageMeta = plasmicData.entryCompMetas[0]; return ( // Pass in the data fetched in getStaticProps as prefetchedData <PlasmicRootProvider loader={PLASMIC} prefetchedData={plasmicData}> { // plasmicData.entryCompMetas[0].name contains the name // of the component you fetched. } <PlasmicComponent component={pageMeta.name} /> </PlasmicRootProvider> );}
Notes:
- You can use incremental static regeneration with
getStaticProps
.
Render a single Plasmic page or component
Note: You can instead auto-load all Plasmic pages at the correct routes (recommended) rather than manually loading individual pages—see previous section.
We use Next.js’s getStaticProps()
to fetch the design statically.
For example, to render a page: add a file under pages/
, named for your desired route, with the following code.
PATH_OR_COMPONENT
refers to the name of the page or component that you want to render, such as Winter22LandingPage
.
If it’s a page, you can also use the route you assigned the page in Plasmic, like /landing
.
// This page will show up at the route /mypage
import { initPlasmicLoader, PlasmicRootProvider, PlasmicComponent, ComponentRenderData} from '@plasmicapp/loader-nextjs';import { PLASMIC } from '../plasmic-init';
// Statically fetch the data needed to render Plasmic pages or components.export const getStaticProps = async () => { // You can pass in multiple page paths or component names. const plasmicData = await PLASMIC.fetchComponentData('PATH_OR_COMPONENT'); return { props: { plasmicData // ... } };};
// Render the page or component from Plasmic.export default function MyPage(props: { plasmicData: ComponentRenderData }) { return ( <PlasmicRootProvider loader={PLASMIC} prefetchedData={props.plasmicData}> <PlasmicComponent component="PATH_OR_COMPONENT" /> </PlasmicRootProvider> );}
Notes:
- You can skip
getStaticProps
to fetch dynamically at runtime. - Use
getServerSideProps
instead ofgetStaticProps
for SSR. - You can use incremental static regeneration with
getStaticProps
.
Add custom code components
Let your Plasmic Studio users drag/drop and visually manipulate any React component! (Learn more.)
Step 1
Create a simple example React component:
import React, { ReactNode } from 'react';
export interface HelloWorldProps { children?: ReactNode; className?: string; verbose?: boolean;}
export function HelloWorld({ children, className, verbose }: HelloWorldProps) { return ( <div className={className} style={{ padding: '20px' }}> <p>Hello there! {verbose && 'Really nice to meet you!'}</p> <div>{children}</div> </div> );}
Step 2
Add the following to your plasmic-init.ts
to register it:
import { HelloWorld } from './components/HelloWorld';// ...
export const PLASMIC = initPlasmicLoader(/* ... */);
PLASMIC.registerComponent(HelloWorld, { name: 'HelloWorld', props: { verbose: 'boolean', children: 'slot' }});
Step 3
Create a special hidden page at route /plasmic-host
.
import * as React from 'react';import { PlasmicCanvasHost } from '@plasmicapp/loader-nextjs';import { PLASMIC } from '../plasmic-init';
export default function PlasmicHost() { return PLASMIC && <PlasmicCanvasHost />;}
Step 4
Start your app:
npm run dev
And check that you see a confirmation message at http://localhost:3000/plasmic-host.
Step 5
Open https://studio.plasmic.app, click the menu for the current project, select "Configure project," and set it to http://localhost:3000/plasmic-host
.
Step 6
Re-open this project (or reload this tab) to see your component listed in the insert menu!
Later, after you deploy the route to production, update the project to use your production host URL instead,
such as https://my-app.com/plasmic-host
.
This way, other members of your team
(who can’t access your localhost dev server) will be able to open and edit the project in
Plasmic.
(Again, the /plasmic-host route itself is a special hidden route not meant for humans to visit; it is only for Plasmic Studio to hook into.)
Note: If you run next export
rather than (say) hosting on Vercel, then by default it exports with .html
suffixes (unlike the routes in the dev server), so you would get /plasmic-host.html
in production. Either include the .html
in your host URL, or suppress exporting with .html
with trailingSlash: true
in your next.config.js.
Using Plasmic components in _app.js
You may be using _app.js to render parts of your layout that is common to all pages. If you want to use Plasmic components in _app.js
, you need to make sure that:
<PlasmicRootProvider/>
is moved to your_app.js
,- Plasmic designs are still fetched from the page component’s
getStaticProps
, and used from the_app.js
component.
For example, suppose in _app.js
, you want to use the NavHeader
component that is designed in Plasmic. You can do so this way:
import { PLASMIC } from '../plasmic-init';
export default function MyApp({ Component, pageProps }) { return ( // Make use of data fetched by the page component's getStaticProps() <PlasmicRootProvider loader={PLASMIC} prefetchedData={pageProps.plasmicData}> <div> <PlasmicComponent component="NavHeader" /> <Component {...pageProps} /> </div> </PlasmicRootProvider> );}
import { PLASMIC } from '../plasmic-init';
export function getStaticProps() { // Be sure to also fetch data for `NavHeader` const plasmicData = await PLASMIC.fetchComponentData('SomePage', 'NavHeader'); return { props: { plasmicData } };}
export default function SomePage() { // no need for <PlasmicRootProvider /> return <PlasmicComponent component="SomePage" />;}
There’s much more to explore!
For example:
- Explore what you can do with code components.
- Render different variants of your pages/components.
- Override the content or props in your design.
- Add hooks for state and behavior to any component.
- Use Plasmic as a UI builder for creating full apps.
Continue learning in the full docs.