こんにちは。Kaneyasuです。
先日からNext.jsとVercelを始めました。
前回までの分はこちら。
今回はFigmaからソースコードを生成してみます。
Figmaからコードを出力するにはプラグインの力が必要で、今回はLocofyを使用してみました。
手順を自分のような初心者の方向けに書き残しておくのでよろしければご覧ください。
Figmaへのサインアップ
Figmaにサインアップします。
PlanはFreeでやってみます。
私の場合ログインすると、DraftsにFigma basicsというファイルがあるのでこれを使用します。
Dev Modeへの切り替え
ファイルを開くと、右上にDev Modeへ切り替えるスイッチがあるのでこれをクリックします。

↓

Locofyプラグインのインストール
Figmaからコードを出力するにはプラグインの力が必要です。
デフォルトで、AnimaとFigma to Codeというプラグインが入っていますが、Animaは本来有料でフリープランだとすぐ上限になり、Figma to Codeは若干機能が弱そうなので、今回はLocofyというものを使ってみます。
Dev Modeに切り替えた後、Pluginsタブをクリックします。

検索ボックスにLocofy.aiと入力して検索。

クリックすると詳細情報が表示されるのでRun
をクリック。

アカウントの接続を求められるので、Connect Account
をクリック。

別タブで、Locofyのサイトが開きます。
Googleアカウントなどでサインアップします。
私はFigmaもLocofyもGoogleアカウントでサインアップしました。
おそらく、サインアップする方法は合わせた方がよいと思います。
サインアップ後、Figmaに戻ってプラグインでLocofyを開くと、コード変換の設定などが表示されるようになります。
LocofyでNext.jsのコードを出力する
プラグインにLocofyをインストール後、ファイルを開いて何らかのページを選択してPluginsのLocofyを開くと、コード変換の設定などが表示されます。
上部にフレームワークとスタイルの出力方法を選択する欄があるので、Next.jsを選択。
スタイルは今回はTailwindを使用してるのでそれを選択。
画面下部にダウンロードボタンがあるのでクリックすると、Zip圧縮されたファイル一式がダウンロードされます。
(ヘルプのアイコン邪魔ですね・・・)

ダウンロードしたファイルを解凍すると以下の構成のファイル群ができます。
./
├── README.md
├── next-env.d.ts
├── next.config.js
├── package.json
├── pages
│ ├── _app.tsx
│ ├── global.css
│ └── index.tsx
├── postcss.config.js
├── public
│ ├── jonathankemper1hhrdiolfpuunsplash-1@2x.png
│ └── stocksy-txp226f62b2ane300-medium-4582193-1@2x.png
├── tailwind.config.js
├── tsconfig.json
├── typings.d.ts
└── vercel.svg
既存のNext.jsプロジェクトへのマージ
出力したコードを既存のNext.jsプロジェクトへマージしてみます。
npx create-next-app
で出力したものと差を比較しながら適用します。
いろいろ試したところ、出力されたファイル一式のうち、○がついてるもの以外はマージする必要はないと思いました。
./
├── README.md
├── next-env.d.ts
├── next.config.js
├── package.json <<< ○
├── pages
│ ├── _app.tsx <<< ○
│ ├── global.css <<< ○
│ └── index.tsx <<< ○
├── postcss.config.js
├── public
│ ├── jonathankemper1hhrdiolfpuunsplash-1@2x.png <<< ○
│ └── stocksy-txp226f62b2ane300-medium-4582193-1@2x.png <<< ○
├── tailwind.config.js <<< ○
├── tsconfig.json
├── typings.d.ts
└── vercel.svg
package.jsonにライブラリを追加
autoprefixerが追加されていたので、マージではなく追加でnpm install autoprefixer --save-dev
しました。
画像とページのコードを自分のプロジェクトに組み込む
画像とページのコードを自分のプロジェクトに配置
Locofyが出力した画像をpublic
に配置。
次にコードですが、Locofyが出力したコード群にはpages
がありますが、私のプロジェクトにはpages
がないので、src/app
配下にディレクトリを作って、そこに配置します。
./
├── public
│ ├── jonathankemper1hhrdiolfpuunsplash-1@2x.png <<< Locofyが出力した画像
│ ├── shiba.png
│ └── stocksy-txp226f62b2ane300-medium-4582193-1@2x.png <<< Locofyが出力した画像
├── src
│ └── app
│ ├── dogs
│ │ └── page.tsx
│ ├── homepage <<< ディレクトリを新規作成、Locofyが出力したコード群のpages一式を移動
│ │ ├── _app.tsx
│ │ ├── global.css
│ │ └── index.tsx
│ ├── favicon.ico
│ ├── globals.css
│ ├── layout.tsx
│ └── page.tsx
├── next-env.d.ts
├── next.config.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── README.md
├── tailwind.config.ts
└── tsconfig.json
ここの違いは、私のプロジェクトがNext.js 13だからですね。
Next.js 13からは、ルートディレクトリはapp
に変更されています。
どうやら、Locofyが出力するコードは、Next.js 13より前のコードのようです。
Locofyが出力したpackage.json
には、"next": "^13.2.4",
とあるので、古いというより、13より前のNext.jsでも動くようにあえて古いスタイルで出力しているように思えます。
index.tsxをpage.tsxにリネーム
Next.js 13からはインデックスファイルは、index.tsx
からpage.tsx
に変わっているのでリネーム。
./
├── public
│ ├── jonathankemper1hhrdiolfpuunsplash-1@2x.png
│ ├── shiba.png
│ └── stocksy-txp226f62b2ane300-medium-4582193-1@2x.png
├── src
│ └── app
│ ├── dogs
│ │ └── page.tsx
│ ├── homepage
│ │ ├── _app.tsx
│ │ ├── global.css
│ │ └── page.tsx <<< リネーム
│ ├── favicon.ico
│ ├── globals.css
│ ├── layout.tsx
│ └── page.tsx
├── next-env.d.ts
├── next.config.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── README.md
├── tailwind.config.ts
└── tsconfig.json
_app.tsxをlayout.tsxに変更
Next.js 13からはレイアウトは、_app.tsx
からlayout.tsx
で定義するように変わっているのでこれも変更。
しかし、中身を比較してみたら構造が違います。
./
├── public
│ ├── jonathankemper1hhrdiolfpuunsplash-1@2x.png
│ ├── shiba.png
│ └── stocksy-txp226f62b2ane300-medium-4582193-1@2x.png
├── src
│ └── app
│ ├── dogs
│ │ └── page.tsx
│ ├── homepage
│ │ ├── _app.tsx <<< このファイルと(A)を比較
│ │ ├── global.css
│ │ └── page.tsx
│ ├── favicon.ico
│ ├── globals.css
│ ├── layout.tsx <<< (A)
│ └── page.tsx
├── next-env.d.ts
├── next.config.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── README.md
├── tailwind.config.ts
└── tsconfig.json
import { Fragment } from "react";
import Head from "next/head";
import type { AppProps } from "next/app";
import "./global.css";
function MyApp({ Component, pageProps }: AppProps) {
return (
<Fragment>
<Head>
<title>locofy-react-nextjs-project</title>
<meta
name="viewport"
content="minimum-scale=1, initial-scale=1, width=device-width"
/>
</Head>
<Component {...pageProps} />
</Fragment>
);
}
export default MyApp;
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./globals.css";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "kaneyasu", // ここの文字列がブラウザのタブに表示される
description: "Generated by kaneyasu", // こちらはメタタグに表示される文字列
};
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
</html>
);
}
単にリネームしただけでは動作しなかったので、(A)をベースに新たにlayout.tsx
を作成
import type { Metadata } from "next";
import { Inter } from "next/font/google";
import "./global.css";
const inter = Inter({ subsets: ["latin"] });
export const metadata: Metadata = {
title: "locofy-react-nextjs-projec", // ここの文字列がブラウザのタブに表示される
description: "locofy-react-nextjs-projec", // こちらはメタタグに表示される文字列
};
export default function HomepageLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<body className={inter.className}>{children}</body>
</html>
);
}
./
├── public
│ ├── jonathankemper1hhrdiolfpuunsplash-1@2x.png
│ ├── shiba.png
│ └── stocksy-txp226f62b2ane300-medium-4582193-1@2x.png
├── src
│ └── app
│ ├── dogs
│ │ └── page.tsx
│ ├── homepage
│ │ ├── layout.tsx <<< (A)をベースに作成
│ │ ├── global.css
│ │ └── page.tsx
│ ├── favicon.ico
│ ├── globals.css
│ ├── layout.tsx <<< (A)
│ └── page.tsx
├── next-env.d.ts
├── next.config.js
├── package-lock.json
├── package.json
├── postcss.config.js
├── README.md
├── tailwind.config.ts
└── tsconfig.json
tailwind.config.tsをマージ
私のプロジェクトのtailwind.config.ts
と、Locofyが出力したtailwind.config.js
を比較します。
import type { Config } from "tailwindcss";
const config: Config = {
content: [
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {
backgroundImage: {
"gradient-radial": "radial-gradient(var(--tw-gradient-stops))",
"gradient-conic":
"conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))",
},
},
},
plugins: [],
};
export default config;
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./pages/**/*.{js,ts,jsx,tsx}",
"./components/**/*.{js,ts,jsx,tsx}",
],
theme: {
extend: {
colors: {
white: "#fff",
darkolivegreen: "#426b1f",
black: "#000",
},
spacing: {},
fontFamily: {
inter: "Inter",
newsreader: "Newsreader",
},
},
fontSize: {
base: "16px",
sm: "14px",
xl: "20px",
inherit: "inherit",
},
},
corePlugins: {
preflight: false,
},
};
TypeScriptと JavaScriptの違いはありますが、JavaScriptのオブジェクトリテラル形式なのでマージができました。
contentのパスは、Locofyの方だとディレクトリ構造と合わないので、私のプロジェクトの方を正にしました。
themeと、corePluginsはLocofyの方を正にしました。
import type { Config } from "tailwindcss";
const config: Config = {
content: [
"./src/pages/**/*.{js,ts,jsx,tsx,mdx}",
"./src/components/**/*.{js,ts,jsx,tsx,mdx}",
"./src/app/**/*.{js,ts,jsx,tsx,mdx}",
],
theme: {
extend: {
colors: {
white: "#fff",
darkolivegreen: "#426b1f",
black: "#000",
},
spacing: {},
fontFamily: {
inter: "Inter",
newsreader: "Newsreader",
},
},
fontSize: {
base: "16px",
sm: "14px",
xl: "20px",
inherit: "inherit",
},
},
plugins: [],
corePlugins: {
preflight: false,
},
};
export default config;
動作確認
マージが済んだら動作確認してみます。
画像の表示だけ違和感を感じますね。
上述のファイル以外にもいろいろ調整してみましたが結果変わらずなので、これが限界なのかなと思います。
それでもゼロから作るよりは大分楽なので有用であることは感じられました。
有料プラグインのAnimaだとまた違う結果が得られるのかもしれません。
機会があったら試してみます。