ちゃなべの備忘録

ほぼ備忘録です。

SSRってなんだっけ?【備忘録】

はじめに

タイトルにもあるようにSSRがよくわからんかった。 だから調べた。
それをここにアウトプットします。

調査

なんかわかりやすそうなサイト(小並)

www.ragate.co.jp

  • CSR ( Client Side Rendering )
    • ブラウザ側でHTMLを生成する際にJSが実行される。
    • 初回にページ全体を処理するので、最初の読み込みが遅いがそれ以降速い。
    • フロー
      • ブラウザがURLへリクエス
      • が空っぽのHTMLを取得
      • ブラウザはJSを実行してHTMLやCSSをにレンダリング
      • ブラウザはHTMLのに展開されたHTML情報を表示
  • SSR ( Server Side Rendering )
    • サーバー側でレンダリング(描画)を行う
    • CSRと比較するとブラウザでJSを実行しない→コストが低い
    • フロー
      • ブラウザがURLへリクエス
      • サーバー(NodeJS)がリクエストを受け取り、HTML/CSSを生成
      • 完成したHTML/CSSをブラウザにレスポンス、展開する
  • SSG ( Static Site Generation )
    • ビルド時にHTMLなどのコンテンツが生成され、各リクエスト時に再利用してブラウザにわたす
    • リクエスト時にHTML/CSSを生成しないから速い
    • ページの更新時にアプリケーション全体をビルドするので、ページ数が多い大規模なアプリケーションには不向き
    • フロー
      • ブラウザがURLへリクエス
      • ビルド時に生成されていた静的ファイルをブラウザにレスポンス
  • ISR ( Incremental Static Regeneration )
    • SSGとSSRの昨日を兼ね備えた手法
    • 一定時間ごとにバックグラウンドでビルドを行って、APIからのデータ取得や再レンダリングを行ってくれる
    • CSRSSRと比べてデータ更新のリアルタイム性は低いものの、SSGのようなページ速度の速さを実現している。
  • SSRのメリット
    • SEOに強い
      • Googleは読み込みが速いサイトには優先的に検索順位を与える
      • SSRは確実にクロールされるので、CSRよりもやや優れている
    • 初期描画の表示速度がCSRより速い
      • そりゃそう
      • 描画スピードがユーザーのネットワーク環境やデバイスのスペックに左右されない
    • アプリケーションの仕様変更に強い
      • Nuxt or Nextの場合は、<client-only>で囲むことでSSRのプロジェクトでも一部的にCSRにすることができる
      • いろいろ自由(柔軟性が高い)らしい
      • 動的なOGPなどはサーバー側での処理が必要(らしい)ので、SSRはよき
    • 実行結果をCDNでキャッシュ可能
      • CDNとは
        • 一つのサーバーだけで、リクエストに対応していたら、遅いじゃん?(ワンオペ的な感じになるからね) それよりも、一つのオリジンサーバーからのレスポンス情報を複数のサーバーでキャッシュしていたら、対応早そうじゃん。(一人のマネージャーがマニュアル作って、それを複数人に配って、お客さんからの要望にマニュアル通りに対応する感じ) そゆこと。
      • そりゃそう

CSS-in-JSについていろいろ調べてみた【備忘録】

はじめに

自作アプリを作っている途中でcss-in-jsについて知らないことが多すぎて、調べた。

それをまとめただけ。

調査

食べログさんのを勉強

note.com

  • CSS modules
    • 利点
      • パフォーマンスに優れている
      • グローバルなスコープを作らない
      • 記述内で競合することがほぼない
    • いろんなところで使わている
    • nextJSも推奨
    • だけどdeprecatedになった
  • Styled Component
    • なんかいいらしい

styled componentsについて

zenn.dev

  • styled componentsの特徴

zozoさんを参考

techblog.zozo.com

  • CSS Modules
    • cssとjsのファイルが別なので管理コストがかかる
    • スタイルの優先度に保証がない
  • Linaria
    • Zero-runtime CSS in JS
    • Styled ComponentsやEmotionと同じ構文
    • 動的なスタイルを使用した場合にCSS Custom Propertiesを出力するため、多用するとCSSが肥大化する
    • 動的なスタイルの値がundefinedのときに不要なプロパティが残る
    • 同じコンポーネントをネストすると、再利用されたCSS Custom Propertiesが上書きされてしまい、意図した動作をしない
  • styled componentsとEmotionの比較
    • 機能はほぼ同等にいろいろ使える
    • 人気度はほぼ変わらん
    • 通信速度はややEmotionが勝る
    • バンドルサイズもややEmotionが勝る
  • CSS in JSの良さ
    • スタイルがコンポーネントに紐づくため、関心の分離ができる
    • CSSクラス名が自動生成されるので、コンポーネント同士が影響しあわない
    • JSの変数・関数と統合できるので、動的なスタイリングがしやすい

ChatGPTに聞いてみた

Q. もしかしてCSS Modulesはcss-in-jsではないの? A. CSS Modulesは、CSSをモジュールとして扱うことによって、CSS名前空間を自動的に生成し、スコープを限定することができるCSSのアプローチです。これは、CSSJavaScriptのモジュールとして取り扱うことで実現されますが、厳密に言えばCSS-in-JSではありません。 一方、CSS-in-JSは、JavaScriptの中にCSSスタイルを定義し、ランタイム時にスタイルを適用するアプローチです。これは、JavaScriptを使用して動的なスタイル変更を実現するため、コンポーネントベースのアプリケーションでよく使われます。代表的なCSS-in-JSライブラリには、styled-componentsやEmotionがあります。 CSS ModulesとCSS-in-JSは、いずれもCSS名前空間を自動的に生成し、スコープを限定することができる点で共通していますが、アプローチが異なります。CSS Modulesは、CSSファイルをJavaScriptのモジュールとして扱うことでスコープを生成するのに対し、CSS-in-JSはJavaScriptのコード内にスタイルを直接記述することでスコープを生成します。
引用元:Chat GPT

CSSファイルをjavascriptのモジュールとして扱うのが、CSS Modules。 css-in-jsはjsに直接cssを書くこと。

Stitchesってどうなんやろ

zenn.dev

  • Stichesの特徴
    • TSで型安全にかける
    • 速い
    • とにかくいろんなところで補完が効く

と、こんな感じで終わりましょか。

openapiとそれ関連いろいろ実装してみるンゴ (前編)【備忘録】

はじめに

swagger-uiの実装をしようと思ったんだけど、前できなかった。
いまならできそう。あと、いろいろキャッチアップする

前提イメージ

  • openapiを実装しまする
  • aspidaも実装したい
  • 新しいアプリを作ってやる。
  • monorepoで作ろうか
    • turborepo使用
  • 構成はopenapiとnext.js
  • docker上でturborepoを使ってみるという所業
    • だって、localを汚したくない。。

実装

順番はこうかな

  1. 設計
  2. 環境構築
    1. docker
    2. turborepo
  3. openapi実装
  4. next.js実装
    1. aspidaでopenapiの内容をとってくる

設計

なーーに作ろう。next.jsの強みを調べようか。 ...というかそもそも、next.jsってreactのフレームワークだったのかww 知らんかった。
あとnext.jsってSSRなんね。ほえーー。

まぁ、レンダリングの強みを活かしたいから、blogでも作ってみる?chanabe-blog。

ということで簡単に設計

サイトマップ
サイトマップ

ERD
ERD

使用サービス相関図
使用サービス相関図

環境構築

じゃあまずはdockerとturborepoで環境を作っていこう。

$ mkdir chanablog
$ cd chanablog
version: '3'

volumes:
  node-modules:


services:
  app:
    build: ./
    volumes:
      - ./src/:/usr/local/src/
      - node-modules:/usr/local/src/node_modules
    working_dir: /usr/local/src
    tty: true
    container_name: chanablog
FROM node:18.15.0-bullseye-slim

Debianの現状の安定バージョンで、slimのnodeを使った。発火!

$ docker compose up -d

じゃあここに、yarnいれて、turborepoいれよーー。

turbo.build

$ npm i yarn
added 1 package in 1s

$ yarn
yarn install v1.22.19
warning package.json: No license field
info No lockfile found.
warning package-lock.json found. Your project contains lock files generated by tools other than Yarn. It is advised not to mix package managers in order to avoid resolution inconsistencies caused by unsynchronized lock files. To clear this warning, remove package-lock.json.
warning No license field
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
Done in 1.01s.

$ ls
node_modules  package-lock.json  package.json  yarn.lock

$ yarn add create-turbo@latest
$ yarn run create-turbo    
yarn run v1.22.19
warning package.json: No license field
$ /usr/local/src/node_modules/.bin/create-turbo

>>> TURBOREPO

>>> Welcome to Turborepo! Let's get you set up with a new codebase.

? Where would you like to create your turborepo? ./app
? Which package manager do you want to use? yarn

>>> Created a new turborepo with the following:

 - apps/web: Next.js with TypeScript
 - apps/docs: Next.js with TypeScript
 - packages/ui: Shared React component library
 - packages/eslint-config-custom: Shared configuration (ESLint)
 - packages/tsconfig: Shared TypeScript `tsconfig.json`

>>> Success! Created a new Turborepo at "app".
Inside that directory, you can run several commands:

  yarn run build
     Build all apps and packages

  yarn run dev
     Develop 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:

  npx turbo login

We suggest that you begin by typing:

  cd app
  npx turbo login

Done in 178.97s.

おお、なんかできたっぽい。 すげぇファイルいっぱいできてるーー笑

公式の解説を読んでこ。

公式ドキュメントヨミヨミ

turbo.build

これが言っていることをまとめると

  • appsの中にアプリケーションをまとめているよ!
  • packagesにはuiとtsconfigとeslintのフォルダがあるよ!
    • uiはコンポーネントが入っているし、appsからの呼び出しもかんたん!
    • tsconfigはいろんなところに共通した設定を共有できるし、独自の設定もできるよ!
    • eslintも共通できるし、独自もできちゃう
  • コマンド系はturbo.jsonにかこう!
    • lint
      • lintはrootでコマンド打つだけで全部やってくれるよ!
      • しかもcacheを使えば、変更箇所だけやるよ!
    • build
      • buildもrootでコマンド打つだけで全部やるよb
      • これもchache使えば、すぐにできちゃう!
    • run
      • これでappたちが起動しちゃう!かんたんだね!
      • もし全部起動したくなかったら、--filterで絞れるよ!

んなーーーー、これやってて思った。

Swagger(opanapi)関係ねぇ。

ということは? 構成を変えましょ。

再設計

turborepoの強みとdockerの強みが生きるように。

swaggerの作成

じゃあturborepoのやり方もある程度わかったので、次はswaggerの設定をしよう。

なんか、かんたんにできるっぽい?

やってみる。

c-a-p-engineer.github.io

chanablog/
├── services/
│   ├── api/
│   │   └── openapi.yaml
│   └── client/
│       ├── src/
│       └── Dockerfile
└── docker-compose.yml
version: '3'

volumes:
  node-modules:


services:
  client:
    build: ./services/client/
    volumes:
      - ./services/client/src/:/usr/local/src/
      - node-modules:/usr/local/src/node_modules
    working_dir: /usr/local/src
    tty: true
    container_name: chanablog-client
    ports:
      - 3000:3000
      - 3001:3001

  swagger-editor:
    image: swaggerapi/swagger-editor
    container_name: "chanablog-swagger-editor"
    ports:
      - "8001:8080"

  swagger-ui:
    image: swaggerapi/swagger-ui
    container_name: "chanablog-swagger-ui"
    ports:
      - "8002:8080"
    volumes:
      - ./services/api/openapi.yml:/openapi.yml
    environment:
      SWAGGER_JSON: /openapi.yml

  swagger-api:
    image: stoplight/prism:latest
    container_name: "chanablog-swagger-api"
    ports:
      - "8003:4010"
    command: mock -h 0.0.0.0 /openapi.yml
    volumes:
      - ./services/api/openapi.yml:/openapi.yml
openapi: "3.0.3"

info:
  title: "Test1-API"
  version: "1.0.0"

paths:
  "/helloWorld":
    get:
      responses:
        "200":
          description: "test-ok"
          content:
            application/json:
              schema:
                type: string
                example: "Hello World"

じゃあ起動して見てみる。

おぉーーー!これだけでこんなに見れるのか!

だけど、Editorこれいらんな。
Stoplight Studioがlocalにあるからそれを使おう。

じゃあ編集してみる。

作成にあたって

API作成にあたっての注意点が乗ってたから読んでみた。

qiita.com

- URLはケバブケース - クエリ、パラメータはキャメルケース - 例) http://api.domain.com/users/{userId} - jsonのプロパティにもキャメルケース - 例) data: {userName: "Mohammad Faisal", userId: "1"} - APIのURLの前にversionを書く - 例) http://api.domain.com/v1/shops/3/products - 以下のURLは入れておく - /health - 必須 - `200 OK`ステータスコードで応答します。 - /version - 必須 - バージョン番号で応答します。 - /metrics - 必須 - 平均応答時間などのさまざまなmetricsを提供します。 - /debug - システムの動作に関する情報や、エラーが発生した場合のスタックトレースなどの情報を提供します。 - /status - サーバーの稼働時間、リクエスト数、レスポンス時間などの情報を提供します。 - リソースの総数をレスポンスに含める - 例) {total: 34, users: [ ... ]} - limitパラメータとoffsetパラメータを受け入れる - 例) GET /shops?offset=5&limit=5 - セキュリティ - CORS - HTTPSTLS暗号化) - 返すステータスはちゃんとしよう - エラー:4xx - 正常:2xx
引用元:API設計スキルを次のレベルに引き上げるベストプラクティス22選

あとOpenAPIの作り方についても。

qiita.com

- yamlのオブジェクトは以下の構成 - openapi / info - titleやバージョンなど - バージョンは基本的にセマンティックバージョニング - servers - APIのベースパスを設定できます(/api/v0とか) - それぞれ変数ベースで用意できるし、開発者用・本番用にも分けれられる - components - paths等から呼び出せるコンポーネントを定義する - requestとresponseで表示非表示を制御できるreadOnly/writeOnlyというのがある - security - apiKeyなどを定義できる - 全体に適用したり、個別のpathで設定が可能
引用元:作って理解する OpenAPI 3.0 / connexion

あとこれも読んだ、いうてさっきのとあんまり変わらんかったが。

qiita.com

- SSLは使おう - レスポンスは絞れるように - 作成・更新のあとのデータは絞れるように - エラーメッセージはしっかり返そう
引用元:翻訳: WebAPI 設計のベストプラクティス

これはAPIのエラーメッセージについて

blog.restcase.com

- エラーメッセージの分類は最小限に。以下くらいで十分。あんまり多くすると開発者の負担になる。 - 200 - 400 - 401 - 402 - 404 - 500 - エラーメッセージは丁寧説明的で。そして開発者に何をすべきかを促すように。
引用元:REST API Error Codes 101

これも読んだ。 エラーは簡潔で説明的であれ。

nordicapis.com

Stoplight Studioでつくっていく

おk。だいぶわかった。
じゃあ作ってみよ。

...だけど作っているときに大変なことがわかった。 StoplightStudioとaspidaがreadOnlyとwriteOnlyをサポートしていないっぽいのだ。まじかよ。

てか色々穴があるな。。ちょっと使いたくないかも。

だけど、一旦これで進めよう。readOnlyとかは別モデルとして定義して上げてやっていこう。。 もしだめっぽかったら、VSCode拡張機能で勧めていこう

zenn.dev

作った!

docker上で動かしてみる

おー表示された

だけど、なんだかエラーは出ている。

どうやら、Prismだとserverに設定したbaseUrl設定が無効になるらしい。

今回は,わざわざエンドポイントごとに `/api/v0` を入れて書いているが,本来ならば `server:` に一括で指定したい.しかしそうするためには,以下の記事にあるように,現状はPrism以外のツールを使う必要がある模様.
引用元:Swagger (OpenAPI) について

うーーん、これを見てみるとどうやら開発者は、「baseURLはあくまでサーバーが管理する必要があるものであり、OpenAPIが管理する必要がない」という主張っぽいな。あくまでpathの管理をするのがPrismaか。

github.com

じゃーーー今回はいっか。serverから/api/v1の部分を消す。

# 変更前
servers:
  - url: 'http://{host}:{port}/api/{version}'
    description: development
    variables:
      host:
        default: localhost
      port:
        default: '8002'
      version:
        default: v1

# 変更後
servers:
  - url: 'http://{host}:{port}/v1'
    description: development
    variables:
      host:
        default: localhost
      port:
        default: '8002'

よし、動いた。

turborepoの導入

次は、nextアプリを入れてみる。

なお、キャッチアップはこれでやった。

ayumu1212.hatenablog.com

next, react, react-domを入れて、pagesフォルダ作って、yarn devしたらできるというなんともかんたん。

あと、turborepoもcreate-turboみたいな感じの自動setupじゃなくて、manualのsetupをしていこう。

やってみよう。

アプリの枠作成

appsフォルダを作って、その配下にアプリの名前を作る。今回だったら、CDSCMS

こんな感じ。

src/
├── apps/
│   ├── cds/
│   └── cms/
├── node_modules/
├── packages.json
└── yarn.lock

そして、cds配下で必要なpackageをinstallする。

$ cd apps/cds/

# package.jsonの空fileを作り、yarn addしたときに、ここに入れるようにする。
$ touch package.json

$ echo "{}" > package.json

$ yarn add next react react-dom

# next.jsアプリの準備
$ mkdir pages
$ touch pages/index.tsx
$ vi pages/index.tsx
export default function View() {
  return <div>this is cds</div>
}

apps/cds/package.jsonを編集する。

{
  "name": "cds",
  "version": "1.0.0",
  "private": true,
  "scripts": {
    "dev": "next dev --port 3001",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "next": "^13.3.0",
    "react": "^18.2.0",
    "react-dom": "^18.2.0"
  }
}

じゃあ、アプリを起動してみる。

 yarn dev
yarn run v1.22.19
warning ../../package.json: No license field
$ next dev --port 3001
ready - started server on 0.0.0.0:3001, url: http://localhost:3001
It looks like you're trying to use TypeScript but do not have the required package(s) installed.
Installing dependencies

If you are not trying to use TypeScript, please remove the tsconfig.json file from your package root (and any TypeScript files in your pages directory).


Installing devDependencies (yarn):
- typescript
- @types/react
- @types/node

warning ../../package.json: No license field
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
success Saved 6 new dependencies.
info Direct dependencies
├─ @types/node@18.15.11
├─ @types/react@18.0.33
└─ typescript@5.0.4
info All dependencies
├─ @types/node@18.15.11
├─ @types/prop-types@15.7.5
├─ @types/react@18.0.33
├─ @types/scheduler@0.16.3
├─ csstype@3.1.2
└─ typescript@5.0.4

We detected TypeScript in your project and created a tsconfig.json file for you.

Attention: Next.js now collects completely anonymous telemetry regarding usage.
This information is used to shape Next.js' roadmap and prioritize features.
You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
https://nextjs.org/telemetry

warning ../../package.json: No license field
event - compiled client and server successfully in 2.6s (154 modules)
wait  - compiling / (client and server)...
event - compiled client and server successfully in 341 ms (166 modules)
wait  - compiling /_error (client and server)...
event - compiled client and server successfully in 210 ms (167 modules)

完璧。ちゃんと表示もされている。

nextで揃えられた現状のフォルダ構成はこんな感じ。

src/
├── apps/
│   ├── cds/
│   │   ├── .next/
│   │   ├── node_modules/
│   │   ├── pages/
│   │   │   └── index.tsx
│   │   ├── next-env.d.ts
│   │   ├── package.json
│   │   ├── tsconfig.json
│   │   └── yarn.lock
│   └── cms/
├── node_modules/
├── packages.json
└── yarn.lock
turbo導入

rootでturboをinstall

$ yarn add turbo

次にturbo.jsonを定義した。

{
  "$schema": "https://turbo.build/schema.json",
  "pipeline": {
    "build": {
      "dependsOn": [
        "^build"
      ],
      "outputs": [
        ".next/**",
        "!.next/cache/**"
      ]
    },
    "lint": {},
    "dev": {
      "cache": false
    }
  }
}

topのpackage.jsonも編集した。

{
  "private": true,
  "scripts": {
    "build": "turbo run build",
    "dev": "turbo run dev",
    "lint": "turbo run lint"
  },
  "dependencies": {
    "turbo": "^1.8.8"
  }
}

じゃあ実行。

$ yarn dev    
yarn run v1.22.19
$ turbo run dev
• Running dev
• Remote caching disabled
root task dev (turbo run dev) looks like it invokes turbo and might cause a loop

No tasks were executed as part of this run.

 Tasks:    0 successful, 0 total
Cached:    0 cached, 0 total
  Time:    2.188s 

 ERROR  run failed: command  exited (1)
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

$ yarn build
yarn run v1.22.19
$ turbo run build
 ERROR  run failed: error preparing engine: Could not find "___ROOT___#build" in root turbo.json
Turbo error: error preparing engine: Could not find "___ROOT___#build" in root turbo.json
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

ん?実行もbuildもエラーがでた。

調べてもあんまりエラーでないし、なんやろ。

とういことで、別dockerコンテナでcreate-turboして、ソースコードを見比べてみた。 そしたら、package.jsonにあるworkspacesというプロパティがないことに気がついた。

ということでいれる。

{
  "private": true,
  "workspaces": [
    "apps/cds"
  ],
  "scripts": {
    "build": "turbo run build",
    "dev": "turbo run dev",
    "lint": "turbo run lint"
  },
  "dependencies": {
    "turbo": "^1.8.8"
  }
}

これで、yarn devしたら動いた。

そっかーー、workspaceとして登録しないと認識しないのね。

package配置

次にpackageを配置していく。 中身はui, tsconfig, eslint-config-customにする。

そして、それぞれをコマンドで作成する。

$  npm init -w packages/ui
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: (ui) @ui
Sorry, name can only contain URL-friendly characters.
package name: (ui) ui
version: (1.0.0) 
description: package of ui components
entry point: (index.js) index.tsx
test command: 
git repository: 
keywords: 
author: 
license: (ISC) 
About to write to /usr/local/src/packages/ui/package.json:

{
  "name": "ui",
  "version": "1.0.0",
  "description": "package of ui components",
  "main": "index.tsx",
  "devDependencies": {},
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "",
  "license": "ISC"
}


Is this OK? (yes) 

added 2 packages in 1m

3 packages are looking for funding
  run `npm fund` for details

$  npm init -w packages/tsconfig

$  npm init -w packages/eslint-config-custom

packages内に諸々のfileができた。それぞれ構築していく。

ちなみに、package.jsonのworkspacesはワイルドカードにしておこう。

{

  "workspaces": [
    "apps/*",
    "packages/*"
  ],

}
package/tsconfigの設定

これはcreate-turboを参考にした。
フォルダ構成は以下のように。

packages/
└── tsconfig/
    ├── base.json     # 基本となるようなtsconfig
    ├── nextjs.json     # nextjs特有のtsconfig
    └── package.json
{
  "name": "tsconfig",
  "version": "1.0.0",
  "private": true,
  "description": "package of tsconfig files",
  "files": [
    "base.json",
    "nextjs.json",
    "react-library.json"
  ]
}

そして、この設定をアプリの方で読み込んであげる。

{
  "extends": "tsconfig/nextjs.json",
  "include": [
    "next-env.d.ts",
    "**/*.ts",
    "**/*.tsx"
  ],
  "exclude": [
    "node_modules"
  ]
}

これで完了。

package/eslint-config-customの設定

lintの設定をしていく。

これも参考はcreate-turbo

まずは、コマンドでpackageをinstallしていく。

$ yarn workspace eslint-config-custom add eslint eslint-config-next eslint-config-prettier eslint-plugin-react eslint-config-turbo

$ yarn workspace eslint-config-custom add --dev typescript

そして、package.jsonとindex.jsを修正する。

{
  "name": "eslint-config-custom",
  "version": "1.0.0",
  "private": true,
  "description": "base of eslint",
  "main": "index.js",
  "dependencies": {
    "eslint": "^8.38.0",
    "eslint-config-next": "^13.3.0",
    "eslint-config-prettier": "^8.8.0",
    "eslint-config-turbo": "^1.8.8",
    "eslint-plugin-react": "^7.32.2"
  },
  "devDependencies": {
    "typescript": "^5.0.4"
  }
}
module.exports = {
  extends: ["next", "turbo", "prettier"],
  rules: {
    "@next/next/no-html-link-for-pages": "off",
  },
  parserOptions: {
    babelOptions: {
      presets: [require.resolve("next/babel")],
    },
  },
};

ここまでできたら、アプリの方を修正する。
というか、eslintいれてなかったよ。

$ yarn workspace cds add --dev eslint

そして、eslintの設定をつくるぞーー

module.exports = {
  root: true,
  extends: ["custom"],
};

これでlintを回してみる!

$ yarn lint
yarn run v1.22.19
$ turbo run lint
• Packages in scope: cds, eslint-config-custom, tsconfig, ui
• Running lint in 4 packages
• Remote caching disabled
cds:lint: cache miss, executing ed4501e77bc1f2a7
cds:lint: $ next lint
cds:lint: ✔ No ESLint warnings or errors

 Tasks:    1 successful, 1 total
Cached:    0 cached, 1 total
  Time:    2.146s

Done in 2.25s.

いいね、回った。

package/uiの設定

これもturborepoを参考にした。 フォルダ構成は以下のように。

$ yarn workspace ui add --dev typescript react @types/react

これで必要なコンポーネント追加した。

{
  "name": "ui",
  "version": "1.0.0",
  "description": "package of ui components",
  "main": "index.tsx",
  "devDependencies": {
    "@types/react": "^18.0.35",
    "react": "^18.2.0",
    "typescript": "^5.0.4"
  }
}

次にtsconfigをuiに反映させる。packages/tsconfigにreact-library.jsonを追加。

{
  "$schema": "https://json.schemastore.org/tsconfig",
  "display": "React Library",
  "extends": "./base.json",
  "compilerOptions": {
    "jsx": "react-jsx",
    "lib": [
      "ES2015"
    ],
    "module": "ESNext",
    "target": "es6"
  }
}
{
  "name": "tsconfig",
  "version": "1.0.0",
  "private": true,
  "description": "package of tsconfig files",
  "files": [
    "base.json",
    "nextjs.json",
    "react-library.json" # 追加
  ]
}

uiに反映させるために、tsconfigファイルを追加。

{
  "extends": "tsconfig/react-library.json",
  "include": ["."],
  "exclude": ["dist", "build", "node_modules"]
}

turboを動かしてみる。動いたー!

これで準備はできたので、さっさとUIを作ろう。

後編に続く

引用サイト

結局ReactとNext.jsのどちらで開発を進めればいいの? - Qiita

Getting Started with Turborepo – Turborepo

API設計スキルを次のレベルに引き上げるベストプラクティス22選 - Qiita

Next.jsのサンプルアプリを作ってみた【備忘録】

はじめに

turborepoを用いた開発をするときに、next.jsを使おうと思ったのですが、まぁ全くやったことなかったので何もできませんでした。

なのでここで一旦キャッチアップしてからturborepoのキャッチアップをしようと思います。

実装

dockerでnode環境を作る

まず環境を作る。

version: '3'

volumes:
  node-modules:


services:
  app:
    build: ./
    volumes:
      - ./:/usr/local/src/
      - node-modules:/usr/local/src/node_modules
    working_dir: /usr/local/src
    tty: true
    ports:
      - 3000:3000
FROM node:18.15.0-bullseye-slim

これで、起動して、コマンドでアプリを作成していく。

create-next-appコマンドで自動プロジェクト生成

next.jsのサンプルアプリ作成

nextjs.org

これ参考

$ yarn create next-app --typescript
yarn create v1.22.19
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...

success Installed "create-next-app@13.3.0" with binaries:
      - create-next-app
✔ What is your project named? … sample-app
✔ Would you like to use ESLint with this project? … No / Yes
✔ Would you like to use Tailwind CSS 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? … @/*
Creating a new Next.js app in /usr/local/src/sample-app.

Using yarn.

Initializing project with template: default-tw


Installing dependencies:
- react
- react-dom
- next
- typescript
- @types/react
- @types/node
- @types/react-dom
- tailwindcss
- postcss
- autoprefixer
- eslint
- eslint-config-next

yarn add v1.22.19
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
success Saved 238 new dependencies.
info Direct dependencies
├─ @types/node@18.15.11
├─ @types/react-dom@18.0.11
├─ @types/react@18.0.33
├─ autoprefixer@10.4.14
├─ eslint-config-next@13.3.0
├─ eslint@8.38.0
├─ next@13.3.0
├─ postcss@8.4.21
├─ react-dom@18.2.0
├─ react@18.2.0
├─ tailwindcss@3.3.1
└─ typescript@5.0.4
info All dependencies
├─ @babel/runtime@7.21.0
├─ @eslint-community/eslint-utils@4.4.0
・
・
└─ yocto-queue@0.1.0
Done in 142.29s.
Success! Created sample-app at /usr/local/src/sample-app

Done in 336.97s.

$ yarn dev
yarn run v1.22.19
$ next dev
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
Attention: Next.js now collects completely anonymous telemetry regarding usage.
This information is used to shape Next.js' roadmap and prioritize features.
You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
https://nextjs.org/telemetry

event - compiled client and server successfully in 2.4s (170 modules)
wait  - compiling...
event - compiled successfully in 111 ms (137 modules)
wait  - compiling /_error (client and server)...
event - compiled client and server successfully in 108 ms (171 modules)
warn  - Fast Refresh had to perform a full reload. Read more: https://nextjs.org/docs/messages/fast-refresh-reload
wait  - compiling / (client and server)...
event - compiled client and server successfully in 687 ms (195 modules)
warn  - Fast Refresh had to perform a full reload. Read more: https://nextjs.org/docs/messages/fast-refresh-reload

表示できた。

いろいろ試してみる

どうやらフォルダの階層がそのまま表示につながるらしい。

export default function View() {
  return <div>ここはpostsの中の詳細ページだよ</div>
}

たしかに、/posts/1で表示された。

手動でnext.jsを作ってみる。

そのためにdocker-compose.ymlの修正

version: '3'

volumes:
  node-modules-auto:
  node-modules-manual:


services:
  auto-app:
    build:
      context: "./"
      dockerfile: "DockerfileAuto"
    volumes:
      - ./services/sample-app/:/usr/local/src/
      - node-modules-auto:/usr/local/src/node_modules
    working_dir: /usr/local/src
    tty: true
    ports:
      - 3001:3000
  manual-app:
    build:
      context: "./"
      dockerfile: "DockerfileManual"
    volumes:
      - ./services/manual-app/:/usr/local/src/
      - node-modules-manual:/usr/local/src/node_modules
    working_dir: /usr/local/src
    tty: true
    ports:
      - 3002:3000

これで、manual-appのコンテナ内に入って、環境をsetupしていく。

$ yarn add next react react-dom
yarn add v1.22.19
info No lockfile found.
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...

success Saved lockfile.
success Saved 19 new dependencies.
info Direct dependencies
├─ next@13.3.0
├─ react-dom@18.2.0
└─ react@18.2.0
info All dependencies
├─ @next/env@13.3.0
├─ @next/swc-linux-arm64-gnu@13.3.0
├─ @next/swc-linux-arm64-musl@13.3.0
├─ @swc/helpers@0.4.14
├─ busboy@1.6.0
├─ caniuse-lite@1.0.30001476
├─ client-only@0.0.1
├─ js-tokens@4.0.0
├─ nanoid@3.3.6
├─ next@13.3.0
├─ picocolors@1.0.0
├─ postcss@8.4.14
├─ react-dom@18.2.0
├─ react@18.2.0
├─ scheduler@0.23.0
├─ source-map-js@1.0.2
├─ streamsearch@1.1.0
├─ styled-jsx@5.1.1
└─ tslib@2.5.0
Done in 56.97s.

生成されたpackage.jsonに以下を追加

"scripts": {
  "dev": "next dev",
  "build": "next build",
  "start": "next start",
  "lint": "next lint"
}

これで起動してみる。

$ yarn run dev
yarn run v1.22.19
warning package.json: No license field
$ next dev
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
Error: > Couldn't find a `pages` directory. Please create one under the project root
    at Object.findPagesDir (/usr/local/src/node_modules/next/dist/lib/find-pages-dir.js:86:19)
    at DevServer.getRoutes (/usr/local/src/node_modules/next/dist/server/dev/next-dev-server.js:141:59)
    at new Server (/usr/local/src/node_modules/next/dist/server/base-server.js:115:47)
    at new NextNodeServer (/usr/local/src/node_modules/next/dist/server/next-server.js:73:9)
    at new DevServer (/usr/local/src/node_modules/next/dist/server/dev/next-dev-server.js:100:9)
    at NextServer.createServer (/usr/local/src/node_modules/next/dist/server/next.js:152:24)
    at /usr/local/src/node_modules/next/dist/server/next.js:165:42
    at async NextServer.prepare (/usr/local/src/node_modules/next/dist/server/next.js:134:24)
    at async Server.<anonymous> (/usr/local/src/node_modules/next/dist/server/lib/render-server.js:92:17) {
  type: 'Error'
}
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

おっと、pagesフォルダがないとだめみたい。
じゃあ作ってみっか。

export default function View() {
  return <div> This is manual app!</div>
}

これで、起動してみる。

$ yarn run dev
yarn run v1.22.19
warning package.json: No license field
$ next dev
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
It looks like you're trying to use TypeScript but do not have the required package(s) installed.
Installing dependencies

If you are not trying to use TypeScript, please remove the tsconfig.json file from your package root (and any TypeScript files in your pages directory).


Installing devDependencies (yarn):
- typescript
- @types/react
- @types/node

warning package.json: No license field
warning No license field
[1/4] Resolving packages...
[2/4] Fetching packages...
[3/4] Linking dependencies...
[4/4] Building fresh packages...
success Saved lockfile.
warning No license field
success Saved 6 new dependencies.
info Direct dependencies
├─ @types/node@18.15.11
├─ @types/react@18.0.33
└─ typescript@5.0.4
info All dependencies
├─ @types/node@18.15.11
├─ @types/prop-types@15.7.5
├─ @types/react@18.0.33
├─ @types/scheduler@0.16.3
├─ csstype@3.1.2
└─ typescript@5.0.4

We detected TypeScript in your project and created a tsconfig.json file for you.

Attention: Next.js now collects completely anonymous telemetry regarding usage.
This information is used to shape Next.js' roadmap and prioritize features.
You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
https://nextjs.org/telemetry

warning package.json: No license field
event - compiled client and server successfully in 2.1s (154 modules)
wait  - compiling / (client and server)...
event - compiled client and server successfully in 388 ms (166 modules)
wait  - compiling /_error (client and server)...
event - compiled client and server successfully in 181 ms (167 modules)
wait  - compiling...
event - compiled client and server successfully in 257 ms (166 modules)

おーー諸々生成されて、表示もされた!! なお、最小単位はこれ。

manual-app/
├── .next/
├── node_modules/
├── pages/
│   └── index.tsx
├── next-env.d.ts
├── package.json
├── tsconfig.json
└── yarn.lock

これだけで表示してくれるのすごいな!!

キャッチアップ終わり!

macの変換やばすぎ。【備忘録】

はじめに

macの変換使えなすぎ!!(総意) 別のに変えます!!!

(以下はmacの変換のヤバさを伝えるために、漢字への変換を修正しません)

やる

やっぱり無難にgoogle変換かな?
もし使いにくかったら別のに変えよう。

www.google.co.jp

ダウンロード

インストール

あれ?入力できない?

だけど,,,あれ?入力ができない。

いろいろ調べてみたけど、そんな挙動ないので、パソコンを再起動してみた。

そしたら行けた。

使ってみて

まぁーーーいいんじゃないか?今の所別に違和感はない。 だけど、一度間違えると次からそれを表示しちゃうのが少し嫌かも。

あーー逆か。macだと修正してくれなかったから逆にいいかも。

まぁ使っていこう。

エンジニアのためのデイリーニュースラジオ欲しくない?【備忘録】

はじめに

ある日朝起きた時に思った。

「朝ラジオ聴いたら目が覚めるけど、ニュースラジオは日経のものばっかり、エンジニアのものってないのかな?」

いろいろ調べてみた、だけどない!!!!
特にデイリーのがない。

え、じゃあ作らしてもらってもよろしい?

前提イメージ

  • 毎日その日のITニュースを聞きたい
  • マジで技術特化で良いと思われる
  • ラジオはどこかで流したい、パブリックにね。
  • んで、ラジオいう人は最初は自動音声で良い気がする。
    • 聞きやすければいい
  • 原稿もAIに作ってもらおうよ。ChatGPTがあるんだから。
  • 10日後くらいにだそうか。3月中にやってみようよ。(思案日:2023/3/19)
  • 必要なのは3つ
    • ラジオ場所
    • 自動音声の選定
    • 自動記事作成ツールを作成

調査

ラジオ作るのに必要なことを調査しましょう。

ラジオ場所

たぶんポッドキャストがいいと思う。 だいたいシェアで上位なのはこの3つかな。(参考:ポッドキャスト国内利用実態調査2021)

んーーーいい感じになってきたら広げていっていいけど、まずはSpotifyからかな。僕使ってるし。

Podcastのあげかたもむずくなさげ。 あとでやりましょ。

studentwalker.com

んで、今知ったけど、収益化できなそう。 海外だと収益化できるみたいだけど、現状日本だとできなそうだね。

podcasters.spotify.com

けど将来的にできそうだから、一旦ユーザー集める感じでいきたみ。

自動音声

これが一番未知。聞きやすいかが調べたいとこ。

ondoku3.com

→ ドンピシャの記事みっけ、だけど「音読さん」という会社がやっているところだから音読さんがよく見える。まぁ候補。

aicross.co.jp

→ 参考

nlab.itmedia.co.jp

→ 無料ですげぇ自然。

coestation.jp

→ これもありだけど、どうやら150字までしか無理そう。

原稿作成

ChatGPTは2021年以降の情報を学習していないので、昨日今日のニュースはまとめてくれなそう。 だからbing一択になりそう。

Google Bardも期待できそうだけど、リリースがまだなので一旦様子見。

ここらへんの原稿作成が一番アップデートしがいがあるので、随時情報を得ていきましょ。とりあえず始めることが大事。

実装

SpotifyのPodcasterを登録

まずは配信する場所を作りましょう。

podcasters.spotify.com

...え?これだけ?簡単すぎぃ。

イコン画像の作成

イコン画像欲しいからなんか作ろうか。

とりあえずCanvaで作ってみた。

これから

こう

これを登録 ...てかこんなのできたのかよ!!www

原稿作成依頼文の作成

次は原稿作成依頼をbingに投げるんだけど、それを作る。

じゃあやってみよう。

第一稿
昨日から今日までのエンジニアのためのニュースを2つほどピックアップして、1000字程度の原稿にまとめてください。
その原稿はニュースキャスターに読ませる想定で作成してください。
これを聞く人はラジオで聞くため、引用などの表記はしないでください。

改善点

第二稿
次のサイトらに上がっている昨日から今日までのニュースを2つほどピックアップして、紹介するための原稿を作成してください。
- https://techcrunch.com/
- https://www.itmedia.co.jp/
- https://www.businessinsider.jp/sai/
原稿を作る際の注意点は以下です。
- 必ず900字〜1100字にしてください。
- この原稿はニュースキャスターに読ませる想定で作成してください。
- 最初の挨拶は「おはようございます。本日もエンジニアのためのニュースをお届けします。」にしてください。
- これを聞く人はラジオで聞くため、引用などの表記はしないでください。

こいつ、、そういうことか、、「読み」で1000字くらいにしてくれたのか。。

改善点 - 1400文字くらいで良さげ。 - ピックアップするニュースは2-3つにしよう - あと話題はソフトウェアエンジニア向けにしぼろう。

第三稿
次のサイトらに上がっている昨日から今日までのニュースを2〜3つほどピックアップして、紹介するための原稿を作成してください。
- https://techcrunch.com/
- https://www.itmedia.co.jp/
- https://www.businessinsider.jp/sai/
原稿を作る際の注意点は以下です。
- 必ず1300文字以上にしてください。
- ピックアップするニュースはソフトウェアエンジニアに関係するものにしてください。
- この原稿はニュースキャスターに読ませる想定で作成してください。
- 最初の挨拶は「おはようございます。本日もエンジニアのためのニュースをお届けします。」にしてください。
- これを聞く人はラジオで聞くため、引用などの表記はしないでください。

よくなってきた、だけどトヨタの話とかが半年以上も前のものになってしまっている。

改善点 - 必ず前日のものにしよう

第四稿
次のサイトらに上がっているニュースを2〜3つほどピックアップして、紹介するための原稿を作成してください。
- https://techcrunch.com/
- https://www.itmedia.co.jp/
- https://www.businessinsider.jp/sai/

ニュースをピックアップする際の注意点は以下です。
- 必ず2023年3月18日に掲載された記事にしてください。
- ピックアップするニュースはソフトウェアエンジニアに関係するものにしてください。

原稿を作る際の注意点は以下です。
- 必ず1100文字以上にしてください。
- この原稿はニュースキャスターに読ませる想定で作成してください。
- 最初の挨拶は「おはようございます。本日もエンジニアのためのニュースをお届けします。」にしてください。
- これを聞く人はラジオで聞くため、引用などの表記はしないでください。

第五稿
昨日掲載されたニュースを2〜3つほどピックアップして、紹介するための原稿を作成してください。
ピックアップには以下のサイトを利用してください。

- https://techcrunch.com/
- https://www.itmedia.co.jp/
- https://www.businessinsider.jp/sai/

原稿を作る際の注意点は以下です。
- 必ず1100文字以上にしてください。
- この原稿はニュースキャスターに読ませる想定で作成してください。
- 最初の挨拶は「おはようございます。本日もエンジニアのためのニュースをお届けします。」にしてください。
- これを聞く人はラジオで聞くため、引用などの表記はしないでください。

ちゃんと記事も全部最新だし、よきだね。

改善点 - 音声に読ませてみたら、固有名詞のところがうまく読めてなかった - やよい軒 → やよいのき - 最後の締めの言葉も用意しよう。

第六稿
昨日掲載されたニュースを2〜3つほどピックアップして、紹介するための原稿を作成してください。
ピックアップには以下のサイトを利用してください。

- https://techcrunch.com/
- https://www.itmedia.co.jp/
- https://www.businessinsider.jp/sai/

原稿を作る際の注意点は以下です。
- 必ず1100文字以上にしてください。
- この原稿はニュースキャスターの声をした自動音声読み上げに読ませる想定で作成してください。なので固有名詞はひらがなで表記し、アルファベット表記のところはひらがなで表記してください。
- 最初の挨拶は「おはようございます。本日もエンジニアのためのニュースをお届けします。」にしてください。
- 最後の挨拶は「以上エンジニアのためのニュースでした。明日もまた聞いてくださいね。今日も一日頑張りましょう。」にしてください。
- これを聞く人はラジオで聞くため、引用などの表記はしないでください。

いいね、一旦完成。

原稿作成依頼文の作成(2023/04/02追記)

自分で記事をピックアップするバージョンのも作ってみた。

第七稿

やり方を変えたらうまく行った。 まずはbingで以下の文章をそれぞれ送る。

このサイトをを400文字以上にまとめてください。
https://www.businessinsider.jp/post-266813

このサイトをを400文字以上にまとめてください。
https://wired.jp/article/crypto-obfuscation-sxsw-2023/

このサイトをを400文字以上にまとめてください。
https://www.itmedia.co.jp/news/articles/2304/01/news043.html

そしたらそれぞれ返事が帰ってくるので、その文章を用いて以下の文章をChatGPTに投げる。

以下の文章3つを用いて、ニュースキャスターの原稿を作ってください。
原稿を作る際の注意点は以下です。
- 必ず原稿の合計文字数は1200文字以上にしてください。
- この原稿はニュースキャスターの声をした自動音声読み上げに読ませる想定で作成してください。なので固有名詞はひらがなで表記し、アルファベット表記のところはひらがなで表記してください。
- 最初の挨拶は「おはようございます。本日もエンジニアのためのニュースをお届けします。」にしてください。
- 最後の挨拶は「以上エンジニアのためのニュースでした。明日もまた聞いてくださいね。今日も一日頑張りましょう。」にしてください。
- 以下の文章を添削しても構いません。

「元テスラの2人がアメリカ初のフル電動キャンピングカーの会社を設立しました。その新たな会社、ライトシップは、2024年後半に初の電動キャンピングトレーラー「ライトシップL1」の生産を開始する予定です。以前からあるRVメーカーは2022年にいくつかの電動RVのコンセプトモデルを発表しています。1

ライトシップL1は、現在のEVの最大の欠点である航続距離に取り組み、話題になることを狙っています。ライトシップは、デザインと牽引車の負荷を軽減するドライブトレイン(動力伝達装置)によって、航続距離のロスをほぼゼロにできるとしています。80キロワット時のバッテリーは、テスラに搭載されているものとほぼ同じで、DC急速充電に対応しています。1

税額控除を適用する前のL1の価格は125000ドル(約1708万円)で、エアストリームなどのRVメーカーに匹敵する価格帯となります。1」

「世界最大規模のカンファレンス「SXSW 2023」では、これまでとは一転して暗号資産やNFT、ブロックチェーンの話題が影を潜めていました。この分野への懐疑的な見方が広がり、この技術を使用していることを表立って言わなくなったことが一因です。1

2022年に初めて参加したSXSWでは、そこには暗号資産の推進者たちによる息苦しい雰囲気から逃がれられる場がなかった。アートとテクノロジーの交差点を謳うこのイベントは、一見すると成長していそうなNFTのコミュニティにとって豊かな土壌であるかのように思えました。しかし、2023年のイベントはどうだったかというと、暗号資産の話をほとんど聞かなかったのです。そして暗号資産を話題に出した何人かは、それが恥ずかしいことでもあるかのような態度をとっていました。1

暗号資産関連企業がSXSWから完全に撤退したわけではありません。撤退したのではなく、姿を変えて参加していました。展示会場では暗号資産技術を使っていることを認め、既存の製品に金融に関連する機能を付け加えられることを誇らしげに主張している企業を今年も何社か見かけました。1」

「イタリアの個人データ保護当局がOpenAIに対し、ChatGPTの提供を一時的に禁止しました。ユーザーの個人データを違法に収集しているためとしています。また、未成年が違法なコンテンツにさらされるのを防ぐための年齢確認システムを導入していないと指摘されました。1

OpenAIに対処するまでに20日の猶予を与えるが、GPDRに違反していると判断すれば、2000万ユーロの罰金または世界での年間売上高の4%の罰金を科す可能性があるとしています。OpenAIのサム・アルトマンCEOは「もちろん、私たちはイタリア政府に従い、イタリアでのChatGPTの提供を中止した(ただし、すべてのプライバシー法に従っていると考えている)。イタリアは私の好きな国の1つだ」とツイートしました。1

あとはCoeFontに読み上げさせる。

音声に読み上げさせる。

文章を分けて、CoeFontにあげた。

これ最高だわ。

だけど、少しだけ自動音声の読み上げが弱いところがある。 だからそれを修正する。

よし、結合してダウンロードもできた。

spotifyにアップロード

とりあえずアップ準備。

あと規約も改めて読みましょう。

support.spotify.com

タイトルとエピソード説明のフォーマットはこれ。

タイトル:
2023年4月03日(月)イタリアによるChatGPTへの規制など

説明:
前日に以下のニュースサイトで投稿された記事を要約しています。

* https://techcrunch.com/
* https://newspicks.com/theme-news/technology/
* https://www.businessinsider.jp/sai/

よし!公開!
時間は朝の6:30で!

とりあえず運用とか考えず公開してしまいますた。

URLはこれです。

open.spotify.com

今後

とりあえず毎日やってみようか。 前日までの記事をピックアップすればいいから、夜中にやって、次の日の朝に公開するように。

さくらVPSでサーバー間通信をやってみた【備忘録】

はじめに

これにいろいろ機能をつけてきた。 さぁ次はサーバー間通信かな。

localでのサーバー間通信はやってきたけど、本番環境でのサーバー間通信はやったことがない。 ワクワク。やっていこ!

前提イメージ

  • さくらVPSにサーバー間通信の機能があるっぽいけど、どうなんだろ。
    • なるべく「これ便利サービス」は使いたくない。
  • もしできなそうであればネットワークを構築する必要がありそうなので頑張るわ。

調査

vps.sakura.ad.jp

→ これでやるっぽい。こんな簡単にできるのか?

manual.sakura.ad.jp

→ manualはこれ。やってみるか。

phoenixknight.jp

→ やり始めまで参考

blog.tilfin.net

→ いまはようわからんけど、あとあと参考になりそう

qiita.com

→ 参考になりそう

w.atwiki.jp

→ クソ参考になりそう

cat-marketing.jp

→ まんまやん

検索方法はこれ [さくらVPS ローカル接続]

実装

他の人のサイトを見ながらやってみよう。

スイッチの作成

とりあえず作ってみた。

さくらVPSスイッチ作成 さくらVPSスイッチ作成2 さくらVPSスイッチ作成3

サーバー間通信を行うための、サーバー3つ(front, back, db)をシャットダウンする。

各サーバーに接続先スイッチを追加

サーバーの設定画面 > ネットワーク > ネットワークインターフェース から接続先を設定。
eth0は基本的にインターネットに接続するみたい。だからeth1をさっきのスイッチに設定。

だけどあとでbackサーバーとdbサーバーはeth0のインターネット接続を外す、必要ないしね。

さくらVPS接続先スイッチ設定

各サーバーのネットワーク設定

んで、いろいろみていたら、どうやらこの後はnmcliコマンドというものを使うっぽい。 そして、どうやらこっから先のさくらVPS関連の設定はなさげ? ということは [ nmcli サーバー間通信 ]とかで調べたら出てきそう。

調べてみたけど、やっぱりさくらVPSありきの設定ではありそう。local通信を行うために今回スイッチ作ったしね。

これらを参考にやってみる

cat-marketing.jp

manual.sakura.ad.jp

clientの設定

clientのサーバー入ってみて、設定ファイル見てみたらこうなっていた。ので編集した。

$ cat /etc/sysconfig/network-scripts/ifcfg-ens4
DEVICE=”ens4″
ONBOOT=”no”
TYPE=“Ethernet”

$ vi /etc/sysconfig/network-scripts/ifcfg-ens4
DEVICE="ens4"
ONBOOT=”yes”
TYPE=”Ethernet”
IPADDR=”192.168.1.1″
NETMASK=“255.255.255.0″

$ systemctl restart NetworkManager

けど、この後にpingで確認してもどうやらうまく設定できていないみたいだす。

$ nmcli networking off && nmcli connection reload && nmcli networking on
Error: failed to set networking: Not authorized to enable/disable networking
$ sudo nmcli networking off

あ、、やっちまったwww ネットワーク切ったからssh切れちゃった。 さくらVPSからコンソール入って、以下のコマンド打って再起動しました。 そしたらsshで入れた、よかったーー。

$ sudo nmcli connection reload 
$ sudo nmcli networking on

んーーーだけどやっぱり起動しない。というかconnection見てみたら消えてるし。deviceは残っている。じゃあ追加してみるか。

$ nmcli connection add type ethernet ifname ens4 con-name ens4
Connection 'ens4' successfully added.
$ nmcli connection
NAME         TYPE      DEVICE
ens4         ethernet  ens4
System ens3  ethernet  ens3
System ens5  ethernet  --
$ nmcli device
DEVICE  TYPE      STATE                                  CONNECTION
ens3    ethernet  connected                              System ens3
ens4    ethernet  connecting (getting IP configuration)  ens4
ens5    ethernet  disconnected                           --
lo      loopback  unmanaged                              -- 
$ nmcli device show ens4
GENERAL.DEVICE:                         ens4
GENERAL.TYPE:                           ethernet
GENERAL.HWADDR:                         ~~~~
GENERAL.MTU:                            1500
GENERAL.STATE:                          70 (connecting (getting IP configuration))
GENERAL.CONNECTION:                     ens4
GENERAL.CON-PATH:                       /org/freedesktop/NetworkManager/ActiveConnection/4
WIRED-PROPERTIES.CARRIER:               on
IP4.GATEWAY:                            --
IP6.ADDRESS[1]:                         ~~~~
IP6.GATEWAY:                            --
IP6.ROUTE[1]:                           dst = fe80::/64, nh = ::, mt = 1024

おおーきた!! ん、ということはさっきのファイル直接編集はやっぱりしなくても良さげだな。connectionを一旦落として、addして、network設定すればよさげ。

というかこれ見てみたら、さっきの設定ファイル反映できてなくね? ....あとでそれはするとしてIP6のアドレス設定しかできてないからちょっとnmcliコマンドで修正しよう。

$ sudo nmcli connection modify ens4 ipv4.method manual ipv4.addresses "192.168.1.1/24" ipv6.method "ignore" connection.autoconnect yes
[rocky@ik1-443-53839 ~]$ nmcli device
DEVICE  TYPE      STATE         CONNECTION
ens3    ethernet  connected     System ens3
ens4    ethernet  connected     ens4
ens5    ethernet  disconnected  --
lo      loopback  unmanaged     --
[rocky@ik1-443-53839 ~]$ nmcli device show ens4
GENERAL.DEVICE:                         ens4
GENERAL.TYPE:                           ethernet
GENERAL.HWADDR:                         ~~~~~
GENERAL.MTU:                            1500
GENERAL.STATE:                          100 (connected)
GENERAL.CONNECTION:                     ens4
GENERAL.CON-PATH:                       /org/freedesktop/NetworkManager/ActiveConnection/15
WIRED-PROPERTIES.CARRIER:               on
IP4.ADDRESS[1]:                         192.168.1.1/24
IP4.GATEWAY:                            --
IP4.ROUTE[1]:                           dst = 192.168.1.0/24, nh = 0.0.0.0, mt = 101
IP6.GATEWAY:                            --

できているっぽいな。設定ファイルどうなったんかな。

$ cat /etc/sysconfig/network-scripts/ifcfg-ens4
DEVICE="ens4"
ONBOOT=”yes”
TYPE=”Ethernet”
IPADDR=”192.168.1.1″
NETMASK=“255.255.255.0

なんにも変わってないな。ええーー。サービス再起動してみるか。 ....変わらん。。 えぇ。。じゃあ設定ファイルもとに戻して、再起動して、pingしてみるか。

$ vi /etc/sysconfig/network-scripts/ifcfg-ens4
DEVICE=”ens4″
ONBOOT=”no”
TYPE=“Ethernet”

$ nmcli networking off && nmcli connection reload && nmcli networking on
$ ping -c 10 192.168.1.1
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.015 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.032 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=0.030 ms
64 bytes from 192.168.1.1: icmp_seq=4 ttl=64 time=0.026 ms
64 bytes from 192.168.1.1: icmp_seq=5 ttl=64 time=0.029 ms
64 bytes from 192.168.1.1: icmp_seq=6 ttl=64 time=0.030 ms
64 bytes from 192.168.1.1: icmp_seq=7 ttl=64 time=0.038 ms
64 bytes from 192.168.1.1: icmp_seq=8 ttl=64 time=0.029 ms
64 bytes from 192.168.1.1: icmp_seq=9 ttl=64 time=0.031 ms
64 bytes from 192.168.1.1: icmp_seq=10 ttl=64 time=0.027 ms

--- 192.168.1.1 ping statistics ---
10 packets transmitted, 10 received, 0% packet loss, time 9230ms
rtt min/avg/max/mdev = 0.015/0.028/0.038/0.005 ms

うん、まぁいいんかな。 じゃあこれで他のサーバーも同じ設定でいこか。

backの設定

さっきと違う方法でやってみよう。

$ nmcli connection
NAME         UUID                                  TYPE      DEVICE
System ens3  21d47e65-8523-1a06-af22-6f121086f085  ethernet  ens3
System ens4  e27f182b-d125-2c43-5a30-43524d0229ac  ethernet  --
System ens5  8126c120-a964-e959-ff98-ac4973344505  ethernet  --

$ nmcli connection modify e27f182b-d125-2c43-5a30-43524d0229ac connection.id ens4
$ nmcli connection
NAME         UUID                                  TYPE      DEVICE
System ens3  21d47e65-8523-1a06-af22-6f121086f085  ethernet  ens3
ens4         e27f182b-d125-2c43-5a30-43524d0229ac  ethernet  --
System ens5  8126c120-a964-e959-ff98-ac4973344505  ethernet  --

$ nmcli connection modify ens4 ipv4.method manual ipv4.addresses "192.168.1.2/24" ipv6.method "ignore" connection.autoconnect yes
$ nmcli connection
NAME         UUID                                  TYPE      DEVICE
System ens3  21d47e65-8523-1a06-af22-6f121086f085  ethernet  ens3
ens4         e27f182b-d125-2c43-5a30-43524d0229ac  ethernet  --
System ens5  8126c120-a964-e959-ff98-ac4973344505  ethernet  --
$ nmcli device
DEVICE  TYPE      STATE         CONNECTION
ens3    ethernet  connected     System ens3
ens4    ethernet  disconnected  --
ens5    ethernet  disconnected  --
lo      loopback  unmanaged     --

$ nmcli networking off && nmcli connection reload && nmcli networking on
$ nmcli connection
NAME         UUID                                  TYPE      DEVICE
System ens3  21d47e65-8523-1a06-af22-6f121086f085  ethernet  ens3
ens4         e27f182b-d125-2c43-5a30-43524d0229ac  ethernet  --
System ens5  8126c120-a964-e959-ff98-ac4973344505  ethernet  --

$ nmcli connection up ens4
Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/3)
$ nmcli connection
NAME         UUID                                  TYPE      DEVICE
System ens3  21d47e65-8523-1a06-af22-6f121086f085  ethernet  ens3
ens4         e27f182b-d125-2c43-5a30-43524d0229ac  ethernet  ens4
System ens5  8126c120-a964-e959-ff98-ac4973344505  ethernet  --
$ nmcli device show ens4
GENERAL.DEVICE:                         ens4
GENERAL.TYPE:                           ethernet
GENERAL.HWADDR:                         ~~~~~
GENERAL.MTU:                            1500
GENERAL.STATE:                          100 (connected)
GENERAL.CONNECTION:                     ens4
GENERAL.CON-PATH:                       /org/freedesktop/NetworkManager/ActiveConnection/3
WIRED-PROPERTIES.CARRIER:               on
IP4.ADDRESS[1]:                         192.168.1.2/24
IP4.GATEWAY:                            --
IP4.ROUTE[1]:                           dst = 192.168.1.0/24, nh = 0.0.0.0, mt = 101
IP6.GATEWAY:                            --

お、できたっぽい。たぶん以下のことをすると設定できるかな。

  • nmcli connection up をしてつなぐ
  • プライベートaddressの設定はするべき
  • networkingの再起動はいるかわからん
  • nmcli connection reloadはファイルを読む感じだから関係なさそう

じゃあpingで他のアドレスとも繋がっているか確認しよう。

$ ping -c 10 192.168.1.2
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=0.018 ms
64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=0.031 ms
64 bytes from 192.168.1.2: icmp_seq=3 ttl=64 time=0.031 ms
64 bytes from 192.168.1.2: icmp_seq=4 ttl=64 time=0.038 ms
64 bytes from 192.168.1.2: icmp_seq=5 ttl=64 time=0.036 ms
64 bytes from 192.168.1.2: icmp_seq=6 ttl=64 time=0.038 ms
64 bytes from 192.168.1.2: icmp_seq=7 ttl=64 time=0.030 ms
64 bytes from 192.168.1.2: icmp_seq=8 ttl=64 time=0.039 ms
64 bytes from 192.168.1.2: icmp_seq=9 ttl=64 time=0.032 ms
64 bytes from 192.168.1.2: icmp_seq=10 ttl=64 time=0.031 ms

--- 192.168.1.2 ping statistics ---
10 packets transmitted, 10 received, 0% packet loss, time 9200ms
rtt min/avg/max/mdev = 0.018/0.032/0.039/0.005 ms

$ ping -c 10 192.168.1.1
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.355 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.202 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=0.183 ms
64 bytes from 192.168.1.1: icmp_seq=4 ttl=64 time=0.282 ms
64 bytes from 192.168.1.1: icmp_seq=5 ttl=64 time=0.418 ms
64 bytes from 192.168.1.1: icmp_seq=6 ttl=64 time=0.160 ms
64 bytes from 192.168.1.1: icmp_seq=7 ttl=64 time=0.325 ms
64 bytes from 192.168.1.1: icmp_seq=8 ttl=64 time=0.294 ms
64 bytes from 192.168.1.1: icmp_seq=9 ttl=64 time=0.459 ms
64 bytes from 192.168.1.1: icmp_seq=10 ttl=64 time=0.233 ms

--- 192.168.1.1 ping statistics ---
10 packets transmitted, 10 received, 0% packet loss, time 9221ms
rtt min/avg/max/mdev = 0.160/0.291/0.459/0.094 ms

$ ping -c 10 192.168.1.3
PING 192.168.1.3 (192.168.1.3) 56(84) bytes of data.
From 192.168.1.2 icmp_seq=1 Destination Host Unreachable
From 192.168.1.2 icmp_seq=2 Destination Host Unreachable
From 192.168.1.2 icmp_seq=3 Destination Host Unreachable
From 192.168.1.2 icmp_seq=4 Destination Host Unreachable
From 192.168.1.2 icmp_seq=5 Destination Host Unreachable
From 192.168.1.2 icmp_seq=6 Destination Host Unreachable
From 192.168.1.2 icmp_seq=7 Destination Host Unreachable
From 192.168.1.2 icmp_seq=8 Destination Host Unreachable
From 192.168.1.2 icmp_seq=9 Destination Host Unreachable
From 192.168.1.2 icmp_seq=10 Destination Host Unreachable

--- 192.168.1.3 ping statistics ---
10 packets transmitted, 0 received, +10 errors, 100% packet loss, time 9199ms
pipe 4

おおーーー。ちゃんと自身のアドレスにpingできるだけじゃなくて、clientサーバー(192.1681.1)へpingもちゃんと送れてる。そして、まだ設定していないアドレス(192.168.1.3)には送れていない。

やりたいことできてるぅ!!

dbの設定

次は検証も含めて設定していこう。

$ nmcli connection modify e27f182b-d125-2c43-5a30-43524d0229ac connection.id ens4
$ nmcli connection up ens4
Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/2)
$ nmcli connection
NAME         UUID                                  TYPE      DEVICE
System ens3  21d47e65-8523-1a06-af22-6f121086f085  ethernet  ens3
ens4         e27f182b-d125-2c43-5a30-43524d0229ac  ethernet  ens4
System ens5  8126c120-a964-e959-ff98-ac4973344505  ethernet  --
$ nmcli device show ens4
GENERAL.DEVICE:                         ens4
GENERAL.TYPE:                           ethernet
GENERAL.HWADDR:                         9C:A3:BA:08:67:56
GENERAL.MTU:                            1500
GENERAL.STATE:                          100 (connected)
GENERAL.CONNECTION:                     ens4
GENERAL.CON-PATH:                       /org/freedesktop/NetworkManager/ActiveConnection/2
WIRED-PROPERTIES.CARRIER:               on
IP4.GATEWAY:                            --
IP6.GATEWAY:                            --

あーーーやっぱり起動はするし、つながりもするっぽいな。 だけど、private addressの設定指定なからこのままだとダメだね。

じゃあprivate addressの設定をしていこう。

$ nmcli connection down ens4
Connection 'ens4' successfully deactivated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/2)
$ nmcli connection
NAME         UUID                                  TYPE      DEVICE
System ens3  21d47e65-8523-1a06-af22-6f121086f085  ethernet  ens3
ens4         e27f182b-d125-2c43-5a30-43524d0229ac  ethernet  --
System ens5  8126c120-a964-e959-ff98-ac4973344505  ethernet  --

$ nmcli connection modify ens4 ipv4.method manual ipv4.addresses "192.168.1.3/24" ipv6.method "ignore" connection.autoconnect yes
$ nmcli connection up ens4
Connection successfully activated (D-Bus active path: /org/freedesktop/NetworkManager/ActiveConnection/3)
$ nmcli connection
NAME         UUID                                  TYPE      DEVICE
System ens3  21d47e65-8523-1a06-af22-6f121086f085  ethernet  ens3
ens4         e27f182b-d125-2c43-5a30-43524d0229ac  ethernet  ens4
System ens5  8126c120-a964-e959-ff98-ac4973344505  ethernet  --
$ nmcli device show ens4
GENERAL.DEVICE:                         ens4
GENERAL.TYPE:                           ethernet
GENERAL.HWADDR:                         9C:A3:BA:08:67:56
GENERAL.MTU:                            1500
GENERAL.STATE:                          100 (connected)
GENERAL.CONNECTION:                     ens4
GENERAL.CON-PATH:                       /org/freedesktop/NetworkManager/ActiveConnection/3
WIRED-PROPERTIES.CARRIER:               on
IP4.ADDRESS[1]:                         192.168.1.3/24
IP4.GATEWAY:                            --
IP4.ROUTE[1]:                           dst = 192.168.1.0/24, nh = 0.0.0.0, mt = 101
IP6.GATEWAY:                            --

よし、できた。じゃあpingで確認する。

$ ping -c 5 192.168.1.3
PING 192.168.1.3 (192.168.1.3) 56(84) bytes of data.
64 bytes from 192.168.1.3: icmp_seq=1 ttl=64 time=0.032 ms
64 bytes from 192.168.1.3: icmp_seq=2 ttl=64 time=0.045 ms
64 bytes from 192.168.1.3: icmp_seq=3 ttl=64 time=0.040 ms
64 bytes from 192.168.1.3: icmp_seq=4 ttl=64 time=0.032 ms
64 bytes from 192.168.1.3: icmp_seq=5 ttl=64 time=0.033 ms

--- 192.168.1.3 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4124ms
rtt min/avg/max/mdev = 0.032/0.036/0.045/0.005 ms

$ ping -c 5 192.168.1.1
PING 192.168.1.1 (192.168.1.1) 56(84) bytes of data.
64 bytes from 192.168.1.1: icmp_seq=1 ttl=64 time=0.391 ms
64 bytes from 192.168.1.1: icmp_seq=2 ttl=64 time=0.235 ms
64 bytes from 192.168.1.1: icmp_seq=3 ttl=64 time=0.181 ms
64 bytes from 192.168.1.1: icmp_seq=4 ttl=64 time=0.211 ms
64 bytes from 192.168.1.1: icmp_seq=5 ttl=64 time=0.267 ms

--- 192.168.1.1 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4115ms
rtt min/avg/max/mdev = 0.181/0.257/0.391/0.072 ms

$ ping -c 5 192.168.1.2
PING 192.168.1.2 (192.168.1.2) 56(84) bytes of data.
64 bytes from 192.168.1.2: icmp_seq=1 ttl=64 time=0.290 ms
64 bytes from 192.168.1.2: icmp_seq=2 ttl=64 time=0.219 ms
64 bytes from 192.168.1.2: icmp_seq=3 ttl=64 time=3.83 ms
64 bytes from 192.168.1.2: icmp_seq=4 ttl=64 time=5.86 ms
64 bytes from 192.168.1.2: icmp_seq=5 ttl=64 time=0.294 ms

--- 192.168.1.2 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4075ms
rtt min/avg/max/mdev = 0.219/2.098/5.856/2.331 ms

$ ping -c 5 192.168.1.4
PING 192.168.1.4 (192.168.1.4) 56(84) bytes of data.
From 192.168.1.3 icmp_seq=1 Destination Host Unreachable
From 192.168.1.3 icmp_seq=2 Destination Host Unreachable
From 192.168.1.3 icmp_seq=3 Destination Host Unreachable
From 192.168.1.3 icmp_seq=4 Destination Host Unreachable
From 192.168.1.3 icmp_seq=5 Destination Host Unreachable

--- 192.168.1.4 ping statistics ---
5 packets transmitted, 0 received, +5 errors, 100% packet loss, time 4083ms
pipe 4

いいねーー。ちゃんと自身と設定したサーバーには繋がって、それ以外には繋がらないっぽい。

サーバー同士の接続アドレス変更

じゃああとは、アドレスの向き先を変えればいいんかな?

  1. backとclientの接続
  2. dbとbackの接続

この二つを修正していこう。

backとclientの接続

clientからbackにapiを要求する時のアドレスを変えてみる。 このときはまだサーバーとdbはパブリックアドレスでつながっている。

まずはcurlコマンドで要求できるか確認する。

$ curl http:/192.168.1.2:8080/shops
{
    "message": "get shops",
    "shops": [
        {
            "ID": 5,
            "CreatedAt": "2023-01-15T07:40:33+09:00",
            "UpdatedAt": "2023-01-15T07:40:33+09:00",
            "DeletedAt": null,
            "Name": "test",
            "Description": "test"
        },
        {
            "ID": 7,
            "CreatedAt": "2023-01-21T23:23:37+09:00",
            "UpdatedAt": "2023-01-21T23:23:37+09:00",
            "DeletedAt": null,
            "Name": "test",
            "Description": "test"
        },
        {
            "ID": 8,
            "CreatedAt": "2023-03-05T18:28:01+09:00",
            "UpdatedAt": "2023-03-05T18:28:01+09:00",
            "DeletedAt": null,
            "Name": "牛角",
            "Description": "焼肉食べ放題ならここしかない。"
        }
    ]
}

完璧。じゃあ、コードを変えてみよう。

envファイルを変えてscpで送信してnginxを再起動してみる。

REACT_APP_SERVER_URL='http://192.168.1.2:8080'
$ scp services/client/app/.env.production rocky@133.125.51.93:/usr/local/src/app
.env.production                                                                     100%   46     1.4KB/s   00:00
$ ssh nabelog_client
$ cd /usr/local/src/app
$ sudo systemctl restart nginx

あれ、だけどlog見てみてもどうにも切り替わっていない。もしかしてbuildファイルにenvも含まれる系かな?いや、だけどCDでbuildするけどgithubにenvは持っていっていないし。

だとすると再起動ミスか?一回CD回してみて、それでもダメだったらサーバーを再起動してみよう。

.... ↓

一回CDしてみたけどダメだ。サーバーを再起動してみます。

... ↓

サーバー再起動してもダメだ。え、なんでだろ。 あーーproxyだ。package.jsonのproxy設定が前の状態になってるわ。

えーーこれ環境によって変えたいんだけど、どうしよう。。 んーーまぁとりあえずハードコーディングで変えましょか。

  "proxy": "http://パブリックアドレス:8080",
  ↓
  "proxy": "http://192.168.1.2:8080",

そして、再度npm installしてCDを再度回してみる。

[rocky@ik1-443-53839 app]$ npm install
(#########⠂⠂⠂⠂⠂⠂⠂⠂⠂) ⠹ reify:fsevents: sill reify mark deleted [ '/usr/local/src/app/node_modules/fsevents' ]
<--- Last few GCs --->

[1816:0x5ef0630]   140346 ms: Scavenge (reduce) 248.1 (256.9) -> 248.0 (257.4) MB, 10.7 / 0.0 ms  (average mu = 0.381, current mu = 0.368) allocation failure
[1816:0x5ef0630]   140408 ms: Scavenge (reduce) 248.6 (257.4) -> 248.4 (257.7) MB, 4.6 / 0.0 ms  (average mu = 0.381, current mu = 0.368) allocation failure
[1816:0x5ef0630]   140459 ms: Scavenge (reduce) 249.0 (257.7) -> 248.8 (258.2) MB, 9.0 / 0.0 ms  (average mu = 0.381, current mu = 0.368) allocation failure


<--- JS stacktrace --->

FATAL ERROR: Ineffective mark-compacts near heap limit Allocation failed - JavaScript heap out of memory
 1: 0xb09c10 node::Abort() [npm install]
 2: 0xa1c193 node::FatalError(char const*, char const*) [npm install]
 3: 0xcf8dbe v8::Utils::ReportOOMFailure(v8::internal::Isolate*, char const*, bool) [npm install]
 4: 0xcf9137 v8::internal::V8::FatalProcessOutOfMemory(v8::internal::Isolate*, char const*, bool) [npm install]
 5: 0xeb09d5  [npm install]
 6: 0xeb14b6  [npm install]
 7: 0xebf9de  [npm install]
 8: 0xec0420 v8::internal::Heap::CollectGarbage(v8::internal::AllocationSpace, v8::internal::GarbageCollectionReason, v8::GCCallbackFlags) [npm install]
 9: 0xec339e v8::internal::Heap::AllocateRawWithRetryOrFailSlowPath(int, v8::internal::AllocationType, v8::internal::AllocationOrigin, v8::internal::AllocationAlignment) [npm install]
10: 0xe84612 v8::internal::Factory::AllocateRaw(int, v8::internal::AllocationType, v8::internal::AllocationAlignment) [npm install]
11: 0xe7cc24 v8::internal::FactoryBase<v8::internal::Factory>::AllocateRawWithImmortalMap(int, v8::internal::AllocationType, v8::internal::Map, v8::internal::AllocationAlignment) [npm install]
12: 0xe7ee82 v8::internal::FactoryBase<v8::internal::Factory>::NewDescriptorArray(int, int, v8::internal::AllocationType) [npm install]
13: 0x10cced7 v8::internal::DescriptorArray::CopyUpTo(v8::internal::Isolate*, v8::internal::Handle<v8::internal::DescriptorArray>, int, int) [npm install]
14: 0x10bb011 v8::internal::Map::CopyAddDescriptor(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Map>, v8::internal::Descriptor*, v8::internal::TransitionFlag) [npm install]
15: 0x10bb5cc v8::internal::Map::CopyWithField(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Map>, v8::internal::Handle<v8::internal::Name>, v8::internal::Handle<v8::internal::FieldType>, v8::internal::PropertyAttributes, v8::internal::PropertyConstness, v8::internal::Representation, v8::internal::TransitionFlag) [npm install]
16: 0x10bd3f8 v8::internal::Map::TransitionToDataProperty(v8::internal::Isolate*, v8::internal::Handle<v8::internal::Map>, v8::internal::Handle<v8::internal::Name>, v8::internal::Handle<v8::internal::Object>, v8::internal::PropertyAttributes, v8::internal::PropertyConstness, v8::internal::StoreOrigin) [npm install]
17: 0x10abf52 v8::internal::LookupIterator::PrepareTransitionToDataProperty(v8::internal::Handle<v8::internal::JSReceiver>, v8::internal::Handle<v8::internal::Object>, v8::internal::PropertyAttributes, v8::internal::StoreOrigin) [npm install]
18: 0x10cf3da v8::internal::Object::AddDataProperty(v8::internal::LookupIterator*, v8::internal::Handle<v8::internal::Object>, v8::internal::PropertyAttributes, v8::Maybe<v8::internal::ShouldThrow>, v8::internal::StoreOrigin) [npm install]
19: 0x120860f v8::internal::Runtime_StoreDataPropertyInLiteral(int, unsigned long*, v8::internal::Isolate*) [npm install]
20: 0x15f2099  [npm install]
Aborted (core dumped)
[rocky@ik1-443-53839 app]$ free
               total        used        free      shared  buff/cache   available
Mem:          468352       84176      311032        5696       73144      366360
Swap:              0           0           0
[rocky@ik1-443-53839 app]$ free -m
               total        used        free      shared  buff/cache   available
Mem:             457          86         299           5          71         353
Swap:              0           0           0

これ容量たぶんたりないやつーーー(泣)

node_modules重すぎやろ。どうすればええねん。

たぶんdevのやつも全部installしようとしていたから、それを除いてinstallしてみる

$ rm -rf node_modules
$ npm cache clean --force
$ npm install --production

だめだ、なんかうまくいかん。ためしにlocalの容量を調べてみると。

$ du -h
796M    .

796Mか〜〜。そりゃぁたらんなぁ。だって僕の環境0.5Gだもの。 えーーー、あげるーー? ....あげるか。 お金かかるよ〜〜。。

結局上げました。 1GBにして、再度npm install --productionしたら無事でけた。

けど、まだサーバー間通信はうまくいかない。 試しにlocalでbuildして送ってみる。

すると、、うまくいった!正確にはうまくいっていないんだけど、ページ自体は表示された。 だけどaxiosで到達していない。こいつはもしかしてグローバルipアドレスだと思っている?ローカルipアドレスが?

うーーん、調べるか。

調べていったらわかったーーー

なるほどな、nginxのリバースプロキシを使うのか。

Q. リバースプロキシってなに? A. リバースプロキシ (Reverse Proxy) とは、Webサーバーとして動作し、クライアントからのリクエストを受け取り、対象のサーバーに転送する役割を持つサーバーのことを指します。リバースプロキシサーバーは、その機能により、次のような利点を持っています。 ロードバランシング リバースプロキシサーバーは、バックエンドサーバーの負荷を分散するために、リクエストを複数のサーバーに振り分けることができます。これにより、トラフィックの過負荷を回避し、ユーザーエクスペリエンスを向上させることができます。 キャッシング リバースプロキシサーバーは、一度クライアントからリクエストを受け取ったコンテンツをキャッシュすることができます。これにより、バックエンドサーバーへの負荷を軽減し、ユーザーにより高速なコンテンツ配信を提供することができます。 セキュリティ リバースプロキシサーバーは、フロントエンドとバックエンドサーバーの間に置かれるため、クライアントからの直接接続を防ぐことができます。これにより、バックエンドサーバーを直接攻撃されるリスクを軽減し、セキュリティを向上させることができます。 URLの書き換え リバースプロキシサーバーは、クライアントがアクセスするURLを変更することができます。例えば、example.com/api にアクセスした場合に、api.example.com にアクセスするように変更することができます。これにより、バックエンドサーバーのURLを隠蔽することができます。 リバースプロキシは、Webアプリケーションの運用において、非常に重要な役割を担っています。特に、アプリケーションのロードバランシングやセキュリティ対策には、欠かせない存在となっています。
引用元:ChatGPT

じゃあ設定していこう。

server {
  listen       80;
  server_name  nabelog-client;
  charset      utf-8;

  root /usr/local/src/app/build;
  index index.html;

  location / {
    try_files $uri /index.html;
  }
# ↓これを追加
  location /api/ {
    proxy_pass http://192.168.1.2:8080/;
    proxy_set_header Host $host;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
  }
}

これは「/api/が先頭につく要求はhttp://192.168.1.2:8080/にプロキシするよ」っていう意味。

あと、これが悪さしてたから消しとこう。

  "proxy": "http://192.168.1.2:8080", ← 削除

さぁこれで????

サーバー間通信成功証拠写真

きたーーー!!! 長かった、やっと。 いい勉強になりました。

んで、一応backが他の人からアクセスされないようにネットワークとの接続を切っておこう。

$ sudo nmcli connection down 'System ens3'
client_loop: send disconnect: Broken pipe

あ、、、www そりゃそうか。インターネット経由でサーバーにsshアクセスしてるんだからそうなる。

んーけどなんかens3の接続切ったらローカル通信も切れるっぽい。 CORS設定もしてるし、一旦放置。

dbとbackの接続

次はdbとbackの接続です。 これはどうなんだろ、buildファイルと繋がるのはmysqlを直接参照するし、そんなに問題なさげ。 まずbackサーバーからdbサーバーにプライベートネットワークでmysql接続できるか試してみる。

$ mysql -u server -h 192.168.1.3 -p
-bash: mysql: command not found

うわ、だる。。うーーーん。。mysqlをinstallするとそれだけ容量減るからやだな。。

とりあえずできている前提でつぎやろうか。もしできなかったらやむなくinstallしよう。

ということで早速buildファイルの向き先をプライベートipアドレスに変えてやってみる。

# Clientからの呼び出し元URL
CLIENT_URL="http://192.168.1.1"

MYSQL_DATABASE=DB名
MYSQL_USER=ユーザー名
MYSQL_PASSWORD=パスワード
MYSQL_ROOT_PASSWORD=パスワード
MYSQL_HOST=192.168.1.3

じゃあsystemctlで再起動してみよう。

,,,動かない。。 やっぱりダメかぁ。。じゃあbackサーバーにmysqlを入れよう。

けどこれ思った。clientからアクセスを確認しても実質同じじゃね? ということで容量があるclientからやろう。

$ sudo dnf install mysql-server
43M
・
・
success

$ sudo systemctl start mysqld.service
$ systemctl status mysqld
● mysqld.service - MySQL 8.0 database server
     Loaded: loaded (/usr/lib/systemd/system/mysqld.service; disabled; vendor preset: disabled)
     Active: active (running) since Sun 2023-03-19 00:35:01 JST; 6s ago

43Mは辛いけど、うごいたっぽい。 じゃあclientからdbに呼び出してみよう。

$ mysql -u server -h 192.168.1.3 -p
Enter password:
ERROR 1045 (28000): Access denied for user 'server'@'192.168.1.1' (using password: YES)

んーーー、なんかアクセス拒否されてるな。dbサーバーから直接mysql潜ってみてみよう。

mysql> SELECT host, user from mysql.user;
+-----------------+------------------+
| host            | user             |
+-----------------+------------------+
| %               | exuser           |
| パブリックip      | server           |
| localhost       | mysql.infoschema |
| localhost       | mysql.session    |
| localhost       | mysql.sys        |
| localhost       | root             |
+-----------------+------------------+
6 rows in set (0.00 sec)

あーーそうだった。アクセス制限してるんだった。 じゃあこのユーザー名:serverのやつのhostを変えよう。

mysql> drop user server@パブリックip;
Query OK, 0 rows affected (0.01 sec)

mysql> create user 'server'@'192.168.1.2' identified by パスワード;
Query OK, 0 rows affected (0.00 sec)

mysql> create user 'client'@'192.168.1.1' identified by パスワード;
Query OK, 0 rows affected (0.01 sec)

これでアクセスできるかな?

$ mysql -u client -h 192.168.1.3 -p
Enter password:
Welcome to the MySQL monitor.  Commands end with ; or \g.
Your MySQL connection id is 222
Server version: 8.0.30 Source distribution

Copyright (c) 2000, 2022, Oracle and/or its affiliates.

Oracle is a registered trademark of Oracle Corporation and/or its
affiliates. Other names may be trademarks of their respective
owners.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

mysql>

でけたーーー!

じゃあ権限絞って、最後に確認しよう。

mysql> grant all on nabelog_pro.* to server@192.168.1.2

サーバーとdbのプライベートネットワーク化完了

でーーーけた!!! 終わり!!