bun+TurborepoでNext.js+Expo+Honoの環境構築をしてみる
経緯
学校のPBL実験とかいう面倒な強制共同開発をやる羽目になったから。
とりまそれぞれのドキュメントを置いておく
Bun
Turborepo
Next.js
Expo
Hono
ゴール
- Tuborepoの構成を理解する
- eslint, pretter etc...の構築をする
- actionsを実装
構成(予定)
Server
Hono + tRPC
Website
Next.js + ts + tailwindcss + storybook + etc...
Mobile
Expo
ちなみにt3は参考までに
では恒例のcreateコマンドを
bunx create-turbo@latest
Log
>>> TURBOREPO
>>> Welcome to Turborepo! Let's get you set up with a new codebase.
? Where would you like to create your turborepo? shokupass
? Which package manager do you want to use? bun workspaces (beta)
Downloading files. This might take a moment.
>>> Created a new Turborepo with the following:
apps
- apps/docs
- apps/web
packages
- packages/eslint-config
- packages/typescript-config
- packages/ui
Installing packages. This might take a couple of minutes.
>>> Success! Created a new Turborepo at "shokupass".
Inside that directory, you can run several commands:
bun run build
Build all apps and packages
bun run dev
Develop all apps and packages
bun run lint
Lint all apps and packages
Turborepo will cache locally by default. For an additional
speed boost, enable Remote Caching with Vercel by
entering the following command:
bunx turbo login
We suggest that you begin by typing:
cd shokupass
bunx turbo login
あ、bun
君色付け対応してないんだ...
プロジェクト名はshokupass
になってるを
Turborepo will cache locally by default. For an additional
speed boost, enable Remote Caching with Vercel by
entering the following command:bunx turbo login
We suggest that you begin by typing:
cd shokupass
bunx turbo login
リモートキャッシュできるをだって。
どうしよう
CI回すからやっておいて損はなさそう
一旦動かしてみる
bun && bun dev
Log
Bun is a fast JavaScript runtime, package manager, bundler, and test runner. (1.0.14 (d8be3e51))
Usage: bun <command> [...flags] [...args]
Commands:
run ./my-script.ts Execute a file with Bun
lint Run a package.json script
test Run unit tests with Bun
x nuxi Execute a package binary (CLI), installing if needed (bunx)
repl Start a REPL session with Bun
install Install dependencies for a package.json (bun i)
add elysia Add a dependency to package.json (bun a)
remove tailwindcss Remove a dependency from package.json (bun rm)
update backbone Update outdated dependencies
link [<package>] Register or link a local npm package
unlink Unregister a local npm package
pm <subcommand> Additional package management utilities
build ./a.ts ./b.jsx Bundle TypeScript & JavaScript into a single file
init Start an empty Bun project from a blank template
create elysia Create a new project from a template (bun c)
upgrade Upgrade to latest version of Bun.
<command> --help Print help text for command.
Learn more about Bun: https://bun.sh/docs
Join our Discord community: https://bun.sh/discord
$ turbo dev
• Packages in scope: @repo/eslint-config, @repo/typescript-config, @repo/ui, docs, web
• Running dev in 5 packages
• Remote caching disabled
docs:dev: cache bypass, force executing 01b2860241aed340
web:dev: cache bypass, force executing 31f1838a80245ae8
web:dev: $ next dev
docs:dev: $ next dev --port 3001
docs:dev: ▲ Next.js 14.0.3
docs:dev: - Local: http://localhost:3001
docs:dev:
web:dev: ▲ Next.js 14.0.3
web:dev: - Local: http://localhost:3000
web:dev:
docs:dev: ✓ Ready in 4.5s
web:dev: ✓ Ready in 4.5s
web:dev: ○ Compiling / ...
web:dev: ✓ Compiled / in 4.6s (517 modules)
docs:dev: ○ Compiling / ...
docs:dev: ✓ Compiled / in 4.7s (517 modules)
docs:dev: ○ Compiling /favicon.ico ...
docs:dev: ✓ Compiled /favicon.ico in 1482ms (513 modules)
依存関係を見る
bun turbo run build --graph
digraph {
compound = "true"
newrank = "true"
subgraph "root" {
"[root] @repo/eslint-config#build" -> "[root] ___ROOT___"
"[root] @repo/typescript-config#build" -> "[root] ___ROOT___"
"[root] @repo/ui#build" -> "[root] @repo/eslint-config#build"
"[root] @repo/ui#build" -> "[root] @repo/typescript-config#build"
"[root] docs#build" -> "[root] @repo/eslint-config#build"
"[root] docs#build" -> "[root] @repo/typescript-config#build"
"[root] docs#build" -> "[root] @repo/ui#build"
"[root] web#build" -> "[root] @repo/eslint-config#build"
"[root] web#build" -> "[root] @repo/typescript-config#build"
"[root] web#build" -> "[root] @repo/ui#build"
}
}
package.jsonの中身を見てみる
{
"name": "web",
"version": "1.0.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "eslint . --max-warnings 0"
},
"dependencies": {
"@repo/ui": "*",
"next": "^14.0.3",
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@next/eslint-plugin-next": "^14.0.2",
"@repo/eslint-config": "workspace:*",
"@repo/typescript-config": "workspace:*",
"@types/eslint": "^8.44.7",
"@types/node": "^17.0.12",
"@types/react": "^18.0.22",
"@types/react-dom": "^18.0.7",
"eslint": "^8.53.0",
"typescript": "^5.2.2"
}
}
@repo
の設定はどこだ?
@repo
パッケージ?
中にはシンボリックが入ってる
これです。
全てのpackage.jsonの@repo
を@shokupass
へ変更して再度インストール
bun i
Log
bun i
bun install v1.0.14 (d8be3e51)
🔍 @shokupass/ui [11/14]
error: package "@shokupass/ui" not found registry.npmjs.org/@shokupass%2fui 404
🔍 @shokupass/eslint-config [12/14]
error: package "@shokupass/eslint-config" not found registry.npmjs.org/@shokupass%2feslint-config 404
🔍 @shokupass/typescript-config [13/14]
error: package "@shokupass/typescript-config" not found registry.npmjs.org/@shokupass%2ftypescript-config 404
error: workspace dependency "@shokupass/eslint-config" not found
Searched in "./packages/eslint-config"
Workspace documentation: https://bun.sh/docs/install/workspaces
error: workspace dependency "@shokupass/typescript-config" not found
Searched in "./packages/typescript-config"
Workspace documentation: https://bun.sh/docs/install/workspaces
error: workspace dependency "@shokupass/eslint-config" not found
Searched in "./*"
Workspace documentation: https://bun.sh/docs/install/workspaces
error: workspace dependency "@shokupass/typescript-config" not found
Searched in "./*"
Workspace documentation: https://bun.sh/docs/install/workspaces
error: workspace dependency "@shokupass/eslint-config" not found
Searched in "./*"
Workspace documentation: https://bun.sh/docs/install/workspaces
error: workspace dependency "@shokupass/typescript-config" not found
Searched in "./*"
Workspace documentation: https://bun.sh/docs/install/workspaces
error: workspace dependency "@shokupass/ui" not found
Searched in "./*"
Workspace documentation: https://bun.sh/docs/install/workspaces
error: workspace dependency "@shokupass/typescript-config" not found
Searched in "./packages/typescript-config
ええ...
bun君さぁ
一旦node_modules
とbun.lockb
を消してインストール
Log
bun i
bun install v1.0.14 (d8be3e51)
+ @shokupass/ui@workspace:packages/ui
+ docs@workspace:apps/docs
+ web@workspace:apps/web
+ @shokupass/eslint-config@workspace:packages/eslint-config
+ @shokupass/typescript-config@workspace:packages/typescript-config
+ prettier@3.1.0
+ turbo@1.10.16
589 packages installed [5.62s]
よし
Eslintの設定
とりまこいつがないと始まらない説はあるので
え、bun君--filter
機能ないのか...
いちいちディレクトリ変えないといけないのか
特に変わったこともなく実装
File
/** @type {import("eslint").Linter.Config} */
module.exports = {
env: {
node: true,
es6: true,
},
extends: [
"eslint:recommended",
"prettier",
"eslint-config-turbo",
"plugin:n/recommended",
"plugin:@typescript-eslint/recommended",
],
plugins: ["only-warn", "import", "prettier", "promise", "@typescript-eslint"],
parserOptions: {
ecmaVersion: "latest",
sourceType: "module",
},
parser: "@typescript-eslint/parser",
ignorePatterns: [
// Ignore dotfiles
".*.js",
"node_modules/",
"dist/",
],
rules: {
"import/no-default-export": "error",
"arrow-body-style": ["error", "as-needed"],
"import/extensions": "off",
"import/prefer-default-export": "off",
"import/no-extraneous-dependencies": ["error", { packageDir: ["./"] }],
"import/order": [
"error",
{
pathGroups: [
{
pattern: "@/**",
group: "internal",
position: "before",
},
{
pattern: "#**",
group: "internal",
position: "before",
},
],
alphabetize: {
order: "asc",
},
},
],
},
overrides: [
{
files: ["./*"],
rules: {
"import/no-default-export": "off",
},
},
],
};
/**
ほぼlibraryと同様
**/
/**
ほぼlibraryと同様
**/
tsconfig
次にこいつ
こんな記事を見つけてみたり
hono用のconfigはどうしようかな
こんなスクラップを見つけたり
こうなった
{
"$schema": "https://json.schemastore.org/tsconfig",
"extends": ["@tsconfig/strictest/tsconfig.json"],
"display": "Hono",
"compilerOptions": {
"lib": ["ESNext"],
"module": "esnext",
"target": "esnext",
"moduleResolution": "bundler",
"moduleDetection": "force",
"allowImportingTsExtensions": true,
"noEmit": true,
"composite": true,
"allowSyntheticDefaultImports": true,
"jsx": "react",
"allowJs": true,
"types": ["bun-types"],
"strict": true,
"forceConsistentCasingInFileNames": true,
"skipLibCheck": true
}
}
後のやつはbases
を継承
今日はここまで
YarnからBunに乗り換えたけど体感でわかるほど早い
つどぅき
Prettier
ふぉーまったーの設定
たぶんこれかな?
bun turbo gen workspace --name prettier-config --type package
>>> Add an empty workspace to "shokupass"
? Where should "prettier-config" be added? packages/prettier-config
? Add workspace dependencies to "prettier-config"? No
>>> Success! Created prettier-config at "packages/prettier-config"
tree -I node_modules -I .git -I .next --dirsfirst -a ./packages/prettier-config/
./packages/prettier-config/
├── README.md
└── package.json
1 directory, 2 files
READMEとpackage.jsonが生成された。
{
"name": "prettier-config",
"version": "0.0.0",
"private": true,
"scripts": {
"dev": "echo 'Add dev script here'",
"build": "echo 'Add build script here'",
"test": "echo 'Add test script here'",
"lint": "echo 'Add lint script here'"
}
}
ゴリゴリと書いていく
.prettierrc.cjs
を追加
/** @type {import('prettier').Config} */
module.exports = {
printWidth: 120,
tabWidth: 2,
useTabs: false,
semi: true,
trailingComma: "all",
endOfLine: "lf",
plugins: ["prettier-plugin-tailwindcss"],
arrowParens: "avoid",
};
package.json
も変える
{
"name": "@shokupass/prettier-config",
"version": "0.0.0",
"private": true,
"main": "./.prettierrc.cjs",
"type": "commonjs",
"scripts": {
"fmt": "prettier --write ."
},
"devDependencies": {
"prettier": "^3.1.0",
"prettier-plugin-tailwindcss": "^0.5.7"
}
}
tree -I node_modules -I .git -I .next --dirsfirst -a ./packages/prettier-config/
./packages/prettier-config/
├── .prettierrc.cjs
├── README.md
└── package.json
1 directory, 3 files
そしたら導入したいディレクトリに.prettierrc.cjs
を入れてpackage.json
も変える
Jest
使わないかもしれないけど
こんなかんじ
tree -I node_modules -I .git -I .next --dirsfirst -a ./packages/jest-config/
./packages/jest-config/
├── README.md
├── next.cjs
├── node.cjs
└── package.json
1 directory, 4 files
Tilwindcss
const plugin = require("tailwindcss/plugin");
module.exports = {
mode: "jit",
content: ["./src/**/*.{tsx,ts}"],
theme: {
screens: {
tablet: "640px",
laptop: "1024px",
desktop: "1280px",
},
extend: {},
},
plugins: [
plugin(function ({ addUtilities }) {
const newUtilities = {
".scrollbar-hidden": {
"-ms-overflow-style": "none",
"scrollbar-width": "none",
"&::-webkit-scrollbar": {
display: "none",
},
},
};
addUtilities(newUtilities);
}),
],
};
これも特に変わりなくworkspaceを使って作成する。
ここまでのpackageの中身
tree -I node_modules -I .git -I .next --dirsfirst -a ./packages/
./packages/
├── eslint-config
│ ├── README.md
│ ├── library.cjs
│ ├── next.cjs
│ ├── package.json
│ └── react.cjs
├── jest-config
│ ├── .turbo
│ │ └── turbo-lint.log
│ ├── README.md
│ ├── next.cjs
│ ├── node.cjs
│ └── package.json
├── postcss-config
│ ├── .turbo
│ │ └── turbo-build.log
│ ├── README.md
│ ├── index.cjs
│ └── package.json
├── prettier-config
│ ├── .prettierrc.cjs
│ ├── README.md
│ └── package.json
├── tailwind-config
│ ├── .turbo
│ │ └── turbo-build.log
│ ├── .eslintignore
│ ├── .eslintrc.cjs
│ ├── .prettierignore
│ ├── .prettierrc.cjs
│ ├── README.md
│ ├── input.css
│ ├── package.json
│ ├── tailwind.config.cjs
│ ├── tsconfig.json
│ └── utils.ts
├── typescript-config
│ ├── base.json
│ ├── hono.json
│ ├── nextjs.json
│ ├── package.json
│ ├── react-library.json
│ └── react-native.json
└── ui
├── .turbo
│ └── turbo-lint.log
├── components
│ ├── card.tsx
│ └── code.tsx
├── turbo
│ └── generators
│ ├── templates
│ │ └── component.hbs
│ └── config.ts
├── .eslintrc.cjs
├── package.json
├── tsconfig.json
├── tsconfig.lint.json
└── turbo.json
Next.js
create turbo
後のApps配下は特にはいじってないのでこうなっている
./apps/
├── .turbo
│ └── cookies
├── docs
│ ├── .turbo
│ │ └── turbo-build.log
│ ├── src
│ │ ├── app
│ │ │ ├── favicon.ico
│ │ │ ├── globals.css
│ │ │ ├── layout.tsx
│ │ │ ├── page.module.css
│ │ │ └── page.tsx
│ │ └── public
│ │ ├── circles.svg
│ │ ├── next.svg
│ │ ├── turborepo.svg
│ │ └── vercel.svg
│ ├── .eslintignore
│ ├── .eslintrc.cjs
│ ├── .prettierrc.cjs
│ ├── README.md
│ ├── next-env.d.ts
│ ├── next.config.mjs
│ ├── package.json
│ └── tsconfig.json
└── web
├── .turbo
│ ├── cookies
│ └── turbo-build.log
├── src
│ ├── app
│ │ ├── favicon.ico
│ │ ├── globals.css
│ │ ├── layout.tsx
│ │ ├── page.module.css
│ │ └── page.tsx
│ └── public
│ ├── circles.svg
│ ├── next.svg
│ ├── turborepo.svg
│ └── vercel.svg
├── .eslintignore
├── .eslintrc.cjs
├── .prettierignore
├── .prettierrc.cjs
├── README.md
├── next-env.d.ts
├── next.config.mjs
├── package.json
└── tsconfig.json
14 directories, 37 files
このAppsの中でCreate
コマンドを叩けばいいらしい
b..bun君???
✔ What is your project named? … my-app
✔ Would you like to use TypeScript with this project? … No / Yes
✔ Would you like to use ESLint with this project? … No / Yes
✔ Would you like to use `src/` directory with this project? … No / Yes
✔ Would you like to use experimental `app/` directory with this project? … No / Yes
✔ What import alias would you like configured? … @website/*
Creating a new Next.js app in /Users/kousuke/Desktop/programs/typescript/turbo/shokupass/apps/my-app.
Using npm.
Installing dependencies:
- react
- react-dom
- next
- @next/font
- typescript
- @types/react
- @types/node
- @types/react-dom
- eslint
- eslint-config-next
npm ERR! code EUNSUPPORTEDPROTOCOL
npm ERR! Unsupported URL Type "workspace:": workspace:*
npm ERR! A complete log of this run can be found in: /Users/kousuke/.npm/_logs/2023-12-04T03_51_14_426Z-debug-0.log
Aborting installation.
npm install --save-exact --save react react-dom next @next/font typescript @types/react @types/node @types/react-dom eslint eslint-config-next has failed.
oh...
しゃーないのでyarnで入れます
✔ What is your project named? … website
✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like to use `src/` directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias (@/*)? … No / Yes
✔ What import alias would you like configured? … @website/*
Creating a new Next.js app in
Using yarn.
Initializing project with template: app-tw
Installing dependencies:
- react
- react-dom
- next
Installing devDependencies:
- typescript
- @types/node
- @types/react
- @types/react-dom
- autoprefixer
- postcss
- tailwindcss
- eslint
- eslint-config-next
➤ YN0000: ┌ Resolution step
➤ YN0061: │ abab@npm:2.0.6 is deprecated: Use your platform's native atob() and btoa() methods instead
➤ YN0061: │ domexception@npm:4.0.0 is deprecated: Use your platform's native DOMException instead
➤ YN0032: │ fsevents@npm:2.3.3: Implicit dependencies on node-gyp are discouraged
➤ YN0002: │ @shokupass/eslint-config@workspace:packages/eslint-config doesn't provide eslint (pfb849), requested by @typescript-eslint/eslint-plugin
➤ YN0002: │ @shokupass/eslint-config@workspace:packages/eslint-config doesn't provide eslint (p919fb), requested by @typescript-eslint/parser
➤ YN0002: │ @shokupass/eslint-config@workspace:packages/eslint-config doesn't provide eslint (p9403b), requested by eslint-config-prettier
➤ YN0002: │ @shokupass/eslint-config@workspace:packages/eslint-config doesn't provide eslint (p39d25), requested by eslint-plugin-import
➤ YN0002: │ @shokupass/eslint-config@workspace:packages/eslint-config doesn't provide eslint (p33c32), requested by eslint-plugin-jsx-a11y
➤ YN0002: │ @shokupass/eslint-config@workspace:packages/eslint-config doesn't provide eslint (pf96cf), requested by eslint-plugin-react
➤ YN0002: │ @shokupass/eslint-config@workspace:packages/eslint-config doesn't provide eslint (p6c576), requested by eslint-plugin-react-hooks
➤ YN0002: │ @shokupass/eslint-config@workspace:packages/eslint-config doesn't provide eslint (p4d647), requested by eslint-config-airbnb-typescript
➤ YN0002: │ @shokupass/eslint-config@workspace:packages/eslint-config doesn't provide eslint (p347ef), requested by eslint-config-airbnb
➤ YN0002: │ @shokupass/eslint-config@workspace:packages/eslint-config doesn't provide eslint (p2ce99), requested by eslint-config-next
➤ YN0002: │ @shokupass/eslint-config@workspace:packages/eslint-config doesn't provide eslint (p43b1e), requested by eslint-config-turbo
➤ YN0002: │ @shokupass/eslint-config@workspace:packages/eslint-config doesn't provide eslint (p0bed1), requested by eslint-plugin-n
➤ YN0002: │ @shokupass/eslint-config@workspace:packages/eslint-config doesn't provide eslint (p53956), requested by eslint-plugin-promise
➤ YN0002: │ @shokupass/eslint-config@workspace:packages/eslint-config doesn't provide eslint (p99462), requested by eslint-plugin-storybook
➤ YN0002: │ @shokupass/eslint-config@workspace:packages/eslint-config doesn't provide tailwindcss (pa7af5), requested by eslint-plugin-tailwindcss
➤ YN0002: │ @shokupass/jest-config@workspace:packages/jest-config doesn't provide react (pae3e2), requested by next
➤ YN0002: │ @shokupass/jest-config@workspace:packages/jest-config doesn't provide react-dom (p7ffa8), requested by next
➤ YN0002: │ @shokupass/jest-config@workspace:packages/jest-config doesn't provide typescript (pcedcd), requested by ts-jest
➤ YN0002: │ @turbo/gen@npm:1.10.16 doesn't provide @types/node (pe6832), requested by ts-node
➤ YN0002: │ @turbo/gen@npm:1.10.16 doesn't provide typescript (p0a547), requested by ts-node
➤ YN0000: │ Some peer dependencies are incorrectly met; run yarn explain peer-requirements <hash> for details, where <hash> is the six-letter p-prefixed code
➤ YN0000: └ Completed in 13s 927ms
➤ YN0000: ┌ Fetch step
➤ YN0013: │ yargs-parser@npm:21.1.1 can't be found in the cache and will be fetched from the remote registry
➤ YN0013: │ yargs@npm:17.7.2 can't be found in the cache and will be fetched from the remote registry
➤ YN0013: │ yn@npm:3.1.1 can't be found in the cache and will be fetched from the remote registry
➤ YN0013: │ yocto-queue@npm:0.1.0 can't be found in the cache and will be fetched from the remote registry
➤ YN0013: │ typescript@npm:5.3.2 can't be found in the cache and will be fetched from the remote registry
➤ YN0000: └ Completed in 31s 572ms
➤ YN0000: ┌ Link step
➤ YN0031: │ One or more node_modules have been detected and will be removed. This operation may take some time.
➤ YN0000: │ ESM support for PnP uses the experimental loader API and is therefore experimental
➤ YN0007: │ core-js-pure@npm:3.33.3 must be built because it never has been before or the last one failed
➤ YN0000: └ Completed in 5s 479ms
➤ YN0000: Done with warnings in 51s 121ms
Success! Created website
ん〜
だめだbun君ストレス
pnpmに移行します。
よってclose