かもメモ

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

JavaScript, Node.js 先に作っておいた変数を named export したい

default exports は好きな名前で import できてしまうから極力 named exports / import にしたほうが良いと教えてもらったので、先に変数が作られてる場合どうするんだろう?と思い調べて見たメモ。

ESModules の named exports

exports

// foo.ts
export const foo = 'Foo!';

import

import { foo } from './foo'

ESModules の default exports

exports

// app.ts
import express = require('express');
const app: express.Express = express();

export default app;

import

import app from './app'

default exports は好きな名前で import できる

import myapp from './app'
myapp; // => express.Express

先に作っている変数を named exports したい

// app.ts
import express = require('express');
const app: express.Express = express();
app.use(...); 
// … 色々処理

export app;
// => Error: Declaration or statement expected.

これはDeclaration or statement expected. エラーになる。

export { } で named exports することができる

// app.ts
import express = require('express');
const app: express.Express = express();
app.use(...); 
// … 色々処理

export { app };

import

import { app } from './app';

₍ ᐢ. ̫ .ᐢ ₎👌

as を使えば名前を変えてnamed exports することもできる

// app.ts
import express = require('express');
const app: express.Express = express();

export { app as myapp };

import

import { app } from './app';
// => Error: Module '"./app"' declares 'app' locally, but it is exported as 'myapp'.

TypeScriptでは myapp で exports されているけど?というエラーを表示してくれる。
₍ ᐢ. ̫ .ᐢ ₎👌

default exports は default という特別な名前を付けた named export だった。

export default app;

これは下記と同じ意味

export { app as default };

e.g.

// app.ts
import express = require('express');
const app: express.Express = express();

export { app as default };

import

import { app } from './app';
// => Error: Module '"./app"' has no exported member 'app'. Did you mean to use 'import app from "./app"' instead?

TypeScriptでは import app from "./app" では?というエラーを表示してくれる。
₍ ᐢ. ̫ .ᐢ ₎👌

import

import app from './app';
// 👌

₍ᐢ •̥ ̫ •̥ ᐢ₎‪ 完全に理解した!

感想

import / exports 周り完全に雰囲気で使っているのでチョクチョクあれ?どうやるんだっけ???になってます。
ESModules と CommonJS の import / export, require / module.exports いつかちゃんと調べようと思いつつ数百年が立ってしまった… そして未だに雰囲気でしか理解してない。。。

TypeScript まだよわよわなんで頑張っていきたい。
チョットづつエラーも読めるようになってきた。


[参考]

ハンズオンNode.js

ハンズオンNode.js

  • 作者:今村 謙士
  • 発売日: 2020/11/17
  • メディア: 単行本(ソフトカバー)

Node.jsデザインパターン 第2版

Node.jsデザインパターン 第2版

Firebase Cloud Firestore で複数の OrderBy で 9 FAILED_PRECONDITION: The query requires an index なエラーになった

Cloud Firestore からデータを取ってこようとしたら次のようなエラーが返ってきた。

{
  error: {
    code: 9,
    details: "The query requires an index. You can create it here: https://console.firebase.google.com/v1/r/project/<projectName>/firestore/indexes?...",
    message: "9 FAILED_PRECONDITION: The query requires an index. You can create it here: https://console.firebase.google.com/v1/r/project/<projectName>/firestore/indexes?...",
    metadata: …
  }
}

9 FAILED_PRECONDITION なエラーになるコード

const db = admin.firestore();

const snapshot = await db
  .collection(COLLECTION)
  .orderBy('score', 'asc')
  .orderBy('createAt', 'asc')
  .get();

どうやら orderBy() が複数個あるとエラーになってしまうようでした。

Cloud Firestore にインデックスが作成されてないとエラーになる

エラーを見ていると The query requires an index. You can create it here: https://console.firebase.google.com/... と書かれていました。
エラーに続く URL にアクセスすると Firebase コンソールから Cloud Firestore にインデックスを作成するか聴かれるモーダルが表示されます。そのまま作成ボタンを押すとインデックスが作成されます。

firebase Cloud Firestore console

インデックスのビルドに少し時間がかかりますが、ステータスが 有効 になればインデックスが有効になり先の 9 FAILED_PRECONDITION になっていたクエリが実行できるようになりました。

インデックスが必要だと分かっている場合は、コンソールから前もってから作成しておくのが良さそうです。
インデックスが全く作成されていないプロジェクトなら Cloud Firestore のインデックス タブを選択して インデックスを作成ボタン から作成することができます。

firebase Cloud Firestore console

所管

複数のフィールドで並べ替えを行うこともできます。たとえば、州で並べ替え、各州の中で人口の降順で並べ替える場合は、次のようにします。

citiesRef.orderBy("state").orderBy("population", "desc");
cf. Order and limit data with Cloud Firestore  |  Firebase

公式ドキュメントに orderBy() を複数使う例が載っていて、そこにインデックスが必要なことが書かれていなかったので、そもそも Firestore に接続できてないのか?なども疑ってハマってしまいました。
Firebase のドキュメント総じて分かりにくい気がしてるのは僕だけ?
そして作成されたインデックスの削除の方法が分からない…


[参考]

ナイン (講談社文庫)

ナイン (講談社文庫)

firebase firebase init で Error Failed to list Firebase projects. になる

久々に Firebase Hosting を使おうとしてしたら firebase init の Project Setup で 既にあるプロジェクトを使おうと思い Use an existing project を選択すると Error: Failed to list Firebase projects. See firebase-debug.log for more info. になってしまった。

$ firebase init
    ######## #### ########  ######## ########     ###     ######  ########
     ##        ##  ##     ## ##       ##     ##  ##   ##  ##       ##
     ######    ##  ########  ######   ########  #########  ######  ######
     ##        ##  ##    ##  ##       ##     ## ##     ##       ## ##
     ##       #### ##     ## ######## ########  ##     ##  ######  ########=== Project Setup

First, let's associate this project directory with a Firebase project.
You can create multiple project aliases by running firebase use --add,
but for now we'll just set up a default project.

? Please select an option: Use an existing project

Error: Failed to list Firebase projects. See firebase-debug.log for more info.

firebase-tools をアップデートしていたのが原因だった。

node.js を nodebrew でアップデートしたのに伴い firebase-tools を再インストールしていました。
再インストールした後も firebase login コマンドを実行したら既にログインされていると表示されたので問題ないと思っていたのですが、どうやらログインされている情報がアップデート前の firebase-tools での情報になっていて認証トークン無効になってるのが原因で正しく firebase からプロジェクトのリストを取ってこれなくなっているようでした。

firebase cli で再ログインすれば OK

$ firebase logout
$ firebase login

一度ログアウトして、再度 firebase login でアカウントにログインしたら問題なく既存のプロジェクトが選択できるようになりました!

今年こそちゃんと firebase に向き合っていこうと思います。


[参考]

ちょろいオタクなのでアイカツプラネット!の響子先輩〜になってる。