From 60f25e126cf5f509b1b1bb842cc4b68a05118bdf Mon Sep 17 00:00:00 2001 From: Junhyuck Ko <56826914+mrbartrns@users.noreply.github.com> Date: Thu, 21 Dec 2023 14:20:18 +0900 Subject: [PATCH] App router migration (#195) * chore: install next.js 14 * change eslintrc file name * feat: create StyledComponentRegistry * chore: update tsconfig path * chore: remove eslint config import * chore(WIP): move to app router * chore: move folder * chore: update layout * update layout * [WIP] migrating * fix error on postdetail * switch Post Detail to app router * switch About to app router * switch PS service to app router * style: change style * remove unused files * rename * upgrade packages * w --- .eslintrc | 120 - .eslintrc.js | 93 + .prettierrc => .prettierrc.js | 2 +- .../posts/blog-migration.md | 0 .../posts/challenges-during-making-blog.md | 0 .../posts/cover-test-code.md | 0 .../posts/feelings-during-team-project.md | 0 .../posts/refactoring-legacy-project.md | 0 next.config.js | 12 - package.json | 21 +- src/app/(pages)/about/layout.tsx | 40 + src/app/(pages)/about/page.tsx | 27 + src/app/(pages)/layout.tsx | 64 + src/{pages/index.tsx => app/(pages)/page.tsx} | 49 +- src/app/(pages)/posts/[id]/page.tsx | 78 + src/app/(pages)/posts/layout.tsx | 30 + src/app/(pages)/posts/page.tsx | 10 + src/app/(pages)/ps/[id]/page.tsx | 72 + src/app/(pages)/ps/layout.tsx | 30 + src/app/(pages)/ps/page.tsx | 10 + src/components/Main/MainCardList.tsx | 1 + src/components/Main/MainList.tsx | 1 + .../NavigationBar/NavigationBar.module.scss | 8 +- .../NavigationBar/NavigationBar.tsx | 51 +- .../NotificationBar/NotificationBar.tsx | 1 + .../Post/PostDetail/Markdown.module.scss | 4 +- src/components/Post/PostDetail/PostAside.tsx | 3 +- .../Post/PostDetail/PostContent.tsx | 17 +- src/components/Post/PostDetail/PostFooter.tsx | 50 +- src/components/Post/PostDetail/PostSeries.tsx | 26 +- .../Post/PostDetail/PostSkeleton.tsx | 10 +- src/components/Post/PostList/SearchBar.tsx | 2 +- src/components/Resume/Body.tsx | 4 +- src/components/Resume/Resume.tsx | 12 +- src/components/common/Input/Input.stories.tsx | 4 +- src/components/common/Input/Input.tsx | 18 +- src/components/common/Skeleton/Skeleton.tsx | 6 +- src/components/icons/Hamburger.tsx | 12 +- src/components/layouts/GlobalLayout.tsx | 2 + src/lib/constants/index.ts | 2 + src/lib/registry/redux.tsx | 13 + src/lib/registry/styled-components.tsx | 31 + src/lib/styles/globals.scss | 1 + src/pages/_app.tsx | 65 - src/pages/_document.tsx | 57 - src/pages/about/index.tsx | 47 - src/pages/api/feedback.ts | 32 - src/pages/api/hello.ts | 17 - src/pages/api/post/comment/[id].ts | 39 - src/pages/api/post/hits/[url].ts | 34 - src/pages/api/verify.ts | 42 - src/pages/discussion/index.tsx | 192 - src/pages/posts/[id].tsx | 116 - src/pages/ps/[id].tsx | 119 - src/posts/PSDetailBuilder.tsx | 31 + .../ps/index.tsx => posts/PSListBuilder.tsx} | 51 +- src/posts/PostDetailBuilder.tsx | 29 + .../index.tsx => posts/PostListBuilder.tsx} | 42 +- tsconfig.json | 48 +- yarn.lock | 4280 +++++++++++------ 60 files changed, 3701 insertions(+), 2477 deletions(-) delete mode 100644 .eslintrc create mode 100644 .eslintrc.js rename .prettierrc => .prettierrc.js (88%) rename "content/posts/\353\270\224\353\241\234\352\267\270 \354\235\264\354\243\274\355\225\230\352\270\260 - \354\236\220\354\262\264 \354\204\234\353\271\204\354\212\244\353\245\274 \353\247\214\353\223\244\352\270\260 \354\234\204\355\225\234 \354\262\253 \352\261\270\354\235\214.md" => content/posts/blog-migration.md (100%) rename "content/posts/\353\270\224\353\241\234\352\267\270\353\245\274 \353\247\214\353\223\244\353\251\264\354\204\234 \353\247\210\354\243\274\354\271\234 \354\226\264\353\240\244\354\233\200\353\223\244.md" => content/posts/challenges-during-making-blog.md (100%) rename "content/posts/\355\224\204\353\241\234\354\240\235\355\212\270 \355\205\214\354\212\244\355\212\270 \354\273\244\353\262\204\353\246\254\354\247\200 \353\201\214\354\226\264 \354\230\254\353\246\254\352\270\260.md" => content/posts/cover-test-code.md (100%) rename "content/posts/\355\214\200 \355\224\204\353\241\234\354\240\235\355\212\270\353\245\274 \355\225\230\353\251\264\354\204\234 \353\212\220\352\274\210\353\215\230 \354\240\220\353\223\244.md" => content/posts/feelings-during-team-project.md (100%) rename "content/posts/\352\270\260\354\241\264 \355\224\204\353\241\234\354\240\235\355\212\270 \353\246\254\355\214\251\355\206\240\353\247\201\352\270\260.md" => content/posts/refactoring-legacy-project.md (100%) create mode 100644 src/app/(pages)/about/layout.tsx create mode 100644 src/app/(pages)/about/page.tsx create mode 100644 src/app/(pages)/layout.tsx rename src/{pages/index.tsx => app/(pages)/page.tsx} (64%) create mode 100644 src/app/(pages)/posts/[id]/page.tsx create mode 100644 src/app/(pages)/posts/layout.tsx create mode 100644 src/app/(pages)/posts/page.tsx create mode 100644 src/app/(pages)/ps/[id]/page.tsx create mode 100644 src/app/(pages)/ps/layout.tsx create mode 100644 src/app/(pages)/ps/page.tsx create mode 100644 src/lib/constants/index.ts create mode 100644 src/lib/registry/redux.tsx create mode 100644 src/lib/registry/styled-components.tsx delete mode 100644 src/pages/_app.tsx delete mode 100644 src/pages/_document.tsx delete mode 100644 src/pages/about/index.tsx delete mode 100644 src/pages/api/feedback.ts delete mode 100644 src/pages/api/hello.ts delete mode 100644 src/pages/api/post/comment/[id].ts delete mode 100644 src/pages/api/post/hits/[url].ts delete mode 100644 src/pages/api/verify.ts delete mode 100644 src/pages/discussion/index.tsx delete mode 100644 src/pages/posts/[id].tsx delete mode 100644 src/pages/ps/[id].tsx create mode 100644 src/posts/PSDetailBuilder.tsx rename src/{pages/ps/index.tsx => posts/PSListBuilder.tsx} (79%) create mode 100644 src/posts/PostDetailBuilder.tsx rename src/{pages/posts/index.tsx => posts/PostListBuilder.tsx} (81%) diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index 0dd5ec1..0000000 --- a/.eslintrc +++ /dev/null @@ -1,120 +0,0 @@ -{ - "env": { - "browser": true, - "node": true, - "es6": true - }, - "parser": "@typescript-eslint/parser", - "parserOptions": { - "ecmaFeatures": { - "jsx": true - }, - "tsconfigRootDir": "./", - "project": [ - "./tsconfig.json" - ] - }, - "extends": [ - "next/core-web-vitals", - "eslint:recommended", - "plugin:@typescript-eslint/recommended", - "prettier" - ], - "plugins": ["@typescript-eslint", "import", "react", "react-hooks"], - "rules": { - "@typescript-eslint/array-type": ["error", { "default": "array-simple" }], - "@typescript-eslint/consistent-type-exports": [ - "error", - { "fixMixedExportsWithInlineTypeSpecifier": false } - ], - "@typescript-eslint/consistent-type-imports": [ - "error", - { "prefer": "type-imports" } - ], - "@typescript-eslint/naming-convention": [ - "error", - { - "format": ["camelCase", "PascalCase", "UPPER_CASE"], - "selector": "variable" - }, - { - "format": ["camelCase", "PascalCase"], - "selector": "function" - }, - { - "format": ["PascalCase"], - "selector": "typeLike" - } - ], - "@typescript-eslint/no-explicit-any": "off", - "@typescript-eslint/no-unused-vars": ["warn", { "ignoreRestSiblings": true }], - "@typescript-eslint/no-use-before-define": "off", - "import/order": [ - "error", - { - "groups": [ - "builtin", - "external", - "internal", - "parent", - "sibling", - "index", - "object", - "type", - "unknown" - ], - "pathGroups": [ - { - "pattern": "react", - "group": "external", - "position": "before" - } - ], - "pathGroupsExcludedImportTypes": ["react"], - "alphabetize": { "order": "asc", "caseInsensitive": false }, - "warnOnUnassignedImports": true - } - ], - "no-console": ["warn", { "allow": ["warn", "error"] }], - "radix": "error", - "react/function-component-definition": [ - "error", - { - "namedComponents": "arrow-function" - } - ], - "react/jsx-props-no-spreading": "off", - "react/jsx-max-props-per-line": ["error", { "maximum": 1, "when": "multiline" }], - "react/jsx-no-useless-fragment": "warn", - "react/jsx-sort-props": [ - "error", - { - "callbacksLast": true, - "shorthandFirst": true, - "multiline": "last", - "reservedFirst": true - } - ], - "react/no-unknown-property": ["error", { "ignore": ["css"] }], - "react/prop-types": "off", - "react/react-in-jsx-scope": "off", - "react/require-default-props": "off", - "react/self-closing-comp": "error", - "spaced-comment": "warn" - }, - "overrides": [ - { - "files": [ - "**/*.stories.*" - ], - "rules": { - "import/no-anonymous-default-export": "off" - } - } - ], - "settings": { - "react": { - "version": "detect" - } - } -} diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 0000000..52b154d --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,93 @@ +module.exports = { + env: { + browser: true, + node: true, + es6: true, + }, + parser: '@typescript-eslint/parser', + parserOptions: { + ecmaFeatures: { + jsx: true, + }, + tsconfigRootDir: './', + project: ['./tsconfig.json'], + }, + extends: [ + 'next/core-web-vitals', + 'eslint:recommended', + 'plugin:@typescript-eslint/recommended', + 'prettier', + ], + plugins: ['@typescript-eslint', 'import', 'react', 'react-hooks'], + rules: { + '@typescript-eslint/array-type': ['error', { default: 'array-simple' }], + '@typescript-eslint/consistent-type-exports': [ + 'error', + { fixMixedExportsWithInlineTypeSpecifier: false }, + ], + '@typescript-eslint/consistent-type-imports': [ + 'error', + { prefer: 'type-imports' }, + ], + '@typescript-eslint/naming-convention': [ + 'error', + { + format: ['camelCase', 'PascalCase', 'UPPER_CASE'], + selector: 'variable', + }, + { + format: ['camelCase', 'PascalCase'], + selector: 'function', + }, + { + format: ['PascalCase'], + selector: 'typeLike', + }, + ], + '@typescript-eslint/no-explicit-any': 'off', + '@typescript-eslint/no-unused-vars': ['warn', { ignoreRestSiblings: true }], + '@typescript-eslint/no-use-before-define': 'off', + 'no-console': ['warn', { allow: ['warn', 'error'] }], + radix: 'error', + 'react/function-component-definition': [ + 'error', + { + namedComponents: 'arrow-function', + }, + ], + 'react/jsx-props-no-spreading': 'off', + 'react/jsx-max-props-per-line': [ + 'error', + { maximum: 1, when: 'multiline' }, + ], + 'react/jsx-no-useless-fragment': 'warn', + 'react/jsx-sort-props': [ + 'error', + { + callbacksLast: true, + shorthandFirst: true, + multiline: 'last', + reservedFirst: true, + }, + ], + 'react/no-unknown-property': ['error', { ignore: ['css'] }], + 'react/prop-types': 'off', + 'react/react-in-jsx-scope': 'off', + 'react/require-default-props': 'off', + 'react/self-closing-comp': 'error', + 'spaced-comment': 'warn', + }, + overrides: [ + { + files: ['**/*.stories.*'], + rules: { + 'import/no-anonymous-default-export': 'off', + }, + }, + ], + settings: { + react: { + version: 'detect', + }, + }, +}; diff --git a/.prettierrc b/.prettierrc.js similarity index 88% rename from .prettierrc rename to .prettierrc.js index e8060c3..87738b1 100644 --- a/.prettierrc +++ b/.prettierrc.js @@ -1,4 +1,4 @@ -{ +module.exports = { "singleQuote": true, "semi": true, "useTabs": false, diff --git "a/content/posts/\353\270\224\353\241\234\352\267\270 \354\235\264\354\243\274\355\225\230\352\270\260 - \354\236\220\354\262\264 \354\204\234\353\271\204\354\212\244\353\245\274 \353\247\214\353\223\244\352\270\260 \354\234\204\355\225\234 \354\262\253 \352\261\270\354\235\214.md" b/content/posts/blog-migration.md similarity index 100% rename from "content/posts/\353\270\224\353\241\234\352\267\270 \354\235\264\354\243\274\355\225\230\352\270\260 - \354\236\220\354\262\264 \354\204\234\353\271\204\354\212\244\353\245\274 \353\247\214\353\223\244\352\270\260 \354\234\204\355\225\234 \354\262\253 \352\261\270\354\235\214.md" rename to content/posts/blog-migration.md diff --git "a/content/posts/\353\270\224\353\241\234\352\267\270\353\245\274 \353\247\214\353\223\244\353\251\264\354\204\234 \353\247\210\354\243\274\354\271\234 \354\226\264\353\240\244\354\233\200\353\223\244.md" b/content/posts/challenges-during-making-blog.md similarity index 100% rename from "content/posts/\353\270\224\353\241\234\352\267\270\353\245\274 \353\247\214\353\223\244\353\251\264\354\204\234 \353\247\210\354\243\274\354\271\234 \354\226\264\353\240\244\354\233\200\353\223\244.md" rename to content/posts/challenges-during-making-blog.md diff --git "a/content/posts/\355\224\204\353\241\234\354\240\235\355\212\270 \355\205\214\354\212\244\355\212\270 \354\273\244\353\262\204\353\246\254\354\247\200 \353\201\214\354\226\264 \354\230\254\353\246\254\352\270\260.md" b/content/posts/cover-test-code.md similarity index 100% rename from "content/posts/\355\224\204\353\241\234\354\240\235\355\212\270 \355\205\214\354\212\244\355\212\270 \354\273\244\353\262\204\353\246\254\354\247\200 \353\201\214\354\226\264 \354\230\254\353\246\254\352\270\260.md" rename to content/posts/cover-test-code.md diff --git "a/content/posts/\355\214\200 \355\224\204\353\241\234\354\240\235\355\212\270\353\245\274 \355\225\230\353\251\264\354\204\234 \353\212\220\352\274\210\353\215\230 \354\240\220\353\223\244.md" b/content/posts/feelings-during-team-project.md similarity index 100% rename from "content/posts/\355\214\200 \355\224\204\353\241\234\354\240\235\355\212\270\353\245\274 \355\225\230\353\251\264\354\204\234 \353\212\220\352\274\210\353\215\230 \354\240\220\353\223\244.md" rename to content/posts/feelings-during-team-project.md diff --git "a/content/posts/\352\270\260\354\241\264 \355\224\204\353\241\234\354\240\235\355\212\270 \353\246\254\355\214\251\355\206\240\353\247\201\352\270\260.md" b/content/posts/refactoring-legacy-project.md similarity index 100% rename from "content/posts/\352\270\260\354\241\264 \355\224\204\353\241\234\354\240\235\355\212\270 \353\246\254\355\214\251\355\206\240\353\247\201\352\270\260.md" rename to content/posts/refactoring-legacy-project.md diff --git a/next.config.js b/next.config.js index 58f0bff..f21d486 100644 --- a/next.config.js +++ b/next.config.js @@ -1,6 +1,5 @@ /* eslint-disable @typescript-eslint/no-var-requires */ /** @type {import('next').NextConfig} */ -const path = require('path'); const withBundleAnalyzer = require('@next/bundle-analyzer')({ enabled: process.env.ANALYZE === 'true', @@ -32,17 +31,6 @@ const nextConfig = { }, ], }); - - config.resolve = { - alias: { - '~': path.resolve(__dirname, 'src'), - '~components': path.resolve(__dirname, 'src/components'), - '~hooks': path.resolve(__dirname, 'src/hooks'), - '~models': path.resolve(__dirname, 'src/models'), - }, - ...config.resolve, - }; - return config; }, }; diff --git a/package.json b/package.json index 9c40ba2..f28fb7a 100644 --- a/package.json +++ b/package.json @@ -20,7 +20,8 @@ "gist-react": "^1.0.1", "js-base64": "^3.7.5", "lottie-react": "^2.4.0", - "next": "^13.4.3", + "nanoid": "^5.0.4", + "next": "^14.0.4", "octokit": "^2.0.14", "react": "^18.2.0", "react-dom": "^18.2.0", @@ -39,7 +40,7 @@ "remark-parse-frontmatter": "^1.0.3", "remark-stringify": "^10.0.2", "slick-carousel": "^1.8.1", - "styled-components": "^5.3.8", + "styled-components": "^6.1.1", "unified": "^10.1.2", "uuid": "^9.0.0" }, @@ -51,8 +52,8 @@ "@storybook/addon-links": "7.0.18", "@storybook/addon-styling": "^1.3.0", "@storybook/blocks": "7.0.18", - "@storybook/nextjs": "7.0.7", - "@storybook/react": "^7.0.7", + "@storybook/nextjs": "^7.6.6", + "@storybook/react": "^7.6.6", "@storybook/testing-library": "^0.1.0", "@svgr/webpack": "^6.5.1", "@types/jest": "^29.5.1", @@ -64,27 +65,27 @@ "@types/react-syntax-highlighter": "^15.5.6", "@types/styled-components": "^5.1.26", "@types/uuid": "^9.0.1", - "@typescript-eslint/eslint-plugin": "^5.48.2", - "@typescript-eslint/parser": "^5.48.2", + "@typescript-eslint/eslint-plugin": "^6.15.0", + "@typescript-eslint/parser": "^6.15.0", "autoprefixer": "^10.4.13", "babel-loader": "^8.3.0", "cross-env": "^7.0.3", - "eslint": "8.32.0", + "eslint": "^8.56.0", "eslint-config-next": "13.1.3", "eslint-config-prettier": "^8.6.0", "eslint-plugin-storybook": "^0.6.12", "jest": "^29.5.0", "jest-environment-jsdom": "^29.5.0", "postcss": "^8.4.21", - "prettier": "^2.8.3", + "prettier": "^3.1.1", "sass": "^1.57.1", - "storybook": "7.0.18", + "storybook": "^7.6.6", "stylelint": "^15.6.0", "stylelint-config-recommended-scss": "^11.0.0", "stylelint-order": "^6.0.3", "stylelint-scss": "^5.0.0", "tailwindcss": "^3.2.4", - "typescript": "^5.0.4" + "typescript": "^5.3.3" }, "eslintConfig": { "extends": [ diff --git a/src/app/(pages)/about/layout.tsx b/src/app/(pages)/about/layout.tsx new file mode 100644 index 0000000..bb93570 --- /dev/null +++ b/src/app/(pages)/about/layout.tsx @@ -0,0 +1,40 @@ +import React from 'react'; +import Head from 'next/head'; +import GlobalLayout from '~components/layouts/GlobalLayout'; +import { DEFAULT_PAGE_TITLE } from '~lib/constants'; +import type { Metadata } from 'next'; + +const metadata: Metadata = { + title: `About Me - ${DEFAULT_PAGE_TITLE}`, + description: '프론트엔드 개발자 벤을 소개합니다.', +}; + +interface Props { + children?: React.ReactNode; +} + +const Layout = (props: Props) => { + const { children } = props; + + return ( + + + About Me - {DEFAULT_PAGE_TITLE} + + + + {children} + + ); +}; + +export default Layout; diff --git a/src/app/(pages)/about/page.tsx b/src/app/(pages)/about/page.tsx new file mode 100644 index 0000000..618001f --- /dev/null +++ b/src/app/(pages)/about/page.tsx @@ -0,0 +1,27 @@ +import Link from 'next/link'; +import ReduxProviderRegistry from '~lib/registry/redux'; +import NotificationBar from '~components/NotificationBar'; +import Resume from '~components/Resume'; + +const Page = () => { + return ( + + +

+ Currently looking for a job.{' '} + + Email + {' '} + me if you want to know more about me. +

+
+ {/** first part of main page, introduction */} + +
+ ); +}; + +export default Page; diff --git a/src/app/(pages)/layout.tsx b/src/app/(pages)/layout.tsx new file mode 100644 index 0000000..7be0ba6 --- /dev/null +++ b/src/app/(pages)/layout.tsx @@ -0,0 +1,64 @@ +import type { Metadata } from 'next'; +import Script from 'next/script'; +import { DEFAULT_PAGE_DESCRIPTION, DEFAULT_PAGE_TITLE } from '~lib/constants'; +import { pageview, GA_TRACKING_ID } from '~/lib/ga/gtag'; +import StyledComponentsRegistry from '~lib/registry/styled-components'; +import '~lib/styles/globals.scss'; + +export const metadata: Metadata = { + title: DEFAULT_PAGE_TITLE, + description: DEFAULT_PAGE_DESCRIPTION, +}; + +interface Props { + children?: React.ReactNode; +} + +const Layout = ({ children }: Props) => { + return ( + + + + {(metadata.title as string) || DEFAULT_PAGE_TITLE} + + +