はじめに
PlasmicというヘッドレスCMSがあるらしい、
という噂を聞いて、何も前提知識は無いですが触ってみた際の備忘録です。
Plasmicの利用準備
アカウント作成
Plasmicのサイト上でアカウントを作成します
\作成完了🥳/
Plasmicでのプロジェクト作成
この後、フロントと繋げるための適当なプロジェクトを一つ作っておきます
今回はテンプレートを利用してみます
\作成完了🥳/
画面右上のCode
を押すと、作成したプロジェクトを埋め込むための
サンプルコードが認証トークンを入れた状態で確認できます
早速使ってみる
今回の利用環境
> node -v
v16.17.0
> yarn -v
1.22.17
{
"@plasmicapp/loader-nextjs": "^1.0.232",
"next": "13.2.1"
}
Get started with Next.js
今回は、Next.jsを利用したハンズオンの中の
- 記事を表示するまで(Auto load all Plasmic pages)
- カスタムコンポーエントの追加(Adding custom code components)
をやっていきます
setup Next.js
とりあえず、Next.jsのアプリケーションを作成
yarn create next-app
✔ What is your project named? … plasmic-sample
✔ Would you like to use TypeScript with this project? … No / Yes
✔ Would you like to use ESLint with this project? … No / Yes
✔ Would you like to use `src/` directory with this project? … No / Yes
✔ Would you like to use experimental `app/` directory with this project? … No / Yes
✔ What import alias would you like configured? … @/*
\作成完了🥳/
install plasmicapp
Plasmicのパッケージを入れます
yarn add @plasmicapp/loader-nextjs
create plasmic-init.ts
touch 'src/plasmic-init.ts'
サンプルコードをコピペ
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,
})
Auto load all Plasmic pages
touch 'src/pages/[[...catchall]].tsx'
サンプルコードをコピペ
import * as React from 'react';
import {
PlasmicComponent,
ComponentRenderData,
PlasmicRootProvider,
extractPlasmicQueryData
} from '@plasmicapp/loader-nextjs';
import { GetStaticPaths, GetStaticProps } from 'next';
import Error from 'next/error';
import { useRouter } from 'next/router';
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 some non-Plasmic catch-all page
return {
props: {}
};
}
// This is a path that Plasmic knows about.
const pageMeta = plasmicData.entryCompMetas[0];
// Cache the necessary data fetched for the page.
const queryCache = await extractPlasmicQueryData(
<PlasmicRootProvider loader={PLASMIC} prefetchedData={plasmicData} pageParams={pageMeta.params}>
<PlasmicComponent component={pageMeta.displayName} />
</PlasmicRootProvider>
);
// Pass the data in as props.
return {
props: { plasmicData, queryCache },
// Using incremental static regeneration, will invalidate this page
// after 300s (no deploy webhooks needed)
revalidate: 300
};
};
/**
* Actually render the page!
*/
export default function CatchallPage(props: { plasmicData?: ComponentRenderData; queryCache?: Record<string, any> }) {
const { plasmicData, queryCache } = props;
const router = useRouter();
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}
prefetchedQueryData={queryCache}
pageParams={pageMeta.params}
pageQuery={router.query}
>
{
// pageMeta.displayName contains the name of the component you fetched.
}
<PlasmicComponent component={pageMeta.displayName} />
</PlasmicRootProvider>
);
}
※Next.jsアプリ作成時に自動生成されるsrc/pages/index.tsx
が残っているとルーティングが被ってエラーが出るので注意
(Error: You cannot define a route with the same specificity as a optional catch-all route
)
yarn dev
open http://localhost:3000
\作成完了🥳/
Adding custom code components
stap.1
mkdir 'src/components'
touch 'src/components/HelloWorld.tsx'
サンプルコードをコピペ
import * as React from 'react';
export interface HelloWorldProps {
children?: React.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
plasmic-init.ts
を修正
import { initPlasmicLoader } from "@plasmicapp/loader-nextjs";
import { HelloWorld } from './components/HelloWorld'; // 追加
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,
})
// 追加
PLASMIC.registerComponent(HelloWorld, {
name: 'HelloWorld',
props: {
verbose: 'boolean',
children: 'slot'
}
});
step.3
touch 'src/pages/plasmic-host.tsx'
サンプルコードをコピペ
import * as React from 'react';
import { PlasmicCanvasHost } from '@plasmicapp/loader-nextjs';
import { PLASMIC } from '../plasmic-init';
export default function PlasmicHost() {
return PLASMIC && <PlasmicCanvasHost />;
}
確認
yarn dev
open http://localhost:3000/plasmic-host
(確認メッセージが表示されるらしいけど、うまく表示されなかった..けど
カスタムコンポーネント自体は正常に追加されいたので...ヨシッ!!)
※この後、Plasmic側の設定で利用するのでdev
環境は立ち上げ続けておいてください
Plasmic側で設定
Plasmicのサイト上にもどり、
カスタムコンポーネントを取得するページを設定すると、
CMSのGUI上で扱えるようになります
\作成完了🥳/
最後に
お疲れ様でした!!🎉
特にカスタムコンポーネントをCMS側でGUIとして
利用できるのは楽しそうですね。
ショートコードをマーケやUIデザイナーが
より直感的に利用できそうです。
一方で、コンポーネントの理解が浅い
非開発のメンバーが触るには少し自由度が高すぎる印象も受けました。
そういったメンバーごとの権限設定や
すでに利用されているカスタムコンポーネトを変更した場合の
管理体制なども調査/考慮して運用にのるかは検討したいところです。
また、世の中にまだノウハウがなさそうなのでみんなで貯めていきましょう。
少しでもこの記事が誰かの参考になれば幸いです。