ノンカフェインであなたにやさしい

Ruby,Rails,HTML,CSS,Reactなど

RailsインスパイアのReactJsフレームワーク Blitzを試した

Blitzとは?

GitHubの説明をGoogle翻訳を通した引用…

Blitzは、Ruby on Railsのようなサーバーレンダリングフレームワークのシンプルさと慣習を復活させ、 Reactとクライアントサイドレンダリングについて私たちが愛するすべてを維持します!

github.com

つまりRailsっぽくてクールなNextJs!!!(?)

Blitzでアプリケーションを作る

公式ドキュメントを参考に進める
form libraryは React Final Form (recommended) を選びました

$ npm install -g blitz
$ blitz new blitzTestApp
You are using alpha software - if you have any problems, please open an issue here:
      https://github.com/blitz-js/blitz/issues/new/choose

? Pick a form library (you can switch to something else later if you want) …
▸ React Final Form (recommended)
  React Hook Form
  Formik

✔ Pick a form library (you can switch to something else later if you want) · React Final Form

Hang tight while we set up your new Blitz app!

CREATE    .env
CREATE    .env.local
CREATE    .env.test.local
CREATE    .eslintrc.js
CREATE    .npmrc
CREATE    .prettierignore
CREATE    README.md
CREATE    app/auth/auth-utils.ts
CREATE    app/auth/components/LoginForm.tsx
CREATE    app/auth/components/SignupForm.tsx
CREATE    app/auth/mutations/login.ts
CREATE    app/auth/mutations/logout.ts
CREATE    app/auth/mutations/signup.ts
CREATE    app/auth/pages/login.tsx
CREATE    app/auth/pages/signup.tsx
CREATE    app/auth/validations.ts
CREATE    app/components/.keep
CREATE    app/hooks/useCurrentUser.ts
CREATE    app/layouts/.keep
CREATE    app/layouts/Layout.tsx
CREATE    app/pages/404.tsx
CREATE    app/pages/_app.tsx
CREATE    app/pages/_document.tsx
CREATE    app/pages/index.test.tsx
CREATE    app/pages/index.tsx
CREATE    app/users/queries/getCurrentUser.ts
CREATE    babel.config.js
CREATE    blitz.config.js
CREATE    db/index.ts
CREATE    db/migrations/.keep
CREATE    db/schema.prisma
CREATE    db/seeds.ts
CREATE    integrations/.keep
CREATE    jest.config.js
CREATE    package.json
CREATE    public/favicon.ico
CREATE    public/logo.png
CREATE    test/.keep
CREATE    test/__mocks__/fileMock.js
CREATE    test/setup.ts
CREATE    test/utils.tsx
CREATE    tsconfig.json
CREATE    types.ts
CREATE    utils/.keep
CREATE    .gitignore
CREATE    app/components/Form.tsx
CREATE    app/components/LabeledTextField.tsx

✔ Retrieving the freshest of dependencies
✔ Resolving packages
✔ Fetching packages
✔ Linking dependencies
✔ Building fresh packages
✔ Initializing SQLite database
✔ Committing your app

Your new Blitz app is ready! Next steps:

   1. cd blitzTestApp
   2. blitz start
$ cd blitzTestApp/
~/work/node/blitzTestApp (master)
$ blitz start
You are using alpha software - if you have any problems, please open an issue here:
      https://github.com/blitz-js/blitz/issues/new/choose

> ⚠️  Git config core.excludesFile is unset. Inferring .gitignore file locations.
✔ Prepped for launch
Loaded env from /home/akinov/work/node/blitzTestApp/.blitz/caches/dev/.env
warn  - You have enabled experimental feature(s).
warn  - Experimental features are not covered by semver, and may cause unexpected or broken application behavior. Use them at your own risk.

ready - started server on http://localhost:3000
info  - Using external babel configuration from /home/akinov/work/node/blitzTestApp/.blitz/caches/dev/babel.config.js

localhost:3000 にアクセスすると最初のページが表示されました
\Hello Wold/

f:id:kuronekopunk:20201212205226p:plain

migrationをしてみる

最初のページに書いてあるとおり、ページを生成、DBのmigrateをしてみる
構文などはほぼRailsである

$ blitz generate all project name:string
You are using alpha software - if you have any problems, please open an issue here:
      https://github.com/blitz-js/blitz/issues/new/choose

✔ Model for 'project' created successfully:

> model Project {
>   id        Int      @default(autoincrement()) @id
>   createdAt DateTime @default(now())
>   updatedAt DateTime @updatedAt
>   name      String
> }

Now run blitz db migrate to add this model to your database

CREATE    app/projects/pages/projects/[projectId]/edit.tsx
CREATE    app/projects/pages/projects/[projectId].tsx
CREATE    app/projects/pages/projects/index.tsx
CREATE    app/projects/pages/projects/new.tsx
CREATE    app/projects/components/ProjectForm.tsx
CREATE    app/projects/queries/getProject.ts
CREATE    app/projects/queries/getProjects.ts
CREATE    app/projects/mutations/createProject.ts
CREATE    app/projects/mutations/deleteProject.ts
CREATE    app/projects/mutations/updateProject.ts

~/work/node/blitzTestApp (master)
$ blitz db migrate
You are using alpha software - if you have any problems, please open an issue here:
      https://github.com/blitz-js/blitz/issues/new/choose

Environment variables loaded from /home/akinov/work/node/blitzTestApp/.env
Prisma schema loaded from db/schema.prisma
✔ Name of migration … y
📼  migrate save --name y

Local datamodel Changes:

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

// --------------------------------------

model Project {
  id Int @default(autoincrement()) @id
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  name String
}

Prisma Migrate just created your migration 20201212115831-y in

migrations/
  └─ 20201212115831-y/
    └─ steps.json
    └─ schema.prisma
    └─ README.md

Run prisma migrate up --experimental to apply the migration

Environment variables loaded from /home/akinov/work/node/blitzTestApp/.env
Prisma schema loaded from db/schema.prisma
🏋️<200d>  migrate up

Changes to be applied:

// This is your Prisma schema file,
// learn more about it in the docs: https://pris.ly/d/prisma-schema

// --------------------------------------

model Project {
  id Int @default(autoincrement()) @id
  createdAt DateTime @default(now())
  updatedAt DateTime @updatedAt
  name String
}

Checking the datasource for potential data loss...

Database Changes:

Migration         Database actions             Status

20201212115831-y  1 CreateTable statements.    Done 🚀

You can get the detailed db changes with prisma migrate up --experimental --verbose
Or read about them here:
      ./migrations/20201212115831-y/README.md


🚀    Done with 1 migration in 128ms.

Environment variables loaded from /home/akinov/work/node/blitzTestApp/.env
Prisma schema loaded from db/schema.prisma

✔ Generated Prisma Client (2.12.1) to ./node_modules/@prisma/client in 60ms
You can now start using Prisma Client in your code. Reference: https://pris.ly/d/client

import { PrismaClient } from '@prisma/client' const prisma = new PrismaClient()

warn Prisma 2.12.0 has breaking changes.
You can update your code with npx @prisma/codemods update-2.12 ./
Read more at https://pris.ly/2.12

このままだとProjectの登録ができないので公式チュートリアルを参考にフォームを動くようにする

blitzjs.com

公式のフォームデータのとり方が配列のindex指定なの全然参考にならなかった。。。

event.target[0].value

他サイトだと document.getElementById を使ってるものもあったりとキレイでベターなやり方が見つからなかった。
ReactJsなのでFormコンポーネント内でstateを持つのが良さそうだと思う。
event.target はHTMLElementなのでquerySelectorなどで取得も可能だった

event.target.querySelector('[name=name]').value

よく使うRails 6.1で生成ファイルを最小限にするrails newコマンド

環境

Ruby 2.7.2
Rails 6.1.0

最小限の rails new

rails new --minimal -S -J -T --database=postgresql TestApp

--minimal

以下のフレームワークがスキップされる

  • action_cable
  • action_mailbox
  • action_mailer
  • action_text
  • active_job
  • active_storage
  • bootsnap
  • jbuilder
  • spring
  • system_tests
  • turbolinks
  • webpack

-S -J -T オプション

minimalと重複するものもありますが以下

  -S, [--skip-sprockets], [--no-skip-sprockets]              # Skip Sprockets files
      [--skip-spring], [--no-skip-spring]                    # Don't install Spring application preloader
      [--skip-listen], [--no-skip-listen]                    # Don't generate configuration that depends on the listen gem
  -J, [--skip-javascript], [--no-skip-javascript]            # Skip JavaScript files
      [--skip-turbolinks], [--no-skip-turbolinks]            # Skip turbolinks gem
      [--skip-jbuilder], [--no-skip-jbuilder]                # Skip jbuilder gem
  -T, [--skip-test], [--no-skip-test]                        # Skip test files
      [--skip-system-test], [--no-skip-system-test]          # Skip system test files
      [--skip-bootsnap], [--no-skip-bootsnap]                # Skip bootsnap gem

その他オプション

rails new -h で詳細を確認できます

$ rails new -h
Usage:
  rails new APP_PATH [options]

Options:
      [--skip-namespace], [--no-skip-namespace]              # Skip namespace (affects only isolated engines)
      [--skip-collision-check], [--no-skip-collision-check]  # Skip collision check
  -r, [--ruby=PATH]                                          # Path to the Ruby binary of your choice
                                                             # Default: /home/akinov/.rbenv/versions/2.7.2/bin/ruby
  -m, [--template=TEMPLATE]                                  # Path to some application template (can be a filesystem path or URL)
  -d, [--database=DATABASE]                                  # Preconfigure for selected database (options: mysql/postgresql/sqlite3/oracle/sqlserver/jdbcmysql/jdbcsqlite3/jdbcpostgresql/jdbc)
                                                             # Default: sqlite3
      [--skip-gemfile], [--no-skip-gemfile]                  # Don't create a Gemfile
  -G, [--skip-git], [--no-skip-git]                          # Skip .gitignore file
      [--skip-keeps], [--no-skip-keeps]                      # Skip source control .keep files
  -M, [--skip-action-mailer], [--no-skip-action-mailer]      # Skip Action Mailer files
      [--skip-action-mailbox], [--no-skip-action-mailbox]    # Skip Action Mailbox gem
      [--skip-action-text], [--no-skip-action-text]          # Skip Action Text gem
  -O, [--skip-active-record], [--no-skip-active-record]      # Skip Active Record files
      [--skip-active-job], [--no-skip-active-job]            # Skip Active Job
      [--skip-active-storage], [--no-skip-active-storage]    # Skip Active Storage files
  -P, [--skip-puma], [--no-skip-puma]                        # Skip Puma related files
  -C, [--skip-action-cable], [--no-skip-action-cable]        # Skip Action Cable files
  -S, [--skip-sprockets], [--no-skip-sprockets]              # Skip Sprockets files
      [--skip-spring], [--no-skip-spring]                    # Don't install Spring application preloader
      [--skip-listen], [--no-skip-listen]                    # Don't generate configuration that depends on the listen gem
  -J, [--skip-javascript], [--no-skip-javascript]            # Skip JavaScript files
      [--skip-turbolinks], [--no-skip-turbolinks]            # Skip turbolinks gem
      [--skip-jbuilder], [--no-skip-jbuilder]                # Skip jbuilder gem
  -T, [--skip-test], [--no-skip-test]                        # Skip test files
      [--skip-system-test], [--no-skip-system-test]          # Skip system test files
      [--skip-bootsnap], [--no-skip-bootsnap]                # Skip bootsnap gem
      [--dev], [--no-dev]                                    # Set up the application with Gemfile pointing to your Rails checkout
      [--edge], [--no-edge]                                  # Set up the application with Gemfile pointing to Rails repository
      [--master], [--no-master]                              # Set up the application with Gemfile pointing to Rails repository master branch
      [--rc=RC]                                              # Path to file containing extra configuration options for rails command
      [--no-rc], [--no-no-rc]                                # Skip loading of extra configuration options from .railsrc file
      [--api], [--no-api]                                    # Preconfigure smaller stack for API only apps
      [--minimal], [--no-minimal]                            # Preconfigure a minimal rails app
  -B, [--skip-bundle], [--no-skip-bundle]                    # Don't run bundle install
  --webpacker, [--webpack=WEBPACK]                           # Preconfigure Webpack with a particular framework (options: react, vue, angular, elm, stimulus)
      [--skip-webpack-install], [--no-skip-webpack-install]  # Don't run Webpack install

Runtime options:
  -f, [--force]                    # Overwrite files that already exist
  -p, [--pretend], [--no-pretend]  # Run but do not make any changes
  -q, [--quiet], [--no-quiet]      # Suppress status output
  -s, [--skip], [--no-skip]        # Skip files that already exist

Rails options:
  -h, [--help], [--no-help]        # Show this help message and quit
  -v, [--version], [--no-version]  # Show Rails version number and quit

Description:
    The 'rails new' command creates a new Rails application with a default
    directory structure and configuration at the path you specify.

    You can specify extra command-line arguments to be used every time
    'rails new' runs in the .railsrc configuration file in your home directory,
    or in $XDG_CONFIG_HOME/rails/railsrc if XDG_CONFIG_HOME is set.

    Note that the arguments specified in the .railsrc file don't affect the
    defaults values shown above in this help message.

Example:
    rails new ~/Code/Ruby/weblog

    This generates a skeletal Rails installation in ~/Code/Ruby/weblog.

レスポンシブサイトでlazysizesを使い画像遅延読み込みをした時のCore Web Vitals CLS対策

Core Web Vitalsの値、気にしてますか? レスポンシブでCLS対策をする時の対応を書きます。

CLSとは?

Cumulative Layout Shift は、ページがどのくらい安定しているように感じられるかを表します。視覚的な安定性を測定し、表示されるページ コンテンツにおける予期しないレイアウトのずれの量を定量化します。

developers-jp.googleblog.com

画像の読み込みや、コンテンツの遅延読み込みなどでサイトの要素がズレる量のことです。 基本的には画像サイズを指定してあげることでズレはなくなります。

画像遅延読み込みとの兼ね合い

lazysizesというプラグインを使い画像遅延読み込みをしていますが、読み込まれるまで1x1pxの透過画像を置いておくのがスタンダードです。

<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="本来の画像URL" class="lazyload" width="200" height="100">

github.com

レスポンシブで1x1px透過画像を先読みする場合の不具合

レスポンシブにしたいと、画像を width: 100%; height: auto; にすると
読込中 1x1px 画像のアスペクト比を保持して横100%になってしまいます。

読み込まれるまで高さがwidthと同じになってしまう
<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="本来の画像URL" class="lazyload" width="200" height="100">

<style>
  img {
    width: 100%;
    height: auto;
  }
</style>

サンプル レスポンシブサイトでlazysizesを使い画像遅延読み込みをした時のCore Web Vitals CLS対策 サンプル

このサンプルでは1枚目の画像も 1:1 の高さを保持してしまっているため画像読み込み後にズレが生じてCLSが0.095になっています。
※サンプルなのでそこまで悪い数字ではないですが f:id:kuronekopunk:20201211231400p:plain

対策

  • imgタグのwidth, heightは幅320pxの時のアスペクト比で入れる
  • height: auto; はlazyloadが完了してから設定する

下記のようになります。

<img src="data:image/gif;base64,R0lGODlhAQABAAAAACH5BAEKAAEALAAAAAABAAEAAAICTAEAOw==" data-src="本来の画像URL" class="lazyload" width="320" height="160">

<style>
  img {
    width: 100%;
  }
  /* lazyload完了後に付与されるクラス */
  img.lazyloaded {
    height: auto;
  }
</style>

サンプル レスポンシブサイトでlazysizesを使い画像遅延読み込みをした時のCore Web Vitals CLS対策 サンプル

CLSが0.009になりました。

f:id:kuronekopunk:20201211231454p:plain

注意

imgタグのwidth, heightは幅320pxの時のアスペクト比で入れる

というのはLighthouseのmobileで計測する時のブラウザ幅です。
違うブラウザ幅だとCLSのガタつきが発生するためユーザーにとって最適とは言えません。
事前にアスペクト比が分かっているならpadding-topを%で指定して先にサイズを確保しておくなどありますが、運用面でコストが高くなってしまいます。
ケースに合った対応を心がけましょう。

WSLでChromedriverを使えるようにする

chromedriverのDL

公式サイトから必要なバージョンをDLします。

f:id:kuronekopunk:20201129142705p:plain

DL後、zipを解凍したらWindowsTerminalでWSLの /bin/ に移動

# CドライブのDownloadsにchromedriverがある
sudo mv chromedriver /bin/cromedriver
# 実行権限の付与
sudo chown 755 /bin/chromedriver

f:id:kuronekopunk:20201129142903p:plain

chromedriver のバージョンを確認

$ chromedriver -v
ChromeDriver 86.0.4240.22 (398b0743353ff36fb1b82468f63a3a93b4e2e89e-refs/branch-heads/4240@{#378})

参考

WSL上でRspecのSystem Specを使った時のエラー - Qiita

「Selenium::WebDriver::Error::WebDriverError: unable to connect to chromedriver 127.0.0.1:9515」または「Selenium::WebDriver::Error::UnknownError: unknown error: cannot find Chrome binary」のエラーに対応する - Qiita

WindowsのLocal by Flywheelで作ったWordPressにシンボリックリンクを貼り別ディレクトリのthemesデータを同期させる

新規でWP環境を作るだけならLocalをインストールするだけなのですがすでにあるプロジェクトのthemesだけを同期させたいため特殊な対応をしました。

まずは公式ドキュメント通りLocalのインストール、WPの作成をします。 localwp.com

themesを同期させる

昔のLocalだとvolumesという設定でファイル同期ができましたが今はシンボリックリンクを貼る必要があるよう

[WordPress] ”Local by Flywheel”でシンボリックリンクを作成する方法

Windows PowerShellを管理者で起動しシンボリックリンクを貼ります

# ローカルにある参照したいthemes
# "C:\Users\user_name\workspace\wordpress\wp-content\themes\"

# LocalでインストールしたWPのディレクトリ
# "C:\Users\user_name\Local Sites\nisso\app\public"
New-Item -Value "C:\Users\user_name\workspace\wordpress\wp-content\themes\" -Path "C:\Users\user_name\Local Sites\nisso\app\public\themes" -ItemType SymbolicLink

※既にインストールしたWPのthemesがある場合は削除しておく必要があります。

エクスプローラーでシンボリックリンクがあるのを確認 f:id:kuronekopunk:20201127174455p:plain