Next.js所作


書き始めるたびに同じことを調べている気がするのでまとめ。

Next.js で最初にやること

アプリを作る

Create Next App

npx create-next-app@latest --ts --use-npm

いらないコードを消す

rm -rf public/ styles/ pages/api/
mkdir src/
mv pages/ src/
src/pages/_app.tsx
import type { AppProps } from "next/app";

function MyApp({ Component, pageProps }: AppProps) {
  return <Component {...pageProps} />;
}

export default MyApp;
src/pages/index.tsx
import type { NextPage } from "next";

const Home: NextPage = () => {
  return <>Home</>;
};

export default Home;

path の alias を通す

tsconfig.json
{
"compilerOptions": {
  ...
+ "baseUrl": ".",
+   "paths": {
+     "@/*": [
+       "src/*"
+     ]
+   }
  }
  ...
}

linter と formatter の設定

prettier を追加

prettier
next lint 周り

npm i -D prettier eslint-config-prettier
.eslintrc.json
{
- "extends": "next/core-web-vitals"
+ "extends": [
+   "next/core-web-vitals",
+   "prettier"
+ ]
}
package.json
{
  "scripts": {
    ...
+   "check-types": "tsc --noEmit",
+   "lint": "next lint --dir src",
+   "lint:fix": "next lint --fix --dir src",
+   "format": "prettier --write --ignore-path .gitignore 'src/**/*.{ts,tsx,json}'"
  }
}

pre-commit の設定

husky
lint-staged

npm i -D husky lint-staged
npm set-script prepare "husky install"
npm run prepare
npx husky add .husky/pre-commit "npm run lint-staged"
.lintstagedrc.js
const path = require("path");

const buildEslintCommand = (filenames) =>
  `next lint --fix --file ${filenames
    .map((f) => path.relative(process.cwd(), f))
    .join(" --file ")}`;

const buildPrettierCommand = (filenames) =>
  `prettier --write ${filenames
    .map((f) => path.relative(process.cwd(), f))
    .join(" ")}`;

const typeCheck = () => `tsc --noEmit`;

module.exports = {
  "*.{js,jsx,ts,tsx}": [buildPrettierCommand, buildEslintCommand, typeCheck],
};

Chakra UI

Chakra UI

npm i @chakra-ui/react @emotion/react@^11 @emotion/styled@^11 framer-motion@^6
src/pages/_app.tsx
import { ChakraProvider } from "@chakra-ui/react";
import type { AppProps } from "next/app";

function MyApp({ Component, pageProps }: AppProps) {
  return (
    <ChakraProvider>
      <Component {...pageProps} />
    </ChakraProvider>
  );
}

export default MyApp;

Storybook

Storybook

npx sb init
npm i -D tsconfig-paths-webpack-plugin
.storybook/main.js
const path = require("path");
const toPath = (_path) => path.join(process.cwd(), _path);

const TsconfigPathsPlugin = require("tsconfig-paths-webpack-plugin");

module.exports = {
  stories: ["../src/**/*.stories.mdx", "../src/**/*.stories.@(js|jsx|ts|tsx)"],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-interactions",
  ],
  framework: "@storybook/react",
  webpackFinal: async (config) => {
    // https://github.com/storybookjs/storybook/issues/16690
    config.module.rules.push({
      test: /\.mjs$/,
      include: /node_modules/,
      type: "javascript/auto",
    });
    config.resolve.plugins = [
      ...(config.resolve.plugins || []),
      new TsconfigPathsPlugin(),
    ];
    return {
      ...config,
      resolve: {
        ...config.resolve,
        alias: {
          // https://zenn.dev/json_hardcoder/articles/3e3db6ed5c583e
          ...config.resolve.alias,
          "@emotion/core": toPath("node_modules/@emotion/react"),
          "emotion-theming": toPath("node_modules/@emotion/react"),
        },
      },
    };
  },
};
.storybook/preview.js
import { ChakraProvider } from "@chakra-ui/react";
import * as React from "react";

const withChakra = (StoryFn) => {
  return (
    <ChakraProvider>
      <StoryFn />
    </ChakraProvider>
  );
};

export const decorators = [withChakra];

jest

npm install --save-dev jest @testing-library/react @testing-library/jest-dom
jest.config.js
const nextJest = require("next/jest");

const createJestConfig = nextJest({
  dir: "./",
});

const customJestConfig = {
  moduleNameMapper: {
    "^@/(.*)$": "<rootDir>/src/$1",
  },
  testEnvironment: "jest-environment-jsdom",
};

module.exports = createJestConfig(customJestConfig);
package.json
{
  "scripts": {
    ...
+   "test": "jest --watch"
  }
}
.lintstagedrc.js
+ const test = () => `jest`;

module.exports = {
-  "*.{js,jsx,ts,tsx}": [buildPrettierCommand, buildEslintCommand, typeCheck],
+  "*.{js,jsx,ts,tsx}": [buildPrettierCommand, buildEslintCommand, typeCheck, test],
};