Turborepo×Expo×Expressにeslint-config・typescript-configを設定
はじめに
私が今のプロジェクトで、Turborepo×Expo×Expressのリポジトリを0から作成しているので、その時に分からなかったeslint-config・typescript-configを設定について記していきたいと思います。
Turborepoは、モノレポを管理するためのツールです。リポジトリのルートでフロントもバックも立ち上げたりすることができます。
今回主に説明するファイルはこちらです。
root/
├── apps/
│ ├── api/ //Express格納
│ ├── mobile/ //Expo格納
├── packages/
│ ├──eslint-config/
│ ├──typescript-config/
├── turbo.json
それでは、まずはリポジトリを作成していきます。
リポジトリ作成
- Turborepoの雛形作成
- Expoの雛形作成
- Expressの雛形作成
Turborepoの雛形作成
$ npx create-turbo@latest
このような構成でリポジトリが完成します🎉
次はapps配下にExpoとExpressを入れていきます。
Expoの雛形作成
$ npx create-expo-app@latest mobile
このような構成でリポジトリが完成します🎉
Expressの雛形作成
雛形作成することもできますが、かなり雛形自体にたくさんのフォルダが入っており、消すのが大変なので、Expressは0から作ります。
$ mkdir api
$ cd api
$ npm install express
ここでできたapi配下にsrc/index.tsのフォルダを作成し、下記を記述してください
import express from 'express';
const app = express();
const port = 3000;
console.log('Hello from the server!');
app.get('/', (req, res) => {
res.send('Hello from the server!');
});
app.listen(port, () => {
console.log(`Server is running on http://localhost:${port}`);
});
$ npm install
こちらで完成です🎉
configを設定
eslint-configとtypescript-configを設定します。
- eslint-configとは?
モノレポ全体で共通のESLint設定を適用するために使用されます。 - typescript-configとは?
モノレポ内のすべてのTypeScriptプロジェクトで使う設定をしたものです。
どちらも、各プロジェクトが個別に設定を持つのではなく、共有設定をパッケージとして管理し、それを継承します。
eslint-configを設定
リポジトリの.eslintrc.jsにどのファイルを継承しているか設定します。
turborepoのpackages/eslint-configとは、モノレポ全体で共通のESLint設定を適用するために使用されるファイルです。
今回の私のプロジェクトでは、base.jsとexpo.jsを設定しました。
この二つのファイルは、下記の設定をするファイルです。
base.js: ベースとなるESlintを設定。api/.eslintrc.jsから継承されています。
expo.js: ExpoのみのESlintを設定。mobile/.eslintrc.jsから継承されています。
ExpressのESlint設定はbase.jsにしました。Express単体のESlintを設定したい時はexpress.jsというファイルを今後作りたいと思います。
下記の3ファイルを実装します。
.eslintrc.js
/** @type {import("eslint").Linter.Config} */
module.exports = {
root: true,
extends: ['@repo/eslint-config/base.js'],
};
base.js
module.exports = {
extends: ['eslint:recommended', 'plugin:@typescript-eslint/recommended', 'prettier'],
env: {
node: true,
es6: true,
},
parser: '@typescript-eslint/parser',
parserOptions: {
project: true,
},
overrides: [
{
files: ['**/__tests__/**/*', '**/.eslintrc.js'],
env: {
jest: true,
},
rules: {
// ルールがあれば
},
},
],
ignorePatterns: [
// Ignore dotfiles
'.*.js',
'node_modules/',
],
rules: {
// 'no-console': 'warn',
'@typescript-eslint/no-unsafe-call': 'error',
'@typescript-eslint/no-unsafe-member-access': 'warn',
'@typescript-eslint/no-unsafe-return': 'error',
'@typescript-eslint/no-empty-function': 'warn',
'object-shorthand': 'error',
'import/no-anonymous-default-export': 'off',
'require-jsdoc': 0,
'valid-jsdoc': ['off'],
'no-restricted-imports': [
'warn',
{
patterns: ['./*', '../*'],
},
],
'import/order': [
'warn',
{
groups: ['builtin', 'external', 'internal', 'parent', 'sibling', 'index', 'object', 'type'],
'newlines-between': 'always',
pathGroupsExcludedImportTypes: ['internal'],
alphabetize: {
order: 'asc',
caseInsensitive: true,
},
pathGroups: [
{
pattern: '@/**',
group: 'external',
position: 'after',
},
],
},
],
},
};
expo.js
const { resolve } = require('node:path');
const project = resolve(process.cwd(), 'tsconfig.json');
/** @type {import("eslint").Linter.Config} */
module.exports = {
extends: ['expo', './base.js', 'turbo'],
env: {
node: true,
browser: true,
'react-native/react-native': true,
},
globals: {
React: true,
JSX: true,
},
plugins: ['only-warn', 'react-native'],
settings: {
'import/resolver': {
typescript: {
project,
},
},
},
overrides: [{ files: ['*.js?(x)', '*.ts?(x)', '**/.eslintrc.js'] }],
rules: [
{
'no-console': 'warn',
},
],
};
typescript-configを設定
リポジトリのtsconfig.jsonにどのファイルを継承しているか設定します。
turborepoのpackages/typescript-configとは、モノレポ全体で共通のTypeScriptの設定を適用するために使用されるファイルです。
今回の私のプロジェクトでは、base.jsonとapi.jsonを設定しました。
この二つのファイルは、下記の設定をするファイルです。
base.json: ベースとなるTSconfigを設定
api.json: ExpressのみのTSconfigを設定
ExpressのTSconfig設定はbase.jsonにしました。Expo単体のTSconfigを設定したい時はexpo.jsonというファイルを今後作りたいと思います。
api/tsconfig.json
{
"extends": "@repo/typescript-config/base.json",
"compilerOptions": {
"lib": ["ES2015"],
"outDir": "./dist",
"rootDir": "./src"
},
"exclude": ["node_modules"],
"include": ["src"]
}
mobile/tsconfig.json
{
"extends": "expo/tsconfig.base",
"compilerOptions": {
"strict": true,
"paths": {
"@/*": ["./*"]
}
},
"include": ["**/*.ts", "**/*.tsx", ".expo/types/**/*.ts", "expo-env.d.ts"]
}
base.json
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"declaration": true,
"declarationMap": true,
"esModuleInterop": true,
"incremental": false,
"isolatedModules": true,
"lib": ["es2022", "DOM", "DOM.Iterable"],
"module": "NodeNext",
"moduleDetection": "force",
"moduleResolution": "NodeNext",
"noUncheckedIndexedAccess": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"strict": true,
"target": "ES2022"
}
}
api.json
{
"extends": "./base.json",
"compilerOptions": {
"module": "NodeNext",
"sourceMap": true,
"outDir": "./dist",
"rootDir": "../../apps/api",
"esModuleInterop": true,
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
"forceConsistentCasingInFileNames": true,
"allowSyntheticDefaultImports": true,
"baseUrl": "../../apps/api",
"paths": {
"@/*": ["./*"]
}
},
"include": ["../../apps/api/src/**/*", "../../apps/mobile/tsconfig.json"],
"exclude": ["node_modules", "../../**/node_modules"],
"compileOnSave": false
}
さいごに
中身はご自身のPJに合わせてご変更ください!私のPJでは上記内容を実装しました!
Discussion