はじめに
タイトルにもあるようにSSRがよくわからんかった。
だから調べた。
それをここにアウトプットします。
タイトルにもあるようにSSRがよくわからんかった。
だから調べた。
それをここにアウトプットします。
自作アプリを作っている途中でcss-in-jsについて知らないことが多すぎて、調べた。
それをまとめただけ。
Q. もしかしてCSS Modulesはcss-in-jsではないの? A. CSS Modulesは、CSSをモジュールとして扱うことによって、CSSの名前空間を自動的に生成し、スコープを限定することができるCSSのアプローチです。これは、CSSをJavaScriptのモジュールとして取り扱うことで実現されますが、厳密に言えば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を書くこと。
と、こんな感じで終わりましょか。
swagger-uiの実装をしようと思ったんだけど、前できなかった。
いまならできそう。あと、いろいろキャッチアップする
順番はこうかな
なーーに作ろう。next.jsの強みを調べようか。
...というかそもそも、next.jsってreactのフレームワークだったのかww 知らんかった。
あとnext.jsってSSRなんね。ほえーー。
まぁ、レンダリングの強みを活かしたいから、blogでも作ってみる?chanabe-blog。
ということで簡単に設計
じゃあまずは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いれよーー。
$ 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.
おお、なんかできたっぽい。 すげぇファイルいっぱいできてるーー笑
公式の解説を読んでこ。
これが言っていることをまとめると
んなーーーー、これやってて思った。
Swagger(opanapi)関係ねぇ。
ということは? 構成を変えましょ。
turborepoの強みとdockerの強みが生きるように。
じゃあturborepoのやり方もある程度わかったので、次はswaggerの設定をしよう。
なんか、かんたんにできるっぽい?
やってみる。
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作成にあたっての注意点が乗ってたから読んでみた。
- 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 - HTTPS(TLS暗号化) - 返すステータスはちゃんとしよう - エラー:4xx - 正常:2xx引用元:API設計スキルを次のレベルに引き上げるベストプラクティス22選
あとOpenAPIの作り方についても。
- yamlのオブジェクトは以下の構成 - openapi / info - titleやバージョンなど - バージョンは基本的にセマンティックバージョニング - servers - APIのベースパスを設定できます(/api/v0とか) - それぞれ変数ベースで用意できるし、開発者用・本番用にも分けれられる - components - paths等から呼び出せるコンポーネントを定義する - requestとresponseで表示非表示を制御できるreadOnly/writeOnlyというのがある - security - apiKeyなどを定義できる - 全体に適用したり、個別のpathで設定が可能引用元:作って理解する OpenAPI 3.0 / connexion
あとこれも読んだ、いうてさっきのとあんまり変わらんかったが。
- SSLは使おう - レスポンスは絞れるように - 作成・更新のあとのデータは絞れるように - エラーメッセージはしっかり返そう引用元:翻訳: WebAPI 設計のベストプラクティス
これはAPIのエラーメッセージについて
- エラーメッセージの分類は最小限に。以下くらいで十分。あんまり多くすると開発者の負担になる。 - 200 - 400 - 401 - 402 - 404 - 500 - エラーメッセージは丁寧説明的で。そして開発者に何をすべきかを促すように。引用元:REST API Error Codes 101
これも読んだ。 エラーは簡潔で説明的であれ。
おk。だいぶわかった。
じゃあ作ってみよ。
...だけど作っているときに大変なことがわかった。 StoplightStudioとaspidaがreadOnlyとwriteOnlyをサポートしていないっぽいのだ。まじかよ。
てか色々穴があるな。。ちょっと使いたくないかも。
だけど、一旦これで進めよう。readOnlyとかは別モデルとして定義して上げてやっていこう。。 もしだめっぽかったら、VSCodeの拡張機能で勧めていこう
作った!
おー表示された
だけど、なんだかエラーは出ている。
どうやら、Prismだとserverに設定したbaseUrl設定が無効になるらしい。
今回は,わざわざエンドポイントごとに `/api/v0` を入れて書いているが,本来ならば `server:` に一括で指定したい.しかしそうするためには,以下の記事にあるように,現状はPrism以外のツールを使う必要がある模様.引用元:Swagger (OpenAPI) について
うーーん、これを見てみるとどうやら開発者は、「baseURLはあくまでサーバーが管理する必要があるものであり、OpenAPIが管理する必要がない」という主張っぽいな。あくまでpathの管理をするのがPrismaか。
じゃーーー今回はいっか。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'
よし、動いた。
次は、nextアプリを入れてみる。
なお、キャッチアップはこれでやった。
next, react, react-domを入れて、pagesフォルダ作って、yarn devしたらできるというなんともかんたん。
あと、turborepoもcreate-turboみたいな感じの自動setupじゃなくて、manualのsetupをしていこう。
やってみよう。
appsフォルダを作って、その配下にアプリの名前を作る。今回だったら、CDSとCMS。
こんな感じ。
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
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を配置していく。
中身は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/*" ], }
これは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" ] }
これで完了。
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.
いいね、回った。
これも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
turborepoを用いた開発をするときに、next.jsを使おうと思ったのですが、まぁ全くやったことなかったので何もできませんでした。
なのでここで一旦キャッチアップしてからturborepoのキャッチアップをしようと思います。
まず環境を作る。
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
これで、起動して、コマンドでアプリを作成していく。
これ参考
$ 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
で表示された。
そのために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の変換のヤバさを伝えるために、漢字への変換を修正しません)
やっぱり無難にgoogle変換かな?
もし使いにくかったら別のに変えよう。
だけど,,,あれ?入力ができない。
いろいろ調べてみたけど、そんな挙動ないので、パソコンを再起動してみた。
そしたら行けた。
まぁーーーいいんじゃないか?今の所別に違和感はない。 だけど、一度間違えると次からそれを表示しちゃうのが少し嫌かも。
あーー逆か。macだと修正してくれなかったから逆にいいかも。
まぁ使っていこう。
ある日朝起きた時に思った。
「朝ラジオ聴いたら目が覚めるけど、ニュースラジオは日経のものばっかり、エンジニアのものってないのかな?」
いろいろ調べてみた、だけどない!!!!
特にデイリーのがない。
え、じゃあ作らしてもらってもよろしい?
ラジオ作るのに必要なことを調査しましょう。
たぶんポッドキャストがいいと思う。 だいたいシェアで上位なのはこの3つかな。(参考:ポッドキャスト国内利用実態調査2021)
んーーーいい感じになってきたら広げていっていいけど、まずはSpotifyからかな。僕使ってるし。
Podcastのあげかたもむずくなさげ。 あとでやりましょ。
んで、今知ったけど、収益化できなそう。 海外だと収益化できるみたいだけど、現状日本だとできなそうだね。
けど将来的にできそうだから、一旦ユーザー集める感じでいきたみ。
これが一番未知。聞きやすいかが調べたいとこ。
→ ドンピシャの記事みっけ、だけど「音読さん」という会社がやっているところだから音読さんがよく見える。まぁ候補。
→ 参考
→ 無料ですげぇ自然。
→ これもありだけど、どうやら150字までしか無理そう。
ChatGPTは2021年以降の情報を学習していないので、昨日今日のニュースはまとめてくれなそう。 だからbing一択になりそう。
Google Bardも期待できそうだけど、リリースがまだなので一旦様子見。
ここらへんの原稿作成が一番アップデートしがいがあるので、随時情報を得ていきましょ。とりあえず始めることが大事。
まずは配信する場所を作りましょう。
...え?これだけ?簡単すぎぃ。
アイコン画像欲しいからなんか作ろうか。
とりあえず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文字以上にしてください。 - この原稿はニュースキャスターの声をした自動音声読み上げに読ませる想定で作成してください。なので固有名詞はひらがなで表記し、アルファベット表記のところはひらがなで表記してください。 - 最初の挨拶は「おはようございます。本日もエンジニアのためのニュースをお届けします。」にしてください。 - 最後の挨拶は「以上エンジニアのためのニュースでした。明日もまた聞いてくださいね。今日も一日頑張りましょう。」にしてください。 - これを聞く人はラジオで聞くため、引用などの表記はしないでください。
いいね、一旦完成。
自分で記事をピックアップするバージョンのも作ってみた。
やり方を変えたらうまく行った。 まずは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の価格は12万5000ドル(約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にあげた。
これ最高だわ。
だけど、少しだけ自動音声の読み上げが弱いところがある。 だからそれを修正する。
よし、結合してダウンロードもできた。
とりあえずアップ準備。
あと規約も改めて読みましょう。
タイトルとエピソード説明のフォーマットはこれ。
タイトル: 2023年4月03日(月)イタリアによるChatGPTへの規制など 説明: 前日に以下のニュースサイトで投稿された記事を要約しています。 * https://techcrunch.com/ * https://newspicks.com/theme-news/technology/ * https://www.businessinsider.jp/sai/
よし!公開!
時間は朝の6:30で!
とりあえず運用とか考えず公開してしまいますた。
URLはこれです。
とりあえず毎日やってみようか。 前日までの記事をピックアップすればいいから、夜中にやって、次の日の朝に公開するように。
これにいろいろ機能をつけてきた。 さぁ次はサーバー間通信かな。
localでのサーバー間通信はやってきたけど、本番環境でのサーバー間通信はやったことがない。 ワクワク。やっていこ!
→ これでやるっぽい。こんな簡単にできるのか?
→ manualはこれ。やってみるか。
→ やり始めまで参考
→ いまはようわからんけど、あとあと参考になりそう
→ 参考になりそう
→ クソ参考になりそう
→ まんまやん
検索方法はこれ [さくらVPS ローカル接続]
他の人のサイトを見ながらやってみよう。
とりあえず作ってみた。
サーバー間通信を行うための、サーバー3つ(front, back, db)をシャットダウンする。
サーバーの設定画面 > ネットワーク > ネットワークインターフェース から接続先を設定。
eth0は基本的にインターネットに接続するみたい。だからeth1をさっきのスイッチに設定。
だけどあとでbackサーバーとdbサーバーはeth0のインターネット接続を外す、必要ないしね。
んで、いろいろみていたら、どうやらこの後はnmcli
コマンドというものを使うっぽい。
そして、どうやらこっから先のさくらVPS関連の設定はなさげ?
ということは [ nmcli サーバー間通信 ]とかで調べたら出てきそう。
調べてみたけど、やっぱりさくらVPSありきの設定ではありそう。local通信を行うために今回スイッチ作ったしね。
これらを参考にやってみる
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
うん、まぁいいんかな。 じゃあこれで他のサーバーも同じ設定でいこか。
さっきと違う方法でやってみよう。
$ 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: --
お、できたっぽい。たぶん以下のことをすると設定できるかな。
じゃあ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)には送れていない。
やりたいことできてるぅ!!
次は検証も含めて設定していこう。
$ 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
いいねーー。ちゃんと自身と設定したサーバーには繋がって、それ以外には繋がらないっぽい。
じゃああとは、アドレスの向き先を変えればいいんかな?
この二つを修正していこう。
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の接続です。 これはどうなんだろ、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
でーーーけた!!! 終わり!!