🗒
Next.js所作
書き始めるたびに同じことを調べている気がするのでまとめ。
Next.js で最初にやること
アプリを作る
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 を追加
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 の設定
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
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
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],
};
Discussion