date-fnsの日本語ファイルから曜日を取得する
date-fnsの日本語ファイル(
date-fns/index.js at master · date-fns/date-fns · GitHub
)に、['日', '月', '火', '水', '木', '金', '土']
という配列が用意されていたので、自分のプログラムから使えないかと調べました。
調査結果
ja.localize.day(index, options)
で配列の要素にアクセスできますが、配列そのものはdate-fnsから提供されていません。この関数を使用して自前で配列を作成してみましょう。
配列の要素にアクセスする関数のindex
には曜日を表す数字(0から6)を指定します。index
の数字と曜日の関係です。
0 | 1 | 2 | 3 | 4 | 5 | 6 |
---|---|---|---|---|---|---|
日 | 月 | 火 | 水 | 木 | 金 | 土 |
options
のプロパティーのキーにはwidth
が指定できます。
width
にはnarrow
、short
、abbreviated
、wide
が指定でき、narrow
が一番短い短縮形で、short
、abbreviated
となるにつれてそれよりも長い省略形になり、wide
は曜日の完全名(一番長い形)です。
width
を指定したときの英語と日本語の表記は以下のようになります。英語、日本語ともデフォルトはwide
です。
アメリカ英語(en-US) | 日本語(ja) | |
---|---|---|
{width:'narrow'} | ['S', 'M', 'T', 'W', 'T', 'F', 'S'] | ['日', '月', '火', '水', '木', '金', '土'] |
{width:'short'} | ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'] | ['日', '月', '火', '水', '木', '金', '土'] |
{width:'abbreviated'} | ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'] | ['日', '月', '火', '水', '木', '金', '土'] |
{width:'wide'} | ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday'] | ['日曜日', '月曜日', '火曜日', '水曜日', '木曜日', '金曜日', '土曜日'] |
日本語だとnarrow
とshort
とabbreviated
は同じですね。今回はshort
を指定します。
まず、動作を確認してみましょう。
import { ja } from 'date-fns/locale' console.log(ja.localize.day(0, {width: 'short'})) console.log(ja.localize.day(1, {width: 'short'})) console.log(ja.localize.day(2, {width: 'short'})) console.log(ja.localize.day(3, {width: 'short'})) console.log(ja.localize.day(4, {width: 'short'})) console.log(ja.localize.day(5, {width: 'short'})) console.log(ja.localize.day(6, {width: 'short'}))
実行結果です。曜日の短い名前が取得できました。
これらを配列にしてみましょう。 JavaScriptにはRubyやPythonのRangeに相当するものがないので、以下のように、 7個の要素を持つ空配列を作成してそれらをmapすることで曜日を取得します。
import { ja } from 'date-fns/locale' const weekdays = new Array(7).fill().map((_, i) => ja.localize.day(i, {width: 'short'})) console.log(weekdays)
fill()を使用する理由については以下の記事をご覧ください。
実行結果です。曜日の配列が取得できました。
しかし、プログラムの可読性から、日本語のみを扱うプログラムでは曜日名をプログラムに直書きで良いと思います。
const weekdays = ['日', '月', '火', '水', '木', '金', '土']
i18nが必要なアプリでは、以下のようにして曜日の一覧が取得できます。
# localeはユーザが指定したロケール。jaとかen-USとかesとか。 const weekdays = new Array(7).fill().map((_, i) => locale.localize.day(i, {width: 'short'}))
あとがき
カレンダーのヘッダ用に曜日の配列が必要でしたが、7要素しかなく、変更もないのでプログラム直書きでもよいという結論に(自分の中では)なりました。
しかし日本語の曜日名を取得する関数の情報は有益だと思いブログ記事にしました。
環境
date-fns: 2.8.1
関連記事
月名バージョン
JavaScriptでn個ずつ配列を分割する
JavaScriptで配列を指定された個数ずつに分割します。
例えば、
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
という配列を3個ずつ分割するのであれば、
[[1, 2, 3], [4, 5, 6], [7, 8, 9], [10]]
という配列になります。
実装方針
配列から一部を通り出すのには、
Array.prototype.slice() - JavaScript | MDN
という関数が使えます。
この関数は、開始のインデックスと終わりのインデックスを渡すと、開始のインデックスから終わりのインデックスの1つ前までの部分の配列を返します。
pythonのmylist[begin:end]
、rubyのarray[begin...end]
のような動作をします。
例えば、
const array=[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
であれば、
array.slice(3, 6),
は、3、4、5のインデックスを含むので
[4, 5, 6]
という配列が返されます。
また、
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
という配列をこのように3個ずつ分割するのを、
[[1,2,3], [4,5,6], [7,8,9], [10]]
slice()
を使用して書くと、
const result = [ array.slice(0, 3), array.slice(3, 6), array.slice(6, 9), array.slice(9, 10) ]
となります。slice()
の2つめの引数に配列の数より大きな値が指定された場合は、array.length
が指定されたのと同じになりますので、下記のように書き換えても同様の結果になります。最後の要素を、array.slice(9, 10)
からarray.slice(9, 12)
に変更しました。これで各sliceの引数が全て3の倍数となりました。
const result = [ array.slice(0, 3), array.slice(3, 6), array.slice(6, 9), array.slice(9, 12) ]
ところで、最終的な配列のサイズは、
分割する対象の配列を3で割って、端数が出たら切り上げた数です。今回分割する対象の配列の長さは10ですので、10/3=3.333..
これを切り上げて4が最終的に作成される配列の長さです。
JavaScriptで切り上げを行うには、
Math.ceil() - JavaScript | MDN
を使用します。
インデックスを3ずつずらしながら、array.slice()
を、作成する配列の長さぶん繰り返せば、配列を分割することができそうです。
コード
コードをステップバイステップで作成します。
はじめに関数を定義します。引数に分割対象の配列と、いくつずつに分割するか指定します。
const sliceByNumber = (array, number) => { console.log('array', array) console.log('number', number) return array } console.log(sliceByNumber([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3))
実行結果です。疎通確認が完了しました。
array [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] number 3 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
作成する配列のサイズを計算します。
const sliceByNumber = (array, number) => { const length = Math.ceil(array.length / number) console.log('length', length) return array } console.log(sliceByNumber([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3))
実行結果です。作成する配列の長さ"4"が取得できました。
length 4 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
次に、長さ4の配列を作成し、配列の各要素に対してmapを呼び出します。この時、配列のインデックスの数にnumber
を掛けたものを表示します。
const sliceByNumber = (array, number) => { const length = Math.ceil(array.length / number) return new Array(length).fill().map((_, i) => { console.log(`i=${i}, i*number=${i*number}, (i+1)*number=${(i+1)*number}`) return i }) } console.log(sliceByNumber([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3))
Array(n)
とmap()
の間にfill()
を挟む理由については、こちらの記事を参照してください。
実行結果です。Array.slice
に渡す数が取得できました。
i=0, i*number=0, (i+1)*number=3 i=1, i*number=3, (i+1)*number=6 i=2, i*number=6, (i+1)*number=9 i=3, i*number=9, (i+1)*number=12 [0, 1, 2, 3]
最後に、i*number
と(i+1)*number
をArray.slice
に渡せば、欲しい配列が出来上がります。
const sliceByNumber = (array, number) => { const length = Math.ceil(array.length / number) return new Array(length).fill().map((_, i) => array.slice(i * number, (i + 1) * number) ) } console.log(sliceByNumber([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 3))
実行結果です。配列が3個ずつに分割されています。最後は要素数が1になっています。
[ [1, 2, 3], [4, 5, 6], [7, 8, 9], [10] ]
array.length
がnumber
で割り切れる例です。長さ10の配列を5個ずつに分割しました。
[ [1, 2, 3, 4, 5], [6, 7, 8, 9, 10] ]
以上でn個ずつ配列を分割することができました。
date-fnsで「○分前」「約○時間前」「○日前」など現在時刻からのざっくりした時間経過を表示する
やりたいこと
Twitterのように、投稿日付を表示したい。「○分前」「○時間前」「○日前」など、現在時刻からの経過時間をざっくり表示したい。
date-fnsのformatDistanceToNowでできる
date-fnsのformatDistanceToNowを使えば、現在からのざっくりした経過時間を表示することができます。
date-fns - modern JavaScript date utility library
経過時間と表示される時間の対応は以下のようになります。
範囲 | 表示 |
---|---|
30秒未満 | 1分未満 |
30秒以上 1 分30 秒未満 | 1分 |
1分30秒以上 44分30秒未満 | [2..44]分 |
44分30秒以上 89分30秒未満 | 約1時間 |
89分30秒以上 23時間59分30秒未満 | 約[2..24]時間 |
23時間59分30秒以上 41時間59分30秒未満 | 1日 |
41時間59分30秒以上 29日23時間59分30秒未満 | [2..30]日 |
29日23時間59分30秒以上 44日23時間59分30秒未満 | 約1か月 |
44日23時間59分30秒以上 59日23時間59分30秒未満 | 約2か月 |
59日23時間59分30秒以上 1年未満 | [2..12]か月 |
1年以上 1年3か月未満 | 約1年 |
1年3か月以上 1年9か月未満 | 1年以上 |
1年9か月以上 2年未満 | 2年近く |
N年以上 N年3か月未満 | 約N年 |
N年3か月以上 N年9か月未満 | N年以上 |
N年9か月以上 N+1年未満 | N+1年近く |
プログラム例
実際に使用してみます。Reactを使用しています。
import React from 'react'; import formatISO9075 from 'date-fns/formatISO9075' import formatDistanceToNow from 'date-fns/formatDistanceToNow' import { ja } from 'date-fns/locale' function App() { const targetDate = new Date(2019, 11, 8, 10, 13) return ( <div> <div>現在時刻: {formatISO9075(new Date())}</div> <div>対象時間: {formatISO9075(targetDate)}</div> <div>経過時間: {formatDistanceToNow(targetDate, {locale: ja})}</div> </div> ); } export default App;
実行結果です。経過時間が表示されました。(実際にはスタイルを適用しています。)
色々な経過時間での表示を確かめる
色々な経過時間で実際に表示時間を確かめてみました。
デフォルトの設定では、"○分"、"約○時間"のように現在からの差分がどのくらいか表示されます。今回は、optionにaddSuffix: true
を指定して、"○分前"、"約○時間後"と、"前"または"後"を後ろにつけるようにしました。
現在時刻が2019-12-08 22:23:56
のとき
説明 | 日時 | formatDistanceToNow(date, {addSuffix: true, locale: ja}) |
---|---|---|
3秒前 | 2019-12-08 22:23:53 | 約1分前 |
40秒前 | 2019-12-08 22:23:16 | 1分前 |
1分20秒前 | 2019-12-08 22:22:36 | 1分前 |
4分50秒前 | 2019-12-08 22:19:06 | 5分前 |
17分25秒前 | 2019-12-08 22:06:31 | 17分前 |
47分4秒前 | 2019-12-08 21:36:52 | 約1時間前 |
1時間25分56秒前 | 2019-12-08 20:58:00 | 約1時間前 |
1時間37分12秒前 | 2019-12-08 20:46:44 | 約2時間前 |
10時間5分32秒前 | 2019-12-08 12:18:24 | 約10時間前 |
23時間50分15秒前 | 2019-12-07 22:33:41 | 約24時間前 |
1日5分52秒前 | 2019-12-07 22:18:04 | 1日前 |
1日17時間2分47秒前 | 2019-12-07 05:21:09 | 1日前 |
1日18時間11分30秒前 | 2019-12-07 04:12:26 | 2日前 |
3日2時間45分7秒前 | 2019-12-05 19:38:49 | 3日前 |
12日20時間36分3秒前 | 2019-11-26 01:47:53 | 13日前 |
29日10時間46分51秒前 | 2019-11-09 11:37:05 | 29日前 |
30日1時間29分1秒前 | 2019-11-08 20:54:55 | 約1か月前 |
50日6時間27分48秒前 | 2019-10-19 15:56:08 | 約2か月前 |
63日22時間1分55秒前 | 2019-10-06 00:22:01 | 2か月前 |
120日19時間4分6秒前 | 2019-08-10 03:19:50 | 4か月前 |
361日9時間22分29秒前 | 2018-12-12 13:01:27 | 12か月前 |
1年10日15時間32分15秒前 | 2018-11-28 06:51:41 | 約1年前 |
1年120日14時間44分20秒前 | 2018-08-10 07:39:36 | 1年以上前 |
1年300日12時間3分30秒前 | 2018-02-11 10:20:26 | 2年近く前 |
3年36日2時間22分45秒前 | 2016-11-02 20:01:11 | 約3年前 |
3年170日5時間38分33秒前 | 2016-06-21 16:45:23 | 3年以上前 |
3年290日2時間39分10秒前 | 2016-02-22 19:44:46 | 4年近く前 |
10年150日13時間4分2秒前 | 2009-07-11 09:19:54 | 10年以上前 |
30秒未満の場合、suffix("前"や"後")をつけないと、"1分未満"と表示されますが、suffixをつけると"約1分前"になります。"1分未満前"にならないところに細かい気遣いがあります。(ソースコードはこちら→ date-fns/index.js at master · date-fns/date-fns · GitHub )
ソースコード
上記の表を出力するコードです。Reactを使用しています。
# date-fnsのインストール
$ yarn add date-fns
import React from 'react'; import formatISO9075 from 'date-fns/formatISO9075' import formatDistanceToNow from 'date-fns/formatDistanceToNow' import subSeconds from 'date-fns/subSeconds' import subMinutes from 'date-fns/subMinutes' import subHours from 'date-fns/subHours' import subDays from 'date-fns/subDays' import subYears from 'date-fns/subYears' import { ja } from 'date-fns/locale' import './App.css'; const subFromNow = ({years=0, days=0, hours=0, minutes=0, seconds=0}) => { let timeAgo = new Date() let description = ""; if (years) { timeAgo = subYears(timeAgo, years) description += `${years}年` } if (days) { timeAgo = subDays(timeAgo, days) description += `${days}日` } if (hours) { timeAgo = subHours(timeAgo, hours) description += `${hours}時間` } if (minutes) { timeAgo = subMinutes(timeAgo, minutes) description += `${minutes}分` } if (seconds) { timeAgo = subSeconds(timeAgo, seconds) description += `${seconds}秒` } description += "前" return {description, timeAgo} } function App() { const timeAgoArr = [] timeAgoArr.push(subFromNow({seconds:3})) timeAgoArr.push(subFromNow({seconds:40})) timeAgoArr.push(subFromNow({minutes:1, seconds:20})) timeAgoArr.push(subFromNow({minutes:4, seconds:50})) timeAgoArr.push(subFromNow({minutes:17, seconds:25})) timeAgoArr.push(subFromNow({minutes:47, seconds:4})) timeAgoArr.push(subFromNow({hours:1, minutes:25, seconds:56})) timeAgoArr.push(subFromNow({hours:1, minutes:37, seconds:12})) timeAgoArr.push(subFromNow({hours:10, minutes:5, seconds:32})) timeAgoArr.push(subFromNow({hours:23, minutes:50, seconds:15})) timeAgoArr.push(subFromNow({days:1, hours:0, minutes:5, seconds:52})) timeAgoArr.push(subFromNow({days:1, hours:17, minutes:2, seconds:47})) timeAgoArr.push(subFromNow({days:1, hours:18, minutes:11, seconds:30})) timeAgoArr.push(subFromNow({days:3, hours:2, minutes:45, seconds:7})) timeAgoArr.push(subFromNow({days:12, hours:20 , minutes:36, seconds:3})) timeAgoArr.push(subFromNow({days:29, hours:10 , minutes:46, seconds:51})) timeAgoArr.push(subFromNow({days:30, hours:1 , minutes:29, seconds:1})) timeAgoArr.push(subFromNow({days:50, hours:6 , minutes:27, seconds:48})) timeAgoArr.push(subFromNow({days:63, hours:22 , minutes:1, seconds:55})) timeAgoArr.push(subFromNow({days:120, hours:19 , minutes:4, seconds:6})) timeAgoArr.push(subFromNow({days:361, hours:9 , minutes:22, seconds:29})) timeAgoArr.push(subFromNow({years:1, days:10, hours:15, minutes:32, seconds:15})) timeAgoArr.push(subFromNow({years:1, days:120, hours:14, minutes:44, seconds:20})) timeAgoArr.push(subFromNow({years:1, days:300, hours:12, minutes:3, seconds:30})) timeAgoArr.push(subFromNow({years:3, days:36, hours:2, minutes:22, seconds:45})) timeAgoArr.push(subFromNow({years:3, days:170, hours:5, minutes:38, seconds:33})) timeAgoArr.push(subFromNow({years:3, days:290, hours:2, minutes:39, seconds:10})) timeAgoArr.push(subFromNow({years:10, days:150, hours:13, minutes:4, seconds:2})) return ( <div className="fromNowTable"> <div className="currentTime">現在時刻: {formatISO9075(new Date())}</div> <table> <thead> <tr> <th>説明</th><th>日時</th><th>formatDistanceToNow({'{'}addSuffix: true, locale: ja})</th> </tr> </thead> <tbody> {timeAgoArr.map(({description, timeAgo}, index) => ( <tr key={index}> <td className="description">{description}</td> <td>{formatISO9075(timeAgo)}</td> <td>{formatDistanceToNow(timeAgo, {addSuffix: true, locale: ja})}</td> </tr> ))} </tbody> </table> </div> ); } export default App;
date-fnsの他の経過時間を表示する関数
date-fnsには他にも date-fns - modern JavaScript date utility library という関数が用意されています。 こちらもざっくりとした経過時間を表示しますが、 "約"や"以上"などを表示しないのですっきりするかもしれません。 引数は2つとる必要があり、毎回現在時刻を渡す必要があります。
環境
関連記事
moment.jsで同様のことを行なった記事です。dete-fnsのformatDistanceToNowとは少し表示が違います。↓
React(JSX)で波括弧をエスケープしたい
ReactのJSX内で波括弧({
と}
)を通常の文字として出力しようとしたところ、エラーになってしまったので、回避方法を記載します。
うまくいかない例
function App() { return ( <div> <div>JavaScriptではオブジェクトを、{key: value} の形式で作成できます。</div> </div> ); }
こちらを実行すると、
Parsing error: Unexpected token, expected "}"
のエラーが表示されます。
エラーの原因
JSXでは{
と}
の間は式として解釈されます。上の例でいうと、{key: value}
の、key: value
の部分は式でなければいけないのですが、これは式ではないためエラーになっています。
また、今回は式として認識されたくないので、何かしらのエスケープ処理が必要になります。
解決方法
Escaping curly brackets · Issue #1545 · facebook/react · GitHub
こちらに回答されている通り、
最初の開き波括弧を{}
の中に文字列表現として記載します。{'{'}
のようになります。
この解決策を使って最初のコードを書き換えたのが以下です。
function App() { return ( <div> <div>JavaScriptではオブジェクトを、{'{'}key: value} の形式で作成できます。</div> </div> );
実行結果です。波括弧が文字列として表示されました。
環境
nコマンドを使用してnode.jsをバージョンアップする
nを使用してnode.jsをアップデートしたときの記録です。
こちらの記事を参考にしました。
nのインストール
nとは、node.jsのバージョンを管理するツールです。
nをインストールします。バージョン6.1.3がインストールされました。
$ npm install -g n /usr/local/bin/n -> /usr/local/lib/node_modules/n/bin/n + n@6.1.3 added 1 package from 4 contributors in 1.085s ╭───────────────────────────────────────────────────────────────╮ │ │ │ New minor version of npm available! 6.2.0 → 6.5.0 │ │ Changelog: https://github.com/npm/cli/releases/tag/v6.5.0 │ │ Run npm install -g npm to update! │ │ │ ╰───────────────────────────────────────────────────────────────╯
アップデート前のnodeのバージョン
アプデート前のnodeとnpmのバージョンです。それぞれ-v
オプションで確認できます。
$ node -v v10.8.0 $ npm -v 6.2.0
nodeの安定板を入手
最新の安定板のバージョンを確認します。
$ n --stable 12.13.1
最新の安定板をインストールします。
$ n stable installing : node-v12.13.1 mkdir : /usr/local/n/versions/node/12.13.1 mkdir: /usr/local/n/versions/node/12.13.1: Permission denied Error: sudo required (or change ownership, or define N_PREFIX)
パーミッションエラーになってしまいました。
Error: sudo required (or change ownership, or define N_PREFIX)
「エラー: sudoが必要。(または、パーミッションを変更するか、N_PREFIXを使用してください)」と書いてあります。
今回はsudo
を使用します。
$ sudo n stable Password: installing : node-v12.13.1 mkdir : /usr/local/n/versions/node/12.13.1 fetch : https://nodejs.org/dist/v12.13.1/node-v12.13.1-darwin-x64.tar.gz installed : v12.13.1 (with npm 6.12.1)
nodeのバージョンを確認します。
$ node -v v12.13.1
最新の安定板にアップデートされました。 ちなみに最新版を使用したい場合は、"stable"を"latest"に変更します。
N_PREFIXを使用する場合について
Error: sudo required (or change ownership, or define N_PREFIX)
こちらのエラーをN_PREFIXを使用して対処する場合。
N_PREFIXはnodeモジュールをインストールする場所です。デフォルトでは/usr/local
です。
インストールする場所を、例えば${HOME}/.n
に変更する場合は、GitHub - tj/n: Node version managementに書いてあるとおり、.bash_profile
などの起動シェルに以下を記載します。
export N_PREFIX=$HOME/.n export PATH=$N_PREFIX/bin:$PATH
npmのアップデート
あわせて、npmもアップデートします。
$ npm update -g npm npm WARN checkPermissions Missing write access to /usr/local/lib/node_modules/npm/node_modules/https-proxy-agent npm WARN checkPermissions Missing write access to /usr/local/lib/node_modules/npm/node_modules/make-fetch-happen npm WARN checkPermissions Missing write access to /usr/local/lib/node_modules/npm/node_modules/pacote/node_modules/minipass npm WARN checkPermissions Missing write access to /usr/local/lib/node_modules/npm/node_modules/pacote npm WARN checkPermissions Missing write access to /usr/local/lib/node_modules/npm/node_modules/read-cmd-shim npm WARN checkPermissions Missing write access to /usr/local/lib/node_modules/npm/node_modules/smart-buffer npm WARN checkPermissions Missing write access to /usr/local/lib/node_modules/npm/node_modules/socks npm WARN checkPermissions Missing write access to /usr/local/lib/node_modules/npm npm WARN checkPermissions Missing write access to /usr/local/lib/node_modules/npm/node_modules npm WARN checkPermissions Missing write access to /usr/local/lib/node_modules/npm/node_modules/pacote/node_modules npm ERR! code EACCES npm ERR! syscall access npm ERR! path /usr/local/lib/node_modules/npm/node_modules/https-proxy-agent npm ERR! errno -13 npm ERR! Error: EACCES: permission denied, access '/usr/local/lib/node_modules/npm/node_modules/https-proxy-agent' npm ERR! [Error: EACCES: permission denied, access '/usr/local/lib/node_modules/npm/node_modules/https-proxy-agent'] { npm ERR! stack: "Error: EACCES: permission denied, access '/usr/local/lib/node_modules/npm/node_modules/https-proxy-agent'", npm ERR! errno: -13, npm ERR! code: 'EACCES', npm ERR! syscall: 'access', npm ERR! path: '/usr/local/lib/node_modules/npm/node_modules/https-proxy-agent' npm ERR! } npm ERR! npm ERR! The operation was rejected by your operating system. npm ERR! It is likely you do not have the permissions to access this file as the current user npm ERR! npm ERR! If you believe this might be a permissions issue, please double-check the npm ERR! permissions of the file and its containing directories, or try running npm ERR! the command again as root/Administrator. npm ERR! A complete log of this run can be found in: npm ERR! /Users/yucatio/.npm/_logs/2019-12-04T00_47_45_795Z-debug.log
エラーになりました。こちらもsudoが必要です。
$ sudo npm update -g npm /usr/local/bin/npm -> /usr/local/lib/node_modules/npm/bin/npm-cli.js /usr/local/bin/npx -> /usr/local/lib/node_modules/npm/bin/npx-cli.js + npm@6.13.2 updated 8 packages in 6.705s
npmのバージョンを確認します。
$ npm -v 6.13.2
npmもアップデートが完了しました。
環境
create-react-app実行時に@typescript-eslint/eslint-plugin@2.3.2: The engine "node" is incompatible with this module. Expected version "^8.10.0 || ^10.13.0 || >=11.10.1".のエラー
エラー内容
create-react-appのバージョンを2.0.4から3.2.0へアップグレードしたところ、yarn create react-app
の実行時にエラーが発生しました。
$ yarn create react-app time-in-words yarn create v1.9.4 [1/4] 🔍 Resolving packages... [2/4] 🚚 Fetching packages... [------------------------------------------------------------------------] 0/91(node:54333) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead. [3/4] 🔗 Linking dependencies... [4/4] 📃 Building fresh packages... success Installed "create-react-app@3.2.0" with binaries: - create-react-app [#######################################################################] 92/92 Creating a new React app in /Users/yucatio/react/time-in-words. Installing packages. This might take a couple of minutes. Installing react, react-dom, and react-scripts... yarn add v1.9.4 [1/4] 🔍 Resolving packages... [2/4] 🚚 Fetching packages... [----------------------------------------------------------------------] 0/1317(node:54337) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead. error @typescript-eslint/eslint-plugin@2.3.2: The engine "node" is incompatible with this module. Expected version "^8.10.0 || ^10.13.0 || >=11.10.1". error Found incompatible module info Visit https://yarnpkg.com/en/docs/cli/add for documentation about this command. Aborting installation. yarnpkg add --exact react react-dom react-scripts --cwd /Users/yucatio/react/time-in-words has failed. Deleting generated file... package.json Deleting generated file... yarn.lock Deleting time-in-words/ from /Users/yucatio/react Done. error Command failed. Exit code: 1 Command: /usr/local/bin/create-react-app Arguments: time-in-words Directory: /Users/yucatio/react Output: info Visit https://yarnpkg.com/en/docs/cli/create for documentation about this command.
原因
画面には色々書かれていますが、エラーの原因はこの部分のようです。
error @typescript-eslint/eslint-plugin@2.3.2: The engine "node" is incompatible with this module. Expected version "^8.10.0 || ^10.13.0 || >=11.10.1". error Found incompatible module
こちらで回答されているとおり、nodeのバージョンが古いことが原因ということがわかりました。
このエラーが発生した時の関連するパッケージのバージョンです↓
$ yarn info create-react-app version 3.2.0 $ node -v v10.8.0 $ npm -v 6.2.0
nodeのバージョンが"^8.10.0 || ^10.13.0 || >=11.10.1"でないことがわかります。
対策
nodeのバージョンをあげました。こちらの記事を参考にしました。
エラーがでた場合はこちらの記事もご覧ください。
執筆時(2019年12月)のnodeのstableバージョンは12.13.1でしたので、このバージョンにアップデートしました。npmのバージョンは6.13.2にアップデートしました。
その後、yarn create react-app
コマンドを実行したところ、正常に実行できました。
環境
create-react-appのバージョンを2.0.4から3.2.0(執筆時最新版)へアップグレードする
久しぶりにReactアプリを作成しようと思い、reate-react-appのバージョンも最新にしようとして試行錯誤したことを記録しておきます。
結論
メジャーバージョンをまたいだ最新バージョンにアップグレードする場合は--latest
を指定する。
$ yarn global upgrade create-react-app --latest
--latestつけないとメジャーバージョンが同一の最新版にアップグレードされる
アップグレード前のバージョン
アップグレード前のバージョンは2.0.4でした。create-react-appがグローバル環境にインストールされています。
$ yarn global list create-react-app yarn global v1.9.4 # これはyarn自体のバージョン [---------------------------------------------------------------] 0/63(node:54313) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead. info "create-react-app@2.0.4" has binaries: # これの 2.0.4の部分がcreate-react-appのバージョン - create-react-app ✨ Done in 0.22s.
upgradeコマンドで最新版にアップグレード
yarnの公式サイトyarn global | Yarnを参考に最新版へのアップグレードを試みました。
$ yarn global upgrade create-react-app yarn global v1.9.4 # これはyarn自体のバージョン [1/4] 🔍 Resolving packages... [2/4] 🚚 Fetching packages... [---------------------------------------------------------------] 0/63(node:54321) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead. [3/4] 🔗 Linking dependencies... [4/4] 📃 Rebuilding all packages... success Saved lockfile. warning Your current version of Yarn is out of date. The latest version is "1.19.2", while you're on "1.9.4". # yarnのバージョンをあげてね、との警告 info To upgrade, run the following command: $ brew upgrade yarn success Saved 52 new dependencies. info Direct dependencies └─ create-react-app@2.1.8 # バージョン2.1.8をインストールする info All dependencies ├─ ansi-styles@2.2.1 ├─ balanced-match@1.0.0 ├─ block-stream@0.0.9 # 中略 ├─ which@1.3.1 ├─ xtend@4.0.2 └─ yallist@2.1.2 ✨ Done in 1.26s.
create-react-appのバージョンを確認します。2.1.8でした。執筆時の最新バージョンは3.2.0ですので、期待した結果ではありません。
$ yarn global list create-react-app yarn global v1.9.4 # これはyarn自体のバージョン [---------------------------------------------------------------] 0/63(node:54322) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead. info "create-react-app@2.1.8" has binaries: # create-react-appのバージョンは2.1.8 - create-react-app ✨ Done in 0.20s.
メジャーバージョンをまたいで最新バージョンを取得する
この記事を書いている時点(2019年12月)の時点でのcreate-react-appの最新バージョンは3.2.0です。メジャーバージョンをまたいで最新バージョンにアップグレードするには、--latest
オプションを使用します。
$ yarn global upgrade create-react-app --latest yarn global v1.9.4 # これはyarn自体のバージョン [1/4] 🔍 Resolving packages... [2/4] 🚚 Fetching packages... [------------------------------------------------------------------------] 0/91(node:54326) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead. [3/4] 🔗 Linking dependencies... [4/4] 📃 Rebuilding all packages... success Saved lockfile. success Saved 40 new dependencies. info Direct dependencies └─ create-react-app@3.2.0 # バージョン3.2.0をインストールする info All dependencies ├─ ansi-escapes@3.2.0 ├─ ansi-regex@4.1.0 ├─ ansi-styles@3.2.1 # 中略 ├─ supports-color@5.5.0 ├─ through@2.3.8 └─ tslib@1.10.0 ✨ Done in 5.73s.
create-react-appのバージョンを確認します。3.2.0でした。執筆時の最新バージョンになりました。
$ yarn global list create-react-app yarn global v1.9.4 # これはyarn自体のバージョン [-------------------------------------------------------------------------------------------] 0/91(node:55561) [DEP0005] DeprecationWarning: Buffer() is deprecated due to security and usability issues. Please use the Buffer.alloc(), Buffer.allocUnsafe(), or Buffer.from() methods instead. info "create-react-app@3.2.0" has binaries: # create-react-appのバージョンは3.2.0 - create-react-app ✨ Done in 0.22s.
global環境にインストールされたパッケージのバージョン管理ポリシー
yarn global add some-package would add a carret-range, something like ^1.0.0
`yarn global upgrade` doesn't upgrade packages · Issue #5001 · yarnpkg/yarn · GitHub
「yarn global add some-package
を実行したときには、"^1.0.0"のように、キャレットレンジが適用されます」と書かれています。
キャレットレンジは
Versions of dependencies | Yarn
に例が示されているように、例えば^1.2.3
であれば、バージョン1.2.3以上、2.0.0未満までのバージョンを受け入れるという意味です。
yarn global add
だけでなく、yarn add
を実行した際、このキャレットレンジがデフォルトで適用されます。
続く
この時点でcreate-react-appのバージョンアップは解決したのですが、nodeをアップグレードしなかったため、別のエラーが出てしまいました。yarn create react-app
の実行の際にエラーが出た場合は下記の記事もご覧ください。