かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

Makefile で .env (環境変数)を読み込んで使いたい

make コマンドに .env にある環境変数を渡したい

include .env で読み込める

Makefileinclude .env を書くだけで .env 内の環境変数が使える

.env

SECRET_KEY=HoshimiyaIchigo

Makefile

include .env

test:
  echo ${SECRET_KEY}

👇

$ make test
echo HoshimiyaIchigo
HoshimiyaIchigo

₍ ᐢ. ̫ .ᐢ ₎👌 デキタ

include .env.local でも問題なく動作したので、いわゆる env ファイルの形式なら問題ないっぽい。便利!


[参考]

envん チャージ!!!!

JavaScript day.js, date-fns で実在する日付かどうか判定したい

Moment.js くんが卒業してからフロントエンドでの日付操作には day.js か date-fns を使っていました。
今回年・月・日が別々の select ボックスで日付を選択する UI があり 2月31日のような存在しない日付が選べてしまうので、存在しない日付を判定しようとして思ったより根が深かったのでメモ。

day.js, date-fns には存在しない日付を判定するメソッドがなかった

Moment.js くんの moment('DATE'). isValid() は存在しない日付をチェックできたのですが、day.js, date-fns の日付チェックのメソッドは完全に存在しない日付を判定できるわけではないようです。

moment.js は isValid() で日付の妥当性を判定できる

// moment.js
import moment from "moment";
const dateList = [
  '2021-04-30',
  '2021-04-31',
  '2021-04-32',
  '2021-02-30',
];

dateList.forEach((date) => {
  console.log(date, moment(date).isValid());
});
/*
2021-04-30, true
2021-04-31, false
2021-04-32, false
2021-02-30, false
*/

day.js, date-fns の isValid メソッドは日付の妥当性は判定しない

day.js

dayjs().isValid()

// day.js
import dayjs from "dayjs";
const dateList = [
  '2021-04-30',
  '2021-04-31',
  '2021-04-32',
  '2021-02-30',
];

dateList.forEach((date) => {
  console.log(date, dayjs(date).isValid());
});
/*
2021-04-30, true
2021-04-31, true
2021-04-32, false
2021-02-30, true
*/

cf. Validation · Day.js

date-fns

isValid(date)

// date-fns
import { isValid } from "date-fns";
const dateList = [
  '2021-04-30',
  '2021-04-31',
  '2021-04-32',
  '2021-02-30',
];

dateList.forEach((date) => {
  console.log(date, isValid(new Date(date)));
});
/*
2021-04-30, true
2021-04-31, true
2021-04-32, false
2021-02-30, true
*/

cf. date-fns - modern JavaScript date utility library

2021-04-32 は共に false になっていますが、2021-04-312021-02-30 といった実在しない日付が true になっています。なんでや!

day.js, date-fns は内部的に Date が使われているので Date の挙動が影響している

const dateList = [
  '2021-04-30',
  '2021-04-31',
  '2021-04-32',
  '2021-02-30',
];

dateList.forEach((date) => {
  console.log(date, new Date(date));
});
/*
2021-04-30, Fri Apr 30 2021 09:00:00 GMT+0900
2021-04-31, Sat May 01 2021 09:00:00 GMT+0900
2021-04-32, Invalid Date
2021-02-30, Tue Mar 02 2021 09:00:00 GMT+0900
*/

Date は 32日というどの月にも存在しない日を指定している日付は Invalid Date になりますが、4/31 や 2/30 といった日付は過ぎている日分翌月にずれる仕様となっているようです。

なので day.js, date-fns での isValid メソッドは Invalid Date になる日付以外は Date で日付になるので true になってしまうものと思われます。
しかし '2021-02-31' のような日付は存在しないので true になってしまうとちょっと困ります…

元の日付と文字列比較をすれば日付の妥当性を判定できる

実在しない日付は Date を通すと日付が変わってしまうので、これを逆手に取って元の日付と同じフォーマットで文字列比較をすれば実在しない日付の場合は一致しないので日付の妥当性を判別できそうです。

day.js, date-fns それぞれで日付を文字列にして比較判定する関数を作成します。(day.js, date-fns でフォーマットの指定方法が微妙に異なるのがちょい面倒です…)

day.js

isValidDate.ts

import dayjs from "dayjs";

export const isValidDate = (
  dateStr: string,
  format: string = "YYYY-MM-DD"
): boolean => {
  const formatDate = dayjs(dateStr, format).format(format);
  return dateStr === formatDate
};

app.ts

import { isValidDate } from './isValidDate'
const dateList = [
  '2021-04-30T00:00+0900',
  '2021-04-31T00:00+0900',
  '2021-04-32T00:00+0900',
  '2021-02-30T00:00+0900',
];

dateList.forEach((date) => {
  console.log(date, isValidDate(date, 'YYYY-MM-DDTHH:mmZZ'));
});
/*
2021-04-30T00:00+0900, true
2021-04-31T00:00+0900, false
2021-04-32T00:00+0900, false
2021-02-30T00:00+0900, false
*/

cf. String + Format · Day.js

意図したとおりに日付の妥当性が判定できました!

date-fns

date-fns も同じように判定する関数を作成できるが、Invalid Date を format しようとするとエラーになるので注意が必要です

isValidDate.ts

import { format as DateFormat } from "date-fns";

export const isValidDate = (
  dateStr: string,
  format: string = "yyyy-MM-dd"
): boolean => {
  const d = new Date(dateStr);
  try {
    const formatDate = DateFormat(d, format);
    return dateStr === formatDate;
  } catch (error) {
    return false;
  }
};

app.ts

import { isValidDate } from './isValidDate'
const dateList = [
  '2021-04-30T00:00+0900',
  '2021-04-31T00:00+0900',
  '2021-04-32T00:00+0900',
  '2021-02-30T00:00+0900',
];

dateList.forEach((date) => {
  console.log(date, isValidDate(date, "yyyy-MM-dd'T'HH:mmxxxx"));
});
/*
2021-04-30T00:00+0900, true
2021-04-31T00:00+0900, false
2021-04-32T00:00+0900, false
2021-02-30T00:00+0900, false
*/

cf. date-fns - modern JavaScript date utility library

こちらも日付の妥当性が判定できました!

動作サンプル

所感

day.js, date-fns には isValid 関数が合ったので日付の妥当性が判定できるものだと思っていたのですが、予期しない挙動でびっくりしました。共に大元の Date の挙動だと分かったのですが、どうしてこんな挙動に…と思うばかりです。
他にも JavaScriptDate には不思議な挙動が多いので JavaScript での日付の操作はかなり注意するか極力行わないようにするのが良いのではないかと思いました。

Date の不思議な挙動の例

YYYY-MM-DD を渡すと UTC 00:00:00 時になるが、それ以外は locale での 00:00:00 時になる

new Date('2021-12-10');
// Fri Dec 10 2021 09:00:00 GMT+0900
new Date('2021/12/10');
// Fri Dec 10 2021 00:00:00 GMT+0900
new Date(2021, 11, 10);
// Fri Dec 10 2021 00:00:00 GMT+0900

[参考]

カレンダーの操作難しいね!

React TypeScript で作ったアプリがビルドできないにハマる

npx create-react-app --template typescript で作成した TypeScript の React アプリでビルド時に初めて出会うエラーになってしまったのでメモ

  • "react": "^17.0.2",
  • "react-dom": "^17.0.2",
  • "typescript": "^4.1.2",

build 時に Could not find a required file. と言われる

yarn start をして開発環境では何もエラーになっていないプロジェクトを build しようとしたら下記のようなエラーになりました。

$ yarn build
yarn run v1.22.17
$ react-scripts build
Could not find a required file.
  Name: index.js
  Searched in: /Users/kikiki/pgoject/react-app/src
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

エントリーポイントである index.js が見つからないらしい…
TypeScript プロジェクトだと index.tsx がエントリーポイントになっているはずなのにな〜ぜ〜だ〜

react-scripts のバージョンが問題だった

Create React App Docs would be to change the version of react-scripts in the package.json file to the most recent stable version like "react-scripts": "^4.0.3". Then, run npm install from the command line.
cf. reactjs - Could not find a required file. - Adding TypeScript to React project - Stack Overflow

package.json を見てみると react-scripts のバージョンが ^0.9.5 になっていました!古っ!!!
git の履歴をさかのぼってみると create-react-app をした段階では "react-scripts": "4.0.3" だったものが、なにかのライブラリをインストールしてやっぱ使わないとアンインストールした際に "react-scripts": "^0.9.5" に依存関係か何かで変更されてそのままになっていたようでした。

解決方法 "react-scripts": "4.0.3" にして npm install を行う

package.jsonreact-scripts のバージョンを "4.0.3" に変更して npm install をします。

  "dependencies": {
    …
-   "react-scripts": "^0.9.5",
+   "react-scripts": "4.0.3",
  }

react-scripts のバージョンが戻ったので再度 yarn build を実行した所問題なくビルドすることができました。

create-react-app で作ったプロジェクトが build できない時は react-scripts のバージョンを疑ってみる

何のパッケージが原因でそうなったのか本当に分らない… おわり。


[参考]

今日はビルドファイトだったな… (違う