Closed4
Next.js + Typescript + FireStore + material-ui/styled-component + Vercel + SSGしたい
上記を参考に環境構築してみる
nextappの作成
npx create-next-app --ts
cd [app-name]
yarn dev
tsconfig.jsonの設定
tsconfig.json
{
"compilerOptions": {
"target": "es6",
"lib": [
"dom",
"dom.iterable",
"esnext"
],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve"
},
"include": [
"next-env.d.ts",
"**/*.ts",
"**/*.tsx"
],
"exclude": [
"node_modules"
]
}
Material-UI と styled-componentsの導入
yarn add @material-ui/core @material-ui/styles styled-components @types/styled-components
src/theme.ts: theme の作成
// src/styles/theme.ts
import { createMuiTheme } from '@material-ui/core'
const theme = createMuiTheme()
export default theme
src/_app.tsx : ルートコンポーネント付近にテーマプロバイダーを設置
// src/pages/_app.tsx
import React, { useEffect } from 'react'
import { ThemeProvider as StyledComponentsThemeProvider } from 'styled-components'
import {
ThemeProvider as MaterialUIThemeProvider,
StylesProvider
} from '@material-ui/styles'
import CssBaseline from '@material-ui/core/CssBaseline'
import theme from '../styles/theme'
import { AppProps } from 'next/dist/next-server/lib/router/router'
const MyApp = ({ Component, pageProps }: AppProps): JSX.Element => {
// Remove the server-side injected CSS.(https://material-ui.com/guides/server-rendering/)
useEffect(() => {
const jssStyles = document.querySelector('#jss-server-side')
if (jssStyles && jssStyles.parentNode) {
jssStyles.parentNode.removeChild(jssStyles)
}
}, [])
return (
<StylesProvider injectFirst>
<MaterialUIThemeProvider theme={theme}>
<StyledComponentsThemeProvider theme={theme}>
<CssBaseline />
<Component {...pageProps} />
</StyledComponentsThemeProvider>
</MaterialUIThemeProvider>
</StylesProvider>
)
}
export default MyApp
pages/_document.tsxをつくる
// src/pages/_documents.tsx
import React from 'react'
import NextDocument, {
Html,
Head,
Main,
NextScript,
DocumentContext,
DocumentInitialProps
} from 'next/document'
import { RenderPageResult } from 'next/dist/next-server/lib/utils'
import { ServerStyleSheet } from 'styled-components'
import { ServerStyleSheets as MaterialServerStyleSheets } from '@material-ui/core'
export default class CustomDocument extends NextDocument {
static async getInitialProps(
ctx: DocumentContext
): Promise<DocumentInitialProps> {
const styledComponentsSheet = new ServerStyleSheet()
const materialUiSheets = new MaterialServerStyleSheets()
const originalRenderPage = ctx.renderPage
try {
ctx.renderPage = (): RenderPageResult | Promise<RenderPageResult> =>
originalRenderPage({
enhanceApp: (App) => (
props
): React.ReactElement<{
sheet: ServerStyleSheet
}> =>
styledComponentsSheet.collectStyles(
materialUiSheets.collect(<App {...props} />)
)
})
const initialProps = await NextDocument.getInitialProps(ctx)
return {
...initialProps,
styles: [
<React.Fragment key="styles">
{initialProps.styles}
{styledComponentsSheet.getStyleElement()}
{materialUiSheets.getStyleElement()}
</React.Fragment>
]
}
} finally {
styledComponentsSheet.seal()
}
}
render(): React.ReactElement {
return (
<Html lang="ja-JP">
<Head>
<link rel="icon" href="/favicon.ico" />
</Head>
<body>
<Main />
<NextScript />
</body>
</Html>
)
}
}
src/components/StyledComponents.tsx: Material-UI のコンポーネントを styled-components で装飾する。
import React from 'react';
import styled from 'styled-components';
import { Button } from '@material-ui/core';
// Material-UI をカッコで囲んで、styled の引数にしてやる
const StyledButton = styled(Button)`
background: linear-gradient(45deg, #fe6b8b 30%, #ff8e53 90%);
border-radius: 3px;
border: 0;
color: white;
height: 48px;
padding: 0 30px;
box-shadow: 0 3px 5px 2px rgba(255, 105, 135, .3);
`;
export default function StyledComponents() {
return (
<div>
<Button>Material-UI</Button>
<StyledButton>Styled Components</StyledButton>
</div>
);
}
firebaseの導入
- firebaseコンソールからプロジェクトを作成する
- firebase init
- cloudfunctionsとfirestoreを選択してインストール
- firebaseコンソールから作成したプロジェクトの設定へ飛び、サービスアカウントタブを開く
- 「新しい秘密鍵の生成」を押下し秘密鍵を生成する
-
.env
ファイルを作成し以下を設定(設定は生成した秘密鍵のjsonファイルに書いてある)
.env
NEXT_PUBLIC_FIREBASE_PROJECT_ID="***************"
NEXT_PUBLIC_FIREBASE_CLIENT_EMAIL="***************"
NEXT_PUBLIC_FIREBASE_PRIVATE_KEY="***************"
- firebase-adminの初期化
lib/db.js
import * as admin from 'firebase-admin';
if (!admin.apps.length) {
admin.initializeApp({
credential: admin.credential.cert({
projectId: process.env.NEXT_PUBLIC_FIREBASE_PROJECT_ID,
clientEmail: process.env.NEXT_PUBLIC_FIREBASE_CLIENT_EMAIL,
privateKey: process.env.NEXT_PUBLIC_FIREBASE_PRIVATE_KEY.replace(/\\n/g, '\n'),
}),
});
}
export const db = admin.firestore();
- firestoreにデータを登録
-
pages
ディレクトリに以下を記述
pages/firebase.js
import { db } from '../lib/db';
import Link from 'next/link';
export default function Firebase({ tasks }) {
return (
<>
<h1>Firebaseのページ</h1>
<ul>
{tasks.map((task) => (
<li key={task.id}>{task.title}</li>
))}
</ul>
<Link href={`/`}>
<a>戻る</a>
</Link>
</>
);
}
export async function getStaticProps() {
const tasks = [];
const ref = await db.collection('tasks').get();
ref.docs.map((doc) => {
const data = { id: doc.id, title: doc.data().title };
tasks.push(data);
});
return {
props: {
tasks,
},
};
}
-
yarn dev
してデータを取得できているか確認
Vercelでデプロイ
- プロジェクトをgit commitしてpush
- Vercelにgithubでログイン
- プロジェクトを選択して
setting
からEnviroment Variables
へ行き環境変数を設定する。環境変数はfirebaseコンソールのプロジェクト設定 > 全般にある。privateKeyとclientEmailは秘密鍵のjsonに書いてある。
NEXT_PUBLIC_FIREBASE_API_KEY=************
NEXT_PUBLIC_FIREBASE_AUTH_DOMAIN=************
NEXT_PUBLIC_FIREBASE_DETABASE_URL=************
NEXT_PUBLIC_FIREBASE_PROJECT_ID=************
NEXT_PUBLIC_FIREBASE_STORAGE_BAKET=************
NEXT_PUBLIC_FIREBASE_MESSAGE_SENDER_ID=************
NEXT_PUBLIC_FIREBASE_APP_ID=************
NEXT_PUBLIC_FIREBASE_MEASUREMENT_ID=************
NEXT_PUBLIC_FIREBASE_CLIENT_EMAIL=************
NEXT_PUBLIC_FIREBASE_PRIVATE_KEY=************
このスクラップは2021/06/27にクローズされました