Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Migrate into Next.js App Router #353

Merged
merged 15 commits into from
Oct 25, 2023
14 changes: 0 additions & 14 deletions .eslintrc

This file was deleted.

17 changes: 17 additions & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
module.exports = {
extends: ["next/core-web-vitals", "prettier"],
plugins: ["chakra-ui"],
parser: "@typescript-eslint/parser",
parserOptions: {
project: true,
tsconfigRootDir: __dirname,
},
rules: {
"sort-imports": "error",
"@next/next/no-img-element": "off",
"chakra-ui/props-order": "error",
"chakra-ui/props-shorthand": "error",
"chakra-ui/require-specific-component": "error",
},
ignorePatterns: [".eslintrc.js"],
};
1 change: 0 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ jobs:
- name: Run build
run: |
yarn build
yarn export
env:
NEXT_PUBLIC_BASE_URL: ${{ secrets.BASE_URL }}
NEXT_PUBLIC_GOOGLE_ANALYTICS_ID: ${{ secrets.GOOGLE_ANALYTICS_ID }}
Expand Down
10 changes: 10 additions & 0 deletions next.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// @ts-check

/**
* @type {import('next').NextConfig}
*/
const nextConfig = {
output: "export",
};

module.exports = nextConfig;
3 changes: 1 addition & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
"export": "next export",
"lint:code": "next lint",
"lint:code:fix": "next lint --fix",
"lint:style": "stylelint 'src/**/*.{css,scss}'",
Expand Down Expand Up @@ -44,6 +43,7 @@
"@types/node": "^18.11.10",
"@types/react": "^18.2.21",
"@types/react-test-renderer": "^18.0.0",
"@typescript-eslint/parser": "^6.7.5",
"@vitejs/plugin-react": "^3.1.0",
"eslint": "8.37.0",
"eslint-config-next": "13.5.3",
Expand All @@ -60,7 +60,6 @@
"react-test-renderer": "^18.2.0",
"sass": "^1.62.1",
"stylelint": "^15.10.3",
"stylelint-config-prettier": "^9.0.4",
"stylelint-config-recess-order": "^4.3.0",
"stylelint-config-sass-guidelines": "^10.0.0",
"ts-node": "^10.9.1",
Expand Down
20 changes: 20 additions & 0 deletions src/app/blog/[id]/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { BlogInfo, BlogInfos, getAllBlogInfos, getBlogFromId } from "../../lib/blog-fetch";
Fixed Show fixed Hide fixed
import { Metadata } from "next";
import { Post } from "./post";

export async function generateMetadata({ params }: { params: BlogInfo }): Promise<Metadata> {
const { title } = await getBlogFromId(params.id);
return { title };
shun-shobon marked this conversation as resolved.
Show resolved Hide resolved
}

export async function generateStaticParams(): Promise<BlogInfos> {
return getAllBlogInfos();
}

export default async function Page({ params }: { params?: BlogInfo }) {
if (params == null) {
throw new Error("invalid params");
}
const post = await getBlogFromId(params.id);
return <Post post={post} />;
}
34 changes: 7 additions & 27 deletions src/pages/blog/[id].tsx → src/app/blog/[id]/post.tsx
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { Blog, BlogInfo, getAllBlogInfos, getBlogFromId } from "../../lib/blog-fetch";
"use client";
Dismissed Show dismissed Hide dismissed

import { Container, Heading, Link, Text, VStack } from "@chakra-ui/react";
import type { GetStaticPaths, GetStaticProps, NextPage } from "next";
import { Blog } from "../../lib/blog-fetch";
import { DateString } from "../../components/date";
import { Layout } from "../../components/layout";
import MarkdownIt from "markdown-it";
import MarkdownItFootnote from "markdown-it-footnote";
import MarkdownItFrontMatter from "markdown-it-front-matter";
Expand All @@ -17,11 +17,11 @@ const md = MarkdownIt({
.use(MarkdownItFrontMatter)
.use(MarkdownItFootnote);

type BlogPostPageProps = {
export type BlogPostPageProps = {
post: Blog;
};

const BlogPostPage: NextPage<BlogPostPageProps> = ({ post }) => {
export const Post = ({ post }: BlogPostPageProps) => {
const prevNext = (
<PrevNextLink
prevLinkHref={post.prevId !== "" ? post.prevId : null}
Expand All @@ -30,7 +30,7 @@ const BlogPostPage: NextPage<BlogPostPageProps> = ({ post }) => {
);
const bodyHtml = md.render(emojify`${post.content}`);
return (
<Layout pageName={`限界開発鯖 - ブログ - ${post.title}`}>
<>
<VStack>
<Heading m={8} textAlign="center">
{post.title}
Expand All @@ -48,26 +48,6 @@ const BlogPostPage: NextPage<BlogPostPageProps> = ({ post }) => {
<div dangerouslySetInnerHTML={{ __html: bodyHtml }} />
</Container>
{prevNext}
</Layout>
</>
);
};

export const getStaticProps: GetStaticProps<BlogPostPageProps, BlogInfo> = async ({ params }) => {
if (params == null) {
throw new Error("invalid params");
}
console.dir(params);
const post = await getBlogFromId(params.id);
return {
props: {
post,
},
};
};

export const getStaticPaths: GetStaticPaths<BlogInfo> = async () => {
const paths = await getAllBlogInfos();
return { paths, fallback: false };
};

export default BlogPostPage;
40 changes: 16 additions & 24 deletions src/pages/blog.tsx → src/app/blog/blog.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
"use client";
Dismissed Show dismissed Hide dismissed
import {
Avatar,
Button,
Expand All @@ -9,17 +10,20 @@ import {
Spacer,
VStack,
} from "@chakra-ui/react";
import type { GetStaticProps, NextPage } from "next";
import { Metadata, getSortedBlogMetadata } from "../lib/blog-fetch";
import { DateString } from "../components/date";
import { Layout } from "../components/layout";
import { Metadata } from "../lib/blog-fetch";
import NextLink from "next/link";
import { Title } from "../components/title";
import { Metadata as NextMetadata } from "next";
import type { NextPage } from "next";

export const metadata: NextMetadata = {
title: "限界開発鯖 - ブログ",
};

const BlogCard = ({ id, title, date, author, authorId }: Metadata): JSX.Element => (
<HStack borderColor="shadowed" borderRightWidth="1px" borderBottomWidth="2px">
<NextLink href={`/blog/${id}`} passHref>
<Avatar as="a" flex="0 0 sm" name={title} />
<Avatar flex="0 0 sm" name={title} />
</NextLink>
<VStack alignItems="self-start" flex="1 1" p={2} spacing="0.5">
<NextLink href={`/blog/${id}`} passHref>
Expand All @@ -32,29 +36,17 @@ const BlogCard = ({ id, title, date, author, authorId }: Metadata): JSX.Element
<DateString dateString={date} />
<Spacer />
<NextLink href={`/blog/${id}`} passHref>
<Button as="a" size="sm">
記事を読む &rarr;
</Button>
<Button size="sm">記事を読む &rarr;</Button>
</NextLink>
shun-shobon marked this conversation as resolved.
Show resolved Hide resolved
</Flex>
</VStack>
</HStack>
);

const BlogPage: NextPage<{ blogs: Metadata[] }> = ({ blogs }) => (
<Layout pageName="限界開発鯖 - ブログ">
<Title>ブログ</Title>
<SimpleGrid gap={4} columns={1}>
{blogs.map((blog) => (
<BlogCard key={blog.id} {...blog} />
))}
</SimpleGrid>
</Layout>
export const Blog: NextPage<{ blogs: Metadata[] }> = ({ blogs }) => (
<SimpleGrid gap={4} columns={1}>
{blogs.map((blog) => (
<BlogCard key={blog.id} {...blog} />
))}
</SimpleGrid>
);

export const getStaticProps: GetStaticProps = async () => {
const blogs = await getSortedBlogMetadata();
return { props: { blogs } };
};

export default BlogPage;
7 changes: 7 additions & 0 deletions src/app/blog/page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import { Blog } from "./blog";
import { getSortedBlogMetadata } from "../lib/blog-fetch";

export default async function Page() {
const blogs = await getSortedBlogMetadata();
return <Blog blogs={blogs} />;
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect, it } from "vitest";
import { DateString } from "./date";
import { render } from "../utils/react-test";
import { render } from "../../utils/react-test";

it("renders correctly", () => {
const tree = render(<DateString dateString="2021-01-01" />);
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect, it } from "vitest";
import { Footer } from "./footer";
import { render } from "../utils/react-test";
import { render } from "../../utils/react-test";

it("renders correctly", () => {
const tree = render(<Footer />);
Expand Down
2 changes: 2 additions & 0 deletions src/components/footer.tsx → src/app/components/footer.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use client";
Dismissed Show dismissed Hide dismissed

import { Box, Link } from "@chakra-ui/react";

import NextLink from "next/link";
Expand Down
43 changes: 43 additions & 0 deletions src/app/components/google-analytics.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
"use client";
Dismissed Show dismissed Hide dismissed

import { usePathname, useSearchParams } from "next/navigation";
import Script from "next/script";
import { useEffect } from "react";

export const GOOGLE_ANALYTICS_ID = process.env.NEXT_PUBLIC_GOOGLE_ANALYTICS_ID ?? "";

const notifyShowingPage = (url: string): void => {
(
window as unknown as { gtag(event: "config", id: string, options: { page_path: string }): void }
).gtag("config", GOOGLE_ANALYTICS_ID, {
page_path: url,
});
};

export const GoogleAnalytics = () => {
const pathname = usePathname();
const searchParams = useSearchParams();
useEffect(() => {
notifyShowingPage(`${pathname}?${searchParams}`);
}, [pathname, searchParams]);
return (
<>
<Script
strategy="afterInteractive"
src={`https://www.googletagmanager.com/gtag/js?id=${GOOGLE_ANALYTICS_ID}`}
/>
<Script strategy="afterInteractive" id="send-ga">
{`
window.dataLayer = window.dataLayer || [];
function gtag() {
dataLayer.push(arguments);
}
gtag("js", new Date());
gtag("config", "${GOOGLE_ANALYTICS_ID}", {
page_path: window.location.pathname,
});
`}
</Script>
</>
);
};
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect, it } from "vitest";
import { Header } from "./header";
import { render } from "../utils/react-test";
import { render } from "../../utils/react-test";

it("renders correctly", () => {
const tree = render(<Header />);
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect, it } from "vitest";
import { Navigation } from "./navigation";
import { render } from "../utils/react-test";
import { render } from "../../utils/react-test";

it("renders correctly", () => {
const tree = render(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
"use client";
Dismissed Show dismissed Hide dismissed

import {
Button,
Container,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect, it } from "vitest";
import { PrevNextLink } from "./prev-next-link";
import { render } from "../utils/react-test";
import { render } from "../../utils/react-test";

it("renders both prev and next correctly", () => {
const tree = render(
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect, it } from "vitest";
import { Questions } from "./questions";
import { render } from "../utils/react-test";
import { render } from "../../utils/react-test";

it("renders correctly", () => {
const tree = render(<Questions />);
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { expect, it } from "vitest";
import { SNSLink } from "./sns-link";
import { render } from "../utils/react-test";
import { render } from "../../utils/react-test";

it("renders twitter link correctly", () => {
const tree = render(<SNSLink type="twitter" url="https://twitter.com/MikurXina" />);
Expand Down
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Subtitle, Title } from "./title";
import { expect, it } from "vitest";
import { render } from "../utils/react-test";
import { render } from "../../utils/react-test";

it("renders title correctly", () => {
const tree = render(<Title>Epic Title</Title>);
Expand Down
File renamed without changes.
6 changes: 6 additions & 0 deletions src/app/fonts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
import { Roboto } from "next/font/google";

export const roboto = Roboto({
weight: "400",
subsets: ["latin"],
});
Loading