演算子 ?? が使えて ??= が使えない理由と Nuxt.js でSSRのときだけ ??= がこける理由
環境
$ node -v
v19.8.1
$ npm i @babel/cli
$ babel -V
7.21.0 (@babel/core 7.21.3)
$ nuxt -v
@nuxt/cli v2.16.3
?? (Nullish Coalescing Operator - ES2020)
$ echo "null ?? 1; let a; a ??= 1" | babel --no-babelrc --plugins @babel/plugin-proposal-nullish-coalescing-operator -f -
var _ref;
(_ref = null) !== null && _ref !== void 0 ? _ref : 1;
let a;
a ??= 1;
-
@babel/plugin-proposal-nullish-coalescing-operator
で有効になる -
??
はトランスパイルしてくれているが??=
はそのままなことがわかる
??= (Logical Assignment Operators - ES2021)
echo "let a; a ||= 1; a ??= 1" | babel --no-babelrc --plugins @babel/plugin-proposal-logical-assignment-operators -f -
let a;
a || (a = 1);
a ?? (a = 1);
-
@babel/plugin-proposal-logical-assignment-operators
で有効になる - 本来は
||=
と書けるようにするためのもの - ついでに
??=
にも対応しているというだけ - つまり
??
と??=
は別ものだった
??=
でこける問題
Nuxt.js で SSR すると Nuxt.js で SSR するとサーバーサイドでのみ ??=
が失敗する。当初 ??
が有効なら ??=
も使えると考えていたし、SSR時のクライアントサイドどサーバーサイドの環境が異なっているとは思わなかったので、サーバーサイドかつ ??=
のときだけおかしくなるという条件に気づくまでが本当に長かった。
こちらを見ると、
サーバーサイドで中途半端に ??
こと @babel/plugin-proposal-nullish-coalescing-operator
だけを有効にしているのがわかったので .babelrc
の plugins
に追加する。
{
"presets": [
"@babel/preset-env",
],
"plugins": [
"@babel/plugin-proposal-logical-assignment-operators",
],
}
ところがぜんぜん反映されないのでドキュメントを見ると、
JavaScript や Vue ファイルのために Babel の設定をカスタマイズします。 .babelrc はデフォルトで無視されます。
とのこと。そういうときに .babelrc
があれば警告を出してあげるぐらいの思いやりはほしい。不親切にもほどがある。
@nuxt/babel-preset-app のデフォルトターゲットは client ビルドでは ie: '9'、server ビルドでは node: 'current' になります。
これは微調整していた package.json の browserslist もまったく効いていなかったということなのだろう。
ちなみに @babel/cli
で入れた babel コマンドは nuxt.config.js
の方なんか見るわけもなく .babelrc
の方を見るし、package.json の browserslist も見る。もう、ややこしすぎて未来の自分がこの記事を読んで理解できそうに思えない。
もともと複雑なもの @babel/preset-app
をより複雑なもの @nuxt/babel-preset-app
でラップしてはいけない(切実)
結局、次のようにするとサーバーサイドでも ??=
が効くようになった。
...
build: {
babel: {
plugins: [
"@babel/plugin-proposal-logical-assignment-operators",
],
},
},
...
なお、クライアントサイドでこけなかった理由はわからない。
まとめ
- babel で
??
が使えたからといって??=
も使えるとは限らない -
??
は Nullish Coalescing Operator と呼ぶ -
??=
は Logical Assignment Operators と呼ぶ- https://babeljs.io/docs/babel-plugin-proposal-logical-assignment-operators
-
||=
と??=
のこと -
??
演算子を含まない
- この2つは babel 的には別のもの
- Nuxt.js (SSR) のサーバーサイドで有効になっているのは前者のみ
- なので
??=
を使うには自力で設定を追加しないといけない - 問題の切り分けが難しすぎる
Discussion