3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

はじめてのPlasmic

Last updated at Posted at 2023-02-26

はじめに

PlasmicというヘッドレスCMSがあるらしい、
という噂を聞いて、何も前提知識は無いですが触ってみた際の備忘録です。

Plasmicの利用準備

アカウント作成

Plasmicのサイト上でアカウントを作成します

スクリーンショット 2023-02-26 16.27.06.png

スクリーンショット 2023-02-26 16.27.22.png

\作成完了🥳/

スクリーンショット 2023-02-26 16.27.42.png

Plasmicでのプロジェクト作成

この後、フロントと繋げるための適当なプロジェクトを一つ作っておきます

スクリーンショット 2023-02-26 16.27.42 4.png

今回はテンプレートを利用してみます

スクリーンショット 2023-02-26 16.57.19.png

スクリーンショット 2023-02-26 16.58.42.png

\作成完了🥳/

画面右上のCodeを押すと、作成したプロジェクトを埋め込むための
サンプルコードが認証トークンを入れた状態で確認できます

スクリーンショット 2023-02-26 17.03.45.png

早速使ってみる

今回の利用環境

> 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'
サンプルコードをコピペ
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'
サンプルコードをコピペ
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

\作成完了🥳/

スクリーンショット 2023-02-26 17.19.40.png

Adding custom code components

stap.1

mkdir 'src/components'    
touch 'src/components/HelloWorld.tsx'
サンプルコードをコピペ
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を修正

src/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'
サンプルコードをコピペ
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上で扱えるようになります

スクリーンショット 2023-02-26 18.19.17.png

\作成完了🥳/

スクリーンショット 2023-02-26 18.17.28.png

最後に

お疲れ様でした!!🎉

特にカスタムコンポーネントをCMS側でGUIとして
利用できるのは楽しそうですね。

ショートコードをマーケやUIデザイナーが
より直感的に利用できそうです。

一方で、コンポーネントの理解が浅い
非開発のメンバーが触るには少し自由度が高すぎる印象も受けました。

そういったメンバーごとの権限設定や
すでに利用されているカスタムコンポーネトを変更した場合の
管理体制なども調査/考慮して運用にのるかは検討したいところです。
また、世の中にまだノウハウがなさそうなのでみんなで貯めていきましょう。

少しでもこの記事が誰かの参考になれば幸いです。

3
3
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?