とーますメモ

Ruby on Rails / Goなどの学習メモ

【React】Styled-components導入時のメモ

CSS in JS。
コンポーネント内にCSSを記述できるのでスコープが明確になる。

TypeScriptを使用するので、@types/styled-componentsをインストール。
TypeScript内のCSSの補完を行いたいので、typescript-styled-pluginもインストール

インストール

$ npm install --save-dev styled-components @types/styled-components typescript-styled-plugin

tsconfig.jsonの変更

以下を追加

{
  "compilerOptions": {
    ...
    "plugins": [{ "name": "typescript-styled-plugin" }]
    ...
  }
}

ThemeProviderはめちゃめちゃ便利そう。
styled-components を試す - アカベコマイリ

defaultPropsはThemeProviderと組合わえてテーマ設定をデフォルトとして使うときに良さげ。
styled-componentsの使い方(パッとわかりやすく、色々なパターンを説明することを目指しています) · GitHub

【React】React × TypeScript × ESLint設定時のメモ

パッケージマネージャーはnpmを使用。
エディターはVSCode。VSCodeの設定とPrettierの設定は以前書いた。

MacでVSCodeを使用してみた - とーますメモ
【VSCode】 フロントエンド開発の使う自分用のPrettier設定まとめ - とーますメモ

Next.jsインストール

$ npx create-next-app "プロジェクト名"

/pagesを/srcに移す

ルートディレクトリが肥大化しわかりづらくなるため移動するのが現在のところベストプラクティスっぽい。
✨Next.js入門✨ 思考停止・爆速開発テンプレ 【TypeScript+ESLint+Prettier】
Blog - Next.js 9.1 | Next.js

$ cd "プロジェクト名"
$ mkdir src && mv pages src

/pagesを/src直下に移したことで__app.jsとindex.jsで読み込んでいるCSSのパスが変わるので以下のように変更する

__app.js

# import '../styles/globals.css';
import '../../styles/globals.css';

index.js

# import styles from '../styles/Home.module.css'
import styles from '../styles/Home.module.css'

この時点で、以下のコマンドを打て、localhost:3000にアクセスすればサンプルページが表示される

$ npm run dev

次にTypeScriptをインストールするためにCtrl + Cで一旦止める

ReactにTypeScriptを導入

プロダクションでは使用しないので、「devDependencies」としてインストールする -D オプションを使う。

$ npm i -D typescript @types/react @types/react-dom @types/node

拡張子の変更

以下のJavaScriptファイルの拡張子をjsからtsxに変更する。TypeScriptはJavaScriptの上位互換なので変更しても動作する。

src/pages/index.js → src/pages/index.tsx
src/pages/_app.js → src/pages/_app.tsx
src/pages/api/hello.ts → src/pages/api/hello.ts

helloはJSXを使用しない純粋なTypeScriptファイルなので拡張子はtsxではなく、tsを使用する。
【TypeScript】.ts拡張子と.tsx拡張子 - Qiita

Next.jsでTypeScriptの環境を構築する|Playground発!アプリ開発会社の技術ブログ
上記のサイトさんと同じように既存のファイルをTypeScriptのフォーマットに変更していく。

tsconfig.jsonを設定

以下の内容を設定

{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "isolatedModules": true,
    "resolveJsonModule": true,
    "noEmit": true,
    "jsx": "preserve",
    "sourceMap": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "noFallthroughCasesInSwitch": true,
    "noImplicitAny": true,
    "removeComments": false
  },
  "exclude": ["node_modules"],
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"]
}

以下のサイトを参考にした
【入門】create-next-appでNext.jsとTypeScript環境を構築 | モグモグ
tsconfig.jsonの全オプションを理解する(随時追加中) - Qiita
Next.jsでTypeScriptの環境を構築する|Playground発!アプリ開発会社の技術ブログ
React with TypeScript: Best Practices - SitePoint

ESLintの設定

最終的に以下をインストール

$ npm install -D eslint @typescript-eslint/eslint-plugin @typescript-eslint/parser eslint-plugin-react eslint-plugin-react-hooks eslint-plugin-jsx-a11y eslint-config-prettier eslint-plugin-jest

インストールされる各プラグインについて

eslint

ESLint本体
適用されるルール: List of available rules - ESLint - Pluggable JavaScript linter

eslint-plugin-react

Reactのルール
適用されるルール:
GitHub - yannickcr/eslint-plugin-react: React specific linting rules for ESLint

eslint-plugin-react-hooks

React-Hooksのルール

@typescript-eslint/eslint-plugin と @typescript-eslint/parser

TypeScriptのルールと、ESLintがTypeScriptをパースすることを許容するパーサー

eslint-plugin-jsx-a11y

Webアクセシビリティー関連のルール
適用されるルール
eslint-plugin-jsx-a11y - npm

eslint-plugin-prettier

ESLintからPrettierを実行できる。ただしPrettier自体は別にインストールしている必要がある。

以前の記事でインストール済みなので、Prettier自体のインストールは省略
【VSCode】 フロントエンド開発の使う自分用のPrettier設定まとめ - とーますメモ

公式推奨が変わったため、eslint-plugin-prettierをいれない方針にする

詳細は以下のサイトさんを参考
Prettier と ESLint の組み合わせの公式推奨が変わり plugin が不要になった
eslint-plugin-prettier を ESLint から 分離するサンプル – Intellij IDEA の設定変更も | DevelopersIO

要は、ESLintとPrettierを個別に使用する方針にした。
こうすることでesllint-plugin-prettierが原因で起こる以下の決定をなくせる。

・エディターに赤いニョロニョロがたくさん出てくる。Prettier は format のことを気にしなくてもいいようにさせるツールなのに、フォーマットの警告が前面にでてきてしまう。
・直接 Prettier を実行するより遅い
・レイヤーをひとつ挟んでおり、不整合が起きる可能性がある

Prettier と ESLint の組み合わせの公式推奨が変わり plugin が不要になった

eslint-config-prettier

Prettierと競合するルールをオフにしてくれる

eslint-plugin-jest

Jest用のルール

設定ファイルの作成及び内容

以下のコマンドで設定ファイルを作成

$ npx eslint --init

回答内容は以下
How would you like to use ESLint?
=> To check syntax, find problems, and enforce code style

What type of modules does your project use?
=> JavaScript modules (import/export)

Which framework does your project use?
=> React

Does your project use TypeScript?
=> Yes

Where does your code run?
=> Browser

How would you like to define a style for your project?
=> Use a popular style guide

Which style guide do you want to follow?
=> Standard: https://github.com/standard/standard

What format do you want your config file to be in?
=> JavaScript

Would you like to install them now with npm?
=> Yes

.eslintrcが出力されるので、それをカスタマイズ。最終的に以下にした。

module.exports = {
  env: {
    browser: true,
    es2021: true,
    jest: true,
  },
  extends: [
    "eslint:recommended",
    "plugin:react/recommended",
    "plugin:@typescript-eslint/eslint-recommended",
    "plugin:@typescript-eslint/recommended",
    "plugin:jsx-a11y/recommended",
    "prettier",
  ],
  parser: "@typescript-eslint/parser",
  parserOptions: {
    ecmaFeatures: {
      jsx: true,
    },
    ecmaVersion: 12,
    sourceType: "module",
  },
  plugins: ["react", "react-hooks", "@typescript-eslint", "jsx-a11y"],
  rules: {
    "react/prop-types": "off",
    "react/react-in-jsx-scope": "off",
  },
  settings: {
    react: {
      version: "detect",
    },
  },
};

設定オプションについては以下のサイトさんの解説が良かった。
https://t-yng.jp/post/understand-eslint

ちなみに.eslintignoreは以下を設定

**/node_modules
**/.next/**
**/dist/**
*.config.js
.*lintrc.js

VSCodeにESLintの拡張をインストール

インストール後に、settings.jsonに以下の設定を入れれば保存時にESlint autofixがかかる。

"editor.codeActionsOnSave": {
  "source.fixAll.eslint": true
},

ESLintとPrettierについて

上記でも書いたが個別に動かすの方針。
VSCodeを使っているので、通常はESLintとPrettierはVSCodeの自動フォーマット機能を使用し、npm scriptsを使うときは一括でlintやフォーマットを行いたいケースという風に使い分けする。

ちなみにnpm scriptsは以下のように設定する。

"scripts": {
    "lint": "run-p -l -c --aggregate-output lint:*",
    "lint:eslint": "eslint .",
    "lint:prettier": "prettier --check .",
    "fix": "run-s fix:prettier fix:eslint",
    "fix:eslint": "npm run lint:eslint -- --fix",
    "fix:prettier": "npm run lint:prettier -- --write",
    "test": "run-p -l -c --aggregate-output lint:* unit",
    "unit": "jest"
}

ESLint, Prettier, VS Code, npm scripts の設定: 2021春

ちなみに上記のrun-pを動作させるためには[npm-run-all]のパッケージをインストールする必要がある。
npm run のスクリプトを連続実行・並列実行する (npm-run-all) | まくまくNode.jsノート



[参考]
ESLint のススメ
✨Next.js入門✨ 思考停止・爆速開発テンプレ 【TypeScript+ESLint+Prettier】
ESLint, Prettier, VS Code, npm scripts の設定: 2021春

【VSCode】 フロントエンド開発の使う自分用のPrettier設定まとめ

以下の記事さんがすごいまとまっていてよかった。
【Prettier】「なんとなく使う」から「分かって使う」へ【Visual Studio Code】 - AI can fly !!

要はVSCodeで、Prettierを使うには以下の2つの方法がある。

1)npmやyarm経由でインストールしたPrettierを使う方法
2)VS Codeの拡張機能にバンドルされているPrettierを使う方法

VS Codeの拡張機能でPrettierを使用している場合で、
ローカルやグローバルにPrettierがインストールされていない場合
VS Codeの拡張機能にバンドルされているPrettierが使用されるため、チーム開発等の場合、バージョンを揃えるのが難しくなってしまう。

そのためVS CodeでPrettierを使用する場合は、まずローカルにnpmやyarm経由で、Prettierをインストールした後にVS CodeでPrettierを使用することを推奨している。ローカルにPrettierがインストールされていれば、VS Codeの拡張機能もそのPrettierを使用する。

This extension will use prettier from your project's local dependencies (recommended).

Should prettier not be installed locally with your project's dependencies or globally on the machine, the version of prettier that is bundled with the extension will be used.

Prettier - Code formatter - Visual Studio Marketplace

またグローバルにPrettierをインストールしている場合は、
「prettier.resolveGlobalModules」を「true」に設定すれば良い。

また固定バージョンのprettierをpackage.jsonに書き込みたい場合は以下のコマンドを使用すれば良い。

$ npm install -D --save-exact prettier

インストールするとVS Code上で、インストールしたPrettierが使用される旨のプロンプトが表示されるので「Allow everywhere」を選択する。

後、VS Codeのsettions.jsonで以下をしてしてあげればフォーマッターが設定できる。

// すべての言語で保存時にフォーマットを行う
"editor.formatOnSave": true,

// すべての言語を対象に既定のフォーマッターを設定する場合
"editor.defaultFormatter": "esbenp.prettier-vscode",

"[javascript]": {
  // 言語単位で既定のフォーマッターを設定する場合
  "editor.defaultFormatter": "esbenp.prettier-vscode",

  // 言語単位で保存時にフォーマットを行うか設定する
  "editor.formatOnSave": true
}

【Prettier】「なんとなく使う」から「分かって使う」へ【Visual Studio Code】 - AI can fly !!

プロジェクト直下に.prettierrcファイルを作成することで、独自ルールが設定でき、VS Code上の設定が上書きされる。
このファイルをチームで共有すれば同じフォーマッター設定が使用できる。

設定する内容

prettierrc

{
  "printWidth": 120,
  "singleQuote": true,
  "endOfLine": "lf"
}

[参考]
【VSCode】Prettierの使い方&おすすめ設定を紹介 | 北海道札幌市のホームページ・Web制作会社|株式会社マーベリックス
.prettierrc - Qiita
prettier-v1.13.7チートシート - Qiita

【Nginx】ngxtopを使用してリアルタイムアクセスログ監視をしてみた

環境はUbuntuを使用。アクセスログ解析ツールとしてGoAccessというツールもあるが、単純にシンプルなツールを使いたかったので、ngxtopを採用した。

インストール

github.com

$ pip3 install ngxtop

使用方法

access_logのパスが/etc/nginx/nginx.confに記載されていれば
単純に以下のコマンドで監視が始まる。

$ ngxtop

自分の場合、一台のサーバで複数のサイトを運営しているため
access_logのパスはサーバ毎の設定ファイルに記述してある。
そのため上記のコマンドを打つと以下のエラーがでる。

$ ngxtop
Error: Access log file is not provided and ngxtop cannot detect it from your config file (/etc/nginx/nginx.conf).

こういった場合は、ログファイルの場所を指定することで使用できるようになる。

$ ngxtop -l /var/log/nginx/access.log

ちなみに余談だが、自分の場合は上記のコマンドでもngxtopが動作しなかった。
調べたところ、ログのフォーマットを独自フォーマットにしていたことが原因だった。

@shaun-ba This was happening to me too and my nginx config is using a custom log format, which turned out to be the issue. Check your nginx.conf file to see if you're doing the same (grep for log_format in the config directory) and if so, just pass ngxtop the config format and it works:

no data · Issue #83 · lebinh/ngxtop · GitHub


なので以下のようにログフォーマットを指定して実行することで、動作した。

$ ngxtop -f '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for" "gzip=$gzip_ratio"' -l /var/log/nginx/access.log

デフォルトだと現在既に出力されているaccess.logのデータは無視されるので
既存のaccess.logを元にしたデータが見たいときは"--no-follow"を指定する。

$ ngxtop -f '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for" "gzip=$gzip_ratio"' -l /var/log/nginx/access.log --no-follow

デフォルトだと10件までしか表示されないので、"-n"オプションを使って、100件表示させる

$ ngxtop -f '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for" "gzip=$gzip_ratio"' -l /var/log/nginx/access.log -n 100

また自分の場合、攻撃目的でアクセスしてくるログを見たいという用途があったため最終的に以下のコマンドになった。

$ ngxtop -f '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for" "gzip=$gzip_ratio"' -l /var/log/nginx/access.log -n 100 -i 'status >= 400' print request status http_referer http_x_forwarded_for

printで表示させるでデータは、nginxと同じものが指定できる。

備考

特定のIPを無視したいときは"-i"オプションを使用する

$ ngxtop -f '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for" "gzip=$gzip_ratio"' -l /var/log/nginx/access.log -n 100 -i 'status >= 400' print request status http_referer http_x_forwarded_for -i 'remote_addr != "xxx.xxx.xxx.xxx"'

[参考]
ngxtop - LinuxでリアルタイムでNginxログファイルを監視する
Monitor Nginx Log Files Using ngxtop on Ubuntu 20.04

【Nginx】複数ドメイン+SSLを同じサーバで設定する方法

昔は、1台のサーバに複数のドメインが設定できても、SSL証明書は1つしか設定できなかったが、今はSNI (Server Name Indication)という仕組みを使うことで1台のサーバでもドメイン数だけSSL証明書をできるようになった。(ワイルドカード証明書、通常SSL証明書の組み合わせでもできる)

詳細は以下のページを参照。
www.idcf.jp

WebサーバでSNIが使用できるかは以下のコマンドで
「TLS SNI support enabled」と表示されていれば使用できる

$ nginx -V
...
...
TLS SNI support enabled
...

Nginxの設定は以下のページを参考にした。
Nginx でSSLを使ってみた(追記:SNIを含めてマルチドメインへの対応) | レンタルサーバー・自宅サーバー設定・構築のヒント

失敗談

実はこの設定をする前に既にひとつのサイトを運営していたのだが、
そのサイトのserver_name設定がそもそも間違えていて、運良くdefault_serverとして間違えていたserver_nameのserverコンテキストが選ばれていたためサイトが動作していたことがわかった。これがわかるまで結構時間がかかった。

間違い

server {
  server_name example.com
}

正しい

server {
  server_name www.example.com
}

【Nginx】IPアドレス直接アクセスを防ぐ(ドロップさせる)方法

Hostヘッダが未定義なリクエスト、つまりIPアドレス直接アクセスを防ぐために試したことのメモ。

未定義のリクエストをさばくためのServerコンテキストを以下のように定義する。

server {
    listen       80  default_server;
    server_name  _;
    return       444;
}

設定で複数のバーチャルサーバがある場合、リクエストのHost ヘッダとserver_nameディレクティブが一致するServerコンテキストが選ばれるが、一致しない場合は、default_serverオプションが付いたServerコンテキストか、設定ファイル内で最初にIPとポート番号に一致したlistenディレクティブを持つServerコンテキストが選ばれる。

そのため明示的に想定外のアクセスを処理するためのServerコンテキストを設定するためにdefault_serverを指定し、server_nameには"_"(アンダースコア)を指定する。"_" を指定することですべての名前に対応する。

ただしこのままだとhttps経由でのアクセスには対応できないので
以下のようにオレオレ証明書を用いた以下の設定をすれば良さそうだったが、

server {
   listen       80  default_server;
   listen       443 ssl default_server;
   server_name  _;
   ssl_certificate         /usr/local/etc/ssl/selfcert.crt;
   ssl_certificate_key     /usr/local/etc/ssl/selfcert.key;
   return 444;
}

自分の場合は、どうやってもうまくできなかったので
最終的にhttps経由でのアクセス対策は以下の方法で対応した。

server {
    listen       80  default_server;
    server_name  _;
    return       444;
}

server {
    listen 443;
    server_name example.com;

    if ($host !~* "example.com") {
        return 444;
    }
    ...
}

[参考]
nginx連載4回目: nginxの設定、その2 - バーチャルサーバの設定 - インフラエンジニアway - Powered by HEARTBEATS
Nginx で http も https も IP 直打ちのアクセスを弾きたい - べにやまぶろぐ
Nginxで「default_server」を指定して想定外のアクセスを遮断する方法 | 4thsight.xyz
nginxの設定 その2 - bnote
Nginxで443ポートにデフォルトサーバーを指定する | Junk Works
Nginx: Block Direct IP Access
nginx - Block direct access to webserver IP via HTTPS - Server Fault
ssl - Properly setting up a "default" nginx server for https - Server Fault

【Nginx】同一サーバで複数サイトを運営し、ログをサイト毎に分ける

自分用メモ。

access_logとerror_logはserverコンテキスト内に以下のように記述

access_log   /var/log/nginx/{service_domain}.access.log warn;
error_log   /var/log/nginx/{service_domain}.error.log;

サイト毎に新たにディレクトリを作成するのではなく、
あくまでもnginxのログはすべて/var/log/nginx内で管理する。
こうすることで、/etc/logrotate.d/nginxのデフォルトである「/var/log/nginx/*.log」の設定がそのまま使用できる。

上記の記述をサイト毎に記述し、nginxを再起動すると記述した通りの{service_domain}.access.logと{service_domain}.error.logができるが、これらのファイルの所有権とグループがroot:rootで作成されてしまう。

この記事を見ると、バグ?みたいな感じで書いてあるが詳細は不明。
centos 7 - Nginx creates log files owned by root instead of specified user - Super User

ただ以下のコマンドで、ログを再読込してあげるとnginx.confのuserディレクティブで指定したユーザが所有者になる。ただしグループはrootのまま。

$ nginx -s reopen

なので、結局はchownコマンドで直してあげるしかないのか...