とーますメモ

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

【React】Material UIについてのメモ書き

Material UI学習時のメモ書き

Gridシステム

bootstrapを使用するときも同じだが、まずは基本のGridシステムの使い方を最初に知る必要がある。

Gridは親Gridでcontainerを書き、その内側の子Gridでitemを定義する。
boostrapでいう、div class='container'とdiv class='row'と同じ関係。

<Grid container spacing={2}>>
  <Grid item xs={6} md={8}>
    <Item>xs=6 md=8</Item>
  </Grid>
  <Grid item xs={6} md={4}>
    <Item>xs=6 md=4</Item>
  </Grid>
  <Grid item xs={6} md={4}>
    <Item>xs=6 md=4</Item>
  </Grid>
  <Grid item xs={6} md={8}>
    <Item>xs=6 md=8</Item>
  </Grid>
</Grid>

レスポンシブデザインは、boostrapと同じように、breakpointがあり内容は以下。

xs, extra-small: 0px
sm, small: 600px
md, medium: 900px
lg, large: 1200px
xl, extra-large: 1536px

Breakpoints - Material UI
モバイルベースのxsベースで考えて、必要に応じてmdやlgを使う。

Auto-layoutという機能もあり、12の数値を全て、各rowに割り振るのではなく、
その一部に当てはめればあとは、使用可能ならスペースに応じて、均等に割り振ったwidthでレイアウトしてくれる。

<Grid container spacing={3}>
  <Grid item xs>
    <Item>xs</Item>
  </Grid>
  <Grid item xs={6}>
    <Item>xs=6</Item>
  </Grid>
  <Grid item xs>
    <Item>xs</Item>
  </Grid>
</Grid>

Grid container(親Grid)でよく使用する属性

direction

子Gridの並び順を定義できる。rowで横並び、columnで縦並び

<Grid container direction="row">
justifyContent

親Gridをメイン軸とし、子Gridを横軸のどの位置に配置するかを指定する
【CSS】justify-content使い方、アイテムの配置する位置を指定する | SHU BLOG

<Grid container justifyContent="flex-start"> // 先頭寄せ
<Grid container justifyContent="center"> // 中央寄せ
<Grid container justifyContent="flex-end"> // 末尾寄せ
alignItems

親Gridをメイン軸とし、子Gridを縦軸のどの位置に配置するかを指定する
【CSS】align-itemsの使い方、配置する方向を指定する! | SHU BLOG

<Grid container alignItems="flex-start"> // 上部寄せ
<Grid container alignItems="center"> // 中央寄せ
<Grid container alignItems="flex-end"> // 下部寄せ
spacing

子Grid間のスペースを設定できる。小数点を含めた正の数を指定できる。
またv5からspacingを含めた全てのproprsでレスポンシブ値をサポート

<Grid container spacing={{ xs: 2, md: 3 }} />
rowSpacingとcolumnSpacing

rowSpacing(縦)とcolumnSpacing(横)の間隔をサポート

<Grid container rowSpacing={1} columnSpacing={{ xs: 1, sm: 2, md: 3 }}>
columns

デフォルトのカラム数である12を変更することができる。
細かいレイアウト表現が必要な時に便利そう。

<Grid container spacing={2} columns={16}>
  <Grid item xs={8}>
    <Item>xs=8</Item>
  </Grid>
  <Grid item xs={8}>
    <Item>xs=8</Item>
  </Grid>
</Grid>

sxを使ったスタイルの当て方

こんにちはMUI! 新しくなったMaterial UI v5

追記

V5でできるようになったこと。

こんにちはMUI! 新しくなったMaterial UI v5

TypeScript 4.5 ファーストインプレッション

個人用メモ。解釈が正しいかは不明なので参考までに。

TypeScript4.5がリリースされたので、その内容を簡単に試してみる。
devblogs.microsoft.com

TypeScriptを既にインストールしている場合は、以下で最新版に更新。

$ npm update typescript

初めてインストールする場合は以下。

$ npm install typescript

公式によるとTypeScript4.5の主な追加項目は以下。

The Awaited Type and Promise Improvements

The Awaited type can be helpful for modeling existing APIs, including JavaScript built-ins like Promise.all, Promise.race, etc. In fact, some of the problems around inference with Promise.all served as motivations for Awaited.

https://devblogs.microsoft.com/typescript/announcing-typescript-4-5/#awaited-type

よくわからん。何が便利になるのかも不明。

=> PromiseLikeの説明
thenが実装しているPromise風オブジェクトのこと?

const fakePromise = { then: () => string };

async/await がやっていること - Qiita
JavaScriptの非同期処理をじっくり理解する (2) Promise

Supporting lib from node_modules

TypeScript does bundle certain libraries to ensure it works together well with Javascript. However, you might want to change those to another type of library implementation.

It is a similar behavior as of @types where you can now choose your appropriate type definitions.

https://betterprogramming.pub/whats-new-in-typescript-4-5-57d6b88b1e72

TypeScriptにバンドルされているライブラリの型定義ファイルを
指定することができるようになるため、適切な型定義ファイルを使用できるようになる?みたい。

TypeScript 4.5 変更点 まとめ

Template String Types as Discriminants

https://devblogs.microsoft.com/typescript/announcing-typescript-4-5/#template-string-discriminants

以下のような、テンプレートリテラルの使い方ができるようになった。4.4以下では失敗する。

export interface Success {
    type: `${string}Success`;
    body: string;
}

export interface Error {
    type: `${string}Error`;
    message: string;
}

export function handler(r: Success | Error) {
    if (r.type === "HttpSuccess") {
        // 'r' has type 'Success'
        let token = r.body;
    }
}

--module es2022

https://devblogs.microsoft.com/typescript/announcing-typescript-4-5/#module-es2022

TypeScriptでes2022モジュールをサポートできるようになった。
一番重要だと思われる機能は、awaitをasync関数外でも使用できるようになること。

Tail-Recursion Elimination on Conditional Types

Conditional Typesで型レベル末尾再帰最適化を行うらしい。

TypeScript 4.5 変更点 まとめ

よくわからん。飛ばす...

Disabling Import Elision

特定の条件下の元で、importしたモジュールを使用している場合、TypeScriptはそのモジュールを未定義と判断し削除するのを防ぐオプション。

以下のようなケースが想定される。

import { Animal } from "./animal.js";
eval("console.log(new Animal().isDangerous())");

Announcing TypeScript 4.5 - TypeScript

import { readFile } from "node:fs/promises";
eval(`readFile("./package.json", "utf-8").then(console.log);`);

TypeScript 4.5 変更点 まとめ

type Modifiers on Import Names

今まではtype修飾子をimport文で使用するときは、モジュールのimportととは分けて記述する必要があったが、4.5からは一緒にかけるようになった。

import type { FC } from 'react';
import { useEffect } from 'react';
import { type FC, useEffect } from 'react';

Private Field Presence Checks

プライベートプロパティの存在チェック。ユースケースがよくわからないが、
このチェックを使用することで、あるインスタンスが、どのクラスから生成されたかを証明することができるようになるということだと思う。
TypeScript 4.5 変更点 まとめ

Import Assertions

ランタイム実行時に、インポートする対象が想定したフォーマットになっているかチェックすることができる。この機能は、どうやらJSONなどのコードを実行する機能がないファイルをインポートする場合は、明示的にフォーマットを指定させることでセキュリティを向上させる狙いがあるっぽい。
GitHub - tc39/proposal-import-assertions: Proposal for syntax to import ES modules with assertions

Const Assertions and Default Type Arguments in JSDoc

一例として、as constを使用せずにJSDocのアサーションを使用することで同じ表現が可能になった?的なことかと。

Faster Load Time with realPathSync.native

内部的な話っぽいので、スキップ。

New Snippet Completions

補完機能が強化された模様。読む限り良さげな改善内容。
新しいVSCode上で動作するとのことだが、自分の環境では確認できず...

Better Editor Support for Unresolved Types

特定のケースにおいて、関数名をマウスオーバー時に表示されるコンテキスト情報が改善された模様。

Experimental Nightly-Only ECMAScript Module Support in Node.js

実験的な機能についての言及。よくわからない。


[参考資料]
TypeScript 4.5 変更点 まとめ
What’s New in TypeScript 4.5?. Awaited Type, type-only modifier… | by Jose Granja | Nov, 2021 | Better Programming

【Ruby】[2021版] MacでRailsが突然動かなくなった話

以前やらかしたことを、またやらかしてしまったので、
再度動作できるようにするまでのメモ。
thoames.hatenadiary.jp

TL;DR

opensslが1.1系に書き換わってる可能性大!!!!
なので以下のことをすれば直った。
1) openssl1.0をインストール
2) /usr/local/opt/opensslのシンボリックリンクを1)でインストールしたパスに貼る。
3) brew switch openssl1.0のパスを直接していする。

経緯

原因は恐らく今度もXcode関係かbrew関係のコマンドを弄ったかが原因だと思われる。
Railsを起動しようとしたら、以下のエラーが出たため
他のサイトに書いてあるとおりに、一度消して再インストールするという同じ過ちを犯してしまった。

$ bundle exec rails s

...
LoadError - library not found for class Digest::SHA1 -- digest/sha1
...

今後は、Rails関係でサーバが立ち上がらないときは、必ず自分のメモを見るように肝に命じておきたい...

自分の場合は/usr/local/opt/opensslのシンボリックリンクが、openssl@1.1を向いていたので
これを古いバージョン(以前使用していたのは1.0.2q)へ向け直す必要があったので、brew switchと組み合わせて以下のようなコマンドで、なんとか2.3.1がインストールできた。

ちなみに古いバージョンのopensslは「/usr/local/Cellar/openssl」に入っている。

$ brew switch openssl 1.0.2q
$ RUBY_CONFIGURE_OPTS="--with-openssl-dir=/usr/local/opt/openssl" rbenv install 2.3.1
$ rbenv rehash
$ rbenv global 2.3.1
$ ruby -v
ruby 2.3.1p112 (2016-04-26 revision 54768) [x86_64-darwin18]

以前は上記での対応で良かったが、今回はなんと
「/usr/local/opt/openssl」のシンボリックリンクもなくなっており、
旧バージョンの「/usr/local/Cellar/openssl」もきれいに無くなっていた。
おいぃいいいい!!!どうなってる!!!!!!

以下のことをやったら直ったのでメモ

Openssl1.0のインストール

1.0系がきれいに消えているので再インストール

$ brew install rbenv/tap/openssl@1.0

インストールすると、「/usr/local/Cellar/openssl@1.0/1.0.2t」にインストールされる。

シンボリックの向きを1.0に向ける。

opensslのシンボリックリンクが消えていたので、1.0に向けて貼り直す。

$ cd /usr/local/opt
$ ln -s ../Cellar/openssl@1.0/1.0.2t openssl

brew switchコマンドで、openssl1.0に向きを変える

$ brew switch openssl /usr/local/Cellar/openssl@1.0/1.0.2t

あとは、前の記事と同じようにRuby, bundler, mysqlをインストールし直した。
これで動作した。

[参考]
brew upgradeしたらopensslが1.1.1gになってしまいRailsが起動できなくなってしまったとき - Qiita

【Next.js】Material UIをSSRで使う方法

何も考えずにNext.jsでMaterial UIを使おうとすると以下のエラーが出ます。

Warning: Prop 'className' did not match. Server ...

Material UIではSSRへの対応方法が準備されており、以下がそのサンプルです。
material-ui/examples/ssr at master · mui-org/material-ui · GitHub

上記のサンプルコードを初見で見て思ったのが、どこがポイントなのよ〜ってこと。
余計なコードがいろいろはいってて、どこがポイントなのか初心者にはわかりにくいです。

色々検証してわかったのは、以下のコードを追加すれば直るってこと。

_app.tsx: useEffectのところのみ必要。

import React from 'react';

export default function MyApp({ Component, pageProps }: AppProps) {
  React.useEffect(() => {
    // Remove the server-side injected CSS.
    const jssStyles = document.querySelector('#jss-server-side');
    if (jssStyles) {
      jssStyles.parentElement!.removeChild(jssStyles);
    }
  }, []);
  ....
  return <Component {...pageProps} />;
}

_document.tsx
ServerStyleSheetsをインポートする箇所と、
MyDocument.getInitialPropsを入れればOK

import { ServerStyleSheets } from '@material-ui/core/styles';
...
...
// `getInitialProps` belongs to `_document` (instead of `_app`),
// it's compatible with server-side generation (SSG).
MyDocument.getInitialProps = async (ctx) => {
  // Resolution order
  //
  // On the server:
  // 1. app.getInitialProps
  // 2. page.getInitialProps
  // 3. document.getInitialProps
  // 4. app.render
  // 5. page.render
  // 6. document.render
  //
  // On the server with error:
  // 1. document.getInitialProps
  // 2. app.render
  // 3. page.render
  // 4. document.render
  //
  // On the client
  // 1. app.getInitialProps
  // 2. page.getInitialProps
  // 3. app.render
  // 4. page.render

  // Render app and page and get the context of the page with collected side effects.
  const sheets = new ServerStyleSheets();
  const originalRenderPage = ctx.renderPage;

  ctx.renderPage = () =>
    originalRenderPage({
      enhanceApp: (App) => (props) => sheets.collect(<App {...props} />),
    });

  const initialProps = await Document.getInitialProps(ctx);

  return {
    ...initialProps,
    // Styles fragment is rendered after the app and page rendering finish.
    styles: [...React.Children.toArray(initialProps.styles), sheets.getStyleElement()],
  };
};

ただ自分の場合、next.config.jsでreactStrictMode: trueをしてたためエラーがで出続けていました。これがわかるまでに結構大変でした。
潜在的な問題点を洗い出すためにtureにしたほうが良いようなのですが
Material UIと一緒に使う場合は、無効にしたほうが良さそう。
Next.js 4年目の知見:SSRはもう古い、VercelにAPIサーバを置くな - Qiita

Material UI v5では直ってるっぽいので、もうちょっとreactStricModeを使うのは待つほうが良いかも...
[styles] Strict Mode support · Issue #18018 · mui-org/material-ui · GitHub

[参考]
Material-UIでNext.jsのポイントを紹介する|fumi|note
フロントエンド初学者がNext.js + Typescript + FireStore + Material-UI + SSGでサイト作るまでのメモ
【Next.js】Material-UI導入時に[Warning: Prop `className` did not match. ]が発生した場合の対処法 - Qiita
Server Rendering - Material-UI

【GraphQL】GraphQL Code Generatorについてのメモ

GraphQL Code Generatorとは、GraphQLのスキーマからTypeScriptの型定義ファイルを作成することができるツール。

テスト環境はNext.js + TypeScript + Apollo + GraphQL Code Generator + Hasuraの構成する。CSRでGraphQLリクエストはせず、SSRとSSG内でのみGraphQLリクエストを行う前提。

余計なプラグインは入れずに、最低限の設定でGraphQLへqueryとmutationを使用できる設定にする。

インストール

$ npm i -D graphql @graphql-codegen/cli @graphql-codegen/typescript @graphql-codegen/typescript-operations @graphql-codegen/typescript-document-nodes

参考: https://www.graphql-code-generator.com/docs/plugins/index

@graphql

=> (必須) GraphQLパッケージ(そもそもこれがないと動かない)

@graphql-codegen/cli

=> (必須) 本体 (型定義ファイルジェネレーター本体)

@graphql-codegen/typescript

=> (必須) TypeScriptの型定義ファイルを生成するのに必要

@graphql-codegen/typescript-operations

=> (必須) ユーザ定義したquery, mutation, subscription, fragmentの型定義ファイル生成

@graphql-codegen/typescript-document-nodes

=> (.graphql)ファイルから(.ts)ファイルを生成し、型定義ファイルに追加してくれる。
導入することで、以下のメリットがある
1) ApolloClientので呼び出すときに、逐一「gql'...'」をつけなくて良い。
2) 型定義ファイルにquery, mutation, subscription, fragmentが追加されるので、importが減りわかりやすい。

@graphql-codegen/fragment-matcher

=> GraphQLのinterfaceやunion(TypeScriptのinterfaceのことではない)を使用している場合に必要。使用する場合InMemoryCacheの引数を設定する必要あり?
@see: https://qiita.com/daiki7nohe/items/8a3d79d0bebf2166f32d

@graphql-codegen/typescript-graphql-files-modules

d.tsファイルを生成してくれる。パッケージ作成時に必要らしいが、パッケージを作成しないなら不要という認識

@graphql-codegen/typescript-react-apollo

=> useQueryのように使える独自ReactHooksを生成!内部でuseQueryやuseMutationを使用している。
@see: https://qiita.com/pure-adachi/items/f1e03941e8c0ac47c7ee
@see: https://developer.medley.jp/entry/2020/11/06/180208

@graphql-codegen/typescript-graphql-request

=> Apollo使わないでGraphQLリクエストするときは導入を考える。

備考: graphqlと@graphql-codegen/cliは、グローバルにインストールすることは非推奨にされている。
Installation

設定

codegen.yml内で環境変数を読み込む方法

Hasuraのエンドポイントとか、HASURA_GRAPHQL_ADMIN_SECRETなんかは、環境変数から読み込ませたい。そんなときは"-r dotenv/config"のオプションをつけて生成すればOK.

"scripts": {
  ...
  "codegen": "graphql-codegen -r dotenv/config"
  ...
}

ただしデフォルトだと.envからしか読み込まないので、.env.localなど他の環境変数ファイルから読み込ませたいときは以下のようにする。

"scripts": {
  ...
  "codegen": "DOTENV_CONFIG_PATH=./.env.local graphql-codegen -r dotenv/config"
  ...
}

[参考]
codegen.yml
Support multiple .env files. · Issue #4635 · dotansimha/graphql-code-generator · GitHub

=====================================

【VSCode】Apollo GraphQLをHasuraと組み合わせて使う方法

下記のページを参考に設定
Guides: Visual Studio Code Setup | Hasura GraphQL Docs

インストール

まずはVSCodeにプラグインのインストール
Apollo GraphQL - Visual Studio Marketplace

このプラグインを入れるとGraphQLにシンタックスハイライトがつき、GraphQL入力時に、補完が使えるようなるのでApollo + GraphQLを使うなら必須。

インストール後、apollo.config.jsをルートディレクトリに作成し、
自分の場合はHeroku上のHasuraのサーバを置いているので、以下のように設定する。

name: 任意の名前
url: HasuraのエンドポイントURL
x-hasura-admin-secret:
=> Heroku上のHasuraのアプリを選択 => Settings => Config Varsに
HASURA_GRAPHQL_ADMIN_SECRET: SECRET_KEY
と同じSECRET_KEYを入れる

(補足) HASURA_GRAPHQL_ADMIN_SECRETの設定の仕方
Run Hasura GraphQL engine on Heroku | Hasura GraphQL Docs

module.exports = {
  client: {
    service: {
      name: "<任意の名前>",
      url: "<HasuraのエンドポイントURL>",
      headers: {
        "x-hasura-admin-secret": "<SECRET_KEY>"
      }
    }
  }
};

VSCode上で、⌘ + Shift + Pで"Apollo: Reload Schema"を選択すれば設定が読み込まれるので、これでエラーが出なければ補完が効くようになる。

[参考]
Hasura Authentication Explained

【VSCode】Next.jsのコードをデバックする方法

Tl;dr

ルートディレクトリに.vscodeフォルダを作り、launch.jsonを以下の内容で作成する。

$ mkdir .vscode && cd .vscode
$ touch launch.json

launch.json

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Next: Node",
      "type": "node",
      "request": "attach",
      "skipFiles": ["<node_internals>/**"],
      "port": 9229
    },
    {
      "name": "Next: Chrome",
      "type": "chrome",
      "request": "launch",
      "url": "http://localhost:3001",
      "sourceMaps": true,
      "sourceMapPathOverrides": {
        "webpack://_N_E/*": "${webRoot}/*"
      },
      "port": 9222
    }
  ]
}

バックエンド用

SSRやSSGの関数内で使用するため。

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Next: Node",
      "type": "node",
      "request": "attach",
      "skipFiles": ["<node_internals>/**"],
      "port": 9229
    }
  ]
}

request: "launch"を設定している人も多いが、自分は既に起動しているプロセス上でデバックしたかったので、attachを選択。

クライアント用

まずはChrome用の拡張である「Debugger for Chrome」をインストール。
Debugger for Chrome - Visual Studio Marketplace

これをインストールすると、type: "chrome"でエラーが出なくなる。
またクライアント用でもrequest: "attach"ができるみたいだけど、よくうまく動作しなかったので、こちらはlaunchで設定。

{
  "version": "0.2.0",
  "configurations": [
    {
      "name": "Next: Chrome",
      "type": "chrome",
      "request": "launch",
      "url": "http://localhost:3001",
      "sourceMaps": true,
      "sourceMapPathOverrides": {
        "webpack://_N_E/*": "${webRoot}/*"
      },
      "port": 9222
    }
  ]
}

[参考]
VSCodeで便利にdebugする方法 | CYOKODOG