⚛️
Create React Appを使わずにReactで新しくアプリを作る
自分がいつもReact.jsで新しくアプリを作るときに行う手順を記事にしました。
Create React Appは便利ですが、「個人開発としては使っても、サービス提供として使うのは一般的ではない」「設定が隠蔽されるため、後々調整が効かなくなる」といったデメリットがあります。
なので、私はCreate React Appを使用せずに、新しくアプリを作成します。
新しくリポジトリを作成する
$ mkdir foo
$ git init
$ cd foo
npm init
$ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.
See `npm help init` for definitive documentation on these fields
and exactly what they do.
Use `npm install <pkg>` afterwards to install a package and
save it as a dependency in the package.json file.
Press ^C at any time to quit.
package name: (foo)
version: (1.0.0)
description:
entry point: (index.js)
test command: jest
git repository:
keywords:
author: skytomo
license: (ISC)
About to write to D:\skytomo\Documents\Programming\sitelen-nena\package.json:
{
"name": "foo",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "skytomo",
"license": "MIT"
}
Is this OK? (yes)
TypeScriptとWebpackのインストール
npm install --save-dev typescript
npm install --save-dev webpack webpack-cli ts-loader
npm install --save-dev webpack-dev-server
Webpackの初期設定
$ npx webpack init
[webpack-cli] For using this command you need to install: '@webpack-cli/generators' package.
[webpack-cli] Would you like to install '@webpack-cli/generators' package? (That will run 'npm install -D @webpack-cli/generators') (Y/n) Y
…(省略)…
? Which of the following JS solutions do you want to use? Typescript
? Do you want to use webpack-dev-server? Yes
? Do you want to simplify the creation of HTML files for your bundle? Yes
? Do you want to add PWA support? Yes
? Which of the following CSS solutions do you want to use? SASS
? Will you be using CSS styles along with SASS in your project? Yes
? Will you be using PostCSS in your project? No
? Do you want to extract CSS for every file? No
? Do you like to install prettier to format generated configuration? Yes
? Pick a package manager: npm
[webpack-cli] ℹ INFO Initialising project...
conflict package.json
? Overwrite package.json? overwrite
force package.json
create src\index.ts
create README.md
create index.html
create webpack.config.js
create tsconfig.json
…(省略)…
[webpack-cli] ⚠ Generated configuration may not be properly formatted as prettier is not installed.
[webpack-cli] Project has been initialised with webpack!
ESLintのインストールと初期設定
Airbnbを使用したいので、ESLint の初期設定時、Airbnb のスタイルガイドが選択肢に表示されない – 手動インストールするという記事を参考に初期設定を済ませます。
2年前とは違う手順なので注意です。
$ npm install --save-dev eslint
$ npx eslint --init
You can also run this command directly using 'npm init @eslint/config@latest'.
Need to install the following packages:
@eslint/create-config@1.1.1
Ok to proceed? (y)
√ How would you like to use ESLint? · syntax
√ What type of modules does your project use? · esm
√ Which framework does your project use? · react
√ The React plugin doesn't officially support ESLint v9 yet. What would you like to do? · 8.x
√ Does your project use TypeScript? · typescript
√ Where does your code run? · browser
The config that you've selected requires the following dependencies:
eslint@8.x, globals, typescript-eslint, eslint-plugin-react
√ Would you like to install them now? · No / Yes
√ Which package manager do you want to use? · npm
☕️Installing...
…(省略)…
Successfully created foo/eslint.config.mjs file.
Airbnbスタイルガイドを手動でインストール
$ npm install --save-dev eslint-config-airbnb eslint-config-airbnb-typescript
.eslintrc.jsの設定
以下ように設定します。
.eslintrc.js
が存在せず、eslint.config.mjs
が存在する場合は、もう一度npx eslint --init
で初期設定すると作成されます(理由は不明)。
eslint.config.mjs
はこっそり削除しておきましょう。
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: ["plugin:react/recommended", "airbnb", "airbnb-typescript"], // ここを編集する
overrides: [
{
env: {
node: true,
},
files: [".eslintrc.{js,cjs}"],
parserOptions: {
sourceType: "script",
},
},
],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
},
plugins: ["@typescript-eslint", "react"],
rules: {},
};
Prettierのインストールと初期設定
Prettierは整形ツールですが、そのままだとESLintと競合してしまうのでそれを防ぐためのプラグイン(eslint-config-prettier
)をともに入れます。
npm install --save-dev prettier eslint-config-prettier
node --eval "fs.writeFileSync('.prettierrc','{}\n')"
.prettierignoreの設定
.prettierignore
を作成し、整形を避けたいファイルを書きます。
.prettierignore
dist
coverage
eslint-config-prettierの設定
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: ["plugin:react/recommended", "airbnb", "airbnb-typescript", "prettier"], // ここを編集する
overrides: [
{
env: {
node: true,
},
files: [".eslintrc.{js,cjs}"],
parserOptions: {
sourceType: "script",
},
},
],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
},
plugins: ["@typescript-eslint", "react"],
rules: {},
};
Reactのインストールと初期設定
npm install --save react react-dom
npm install --save-dev @types/react @types/react-dom
以下のファイルを編集・追加します。
.eslintrc.js
module.exports = {
env: {
browser: true,
es2021: true,
},
extends: ["plugin:react/recommended", "airbnb", "airbnb-typescript"],
overrides: [
{
env: {
node: true,
},
files: [".eslintrc.{js,cjs}"],
parserOptions: {
sourceType: "script",
},
},
],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
},
plugins: ["@typescript-eslint", "react"],
- rules: {},
+ rules: {
+ "import/extesnions": "off",
+ "no-return-assign": ["off"],
+ },
+ settings: {
+ "import/resolver": {
+ node: {
+ extensions: [".js", ".jsx", ".ts", ".tsx"],
+ },
+ },
+ },
};
webpack.config.js
…(省略)…
const config = {
- entry: './src/index.ts',
+ entry: './src/index.tsx',
output: {
path: path.resolve(__dirname, 'dist'),
},
devServer: {
open: true,
host: 'localhost',
},
plugins: [
new HtmlWebpackPlugin({
template: 'index.html',
}),
…(省略)…
tsconfig.json
{
"compilerOptions": {
"allowSyntheticDefaultImports": true,
"noImplicitAny": true,
"module": "es6",
"target": "es5",
- "allowJs": true
+ "allowJs": true,
+ "jsx": "react",
+ "moduleResolution": "bundler"
},
- "files": ["src/index.ts"]
+ "files": ["src/index.tsx"]
}
index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Webpack App</title>
</head>
<body>
- <h1>Hello world!</h1>
- <h2>Tip: Check your console</h2>
+ <div id="root"></div>
+ <script src="bundle.js"></script>
</body>
<script>
if ("serviceWorker" in navigator) {
window.addEventListener("load", () => {
navigator.serviceWorker
.register("service-worker.js")
.then((registration) => {
console.log("Service Worker registered: ", registration);
})
.catch((registrationError) => {
console.error("Service Worker registration failed: ", registrationError);
});
});
}
</script>
</html>
src/index.tsx
import React, { StrictMode } from "react";
import { createRoot } from "react-dom/client";
const App = () => <div>Hello, React!</div>;
const container = document.getElementById("root");
if (container === null)
throw new Error("No root element found in the document");
const root = createRoot(container);
root.render(
<StrictMode>
<App />
</StrictMode>,
);
npm run serve
で動作を確認してみましょう。
Jestのインストールと初期設定
テストの設定も済ませておきましょう。
公式サイトを参考にします。
npm install --save-dev jest babel-jest @babel/preset-env @babel/preset-react react-test-renderer
npm install --save-dev ts-jest @types/jest
npm install --save-dev jest-environment-jsdom @testing-library/react
.eslintrc.js
を編集します。
.eslintrc.js
module.exports = {
env: {
browser: true,
es2021: true,
+ jest: true,
},
extends: ["plugin:react/recommended", "airbnb", "airbnb-typescript"],
overrides: [
{
env: {
node: true,
},
files: [".eslintrc.{js,cjs}"],
parserOptions: {
sourceType: "script",
},
},
],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
},
plugins: ["@typescript-eslint", "react"],
rules: {
"import/extesnions": "off",
"no-return-assign": ["off"],
},
settings: {
"import/resolver": {
node: {
extensions: [".js", ".jsx", ".ts", ".tsx"],
},
},
},
};
以下のファイルを作成し、以下のように設定します。
babel.config.js
module.exports = {
presets: [
"@babel/preset-env",
["@babel/preset-react", { runtime: "automatic" }],
],
};
jest.config.js
module.exports = {
roots: ["<rootDir>/src"],
transform: {
"^.+\\.(ts|tsx)$": "ts-jest",
},
};
以下のファイルを追加してnpm test
が通るか試しましょう。
src/sample.ts
export default function sum(a: number, b: number) {
return a + b;
}
test/sample.test.ts
import sum from "../src/index";
test("adds 1 + 2 to equal 3", () => {
expect(sum(1, 2)).toBe(3);
});
おわり
幸せなReactライフを!
Discussion