20200624のNode.jsに関する記事は4件です。

[Windows][Docker] nodeコンテナでnpm installが動かず地獄を見た

どおおおおもおおおお:innocent:
受諾案件で掲題のことをして地獄を見ましたyagrushです:anger:

引き継いだのは、nodeにgulpやらbabelやらonsen-uiやら大量にインポートしたサーバーアプリケーション。
これ、いままでvagrantで動いてたらしいんだけど、docker化せねばならない。
しかもマルチOS(Windows, Mac, Linux)で。

現状

  • ルートディレクトリに package.json は残っていました。
  • /node_modules はありませんでした。
    (そもそも、違う環境の /node_modules は(環境依存モジュールが有る可能性があるので)流用する気はないですけれども)

package.json をたよりに npm install してみんとす

  • Mac ... 奇跡的に動いた。
  • Linux ... 奇跡的に動いた。

  • Windows ... :anger::anger::anger::anger::anger:

npm ERR! code ENOENT
npm ERR! syscall open
npm ERR! path /xxxxxxxxxxx/xxxxxxxxxxx/xxxxxxxxxxx
npm ERR! errno -2
npm ERR! enoent ENOENT: no such file or directory, open '/xxxxxxxxxxx/xxxxxxxxxxx/xxxxxxxxxxx'
... 
npm ERR! Maximum call stack size exceeded
"Failed to load external module @babel/register"

これらのエラーが途中で無秩序に発生します・・・:anger::anger::anger:
上記3種のエラーが出て止まればまだマシな方で、最悪、Docker Desktopがハングアップします…

なおコマンドインターフェース上のプログレス表示の傾向としては、

  • 最初は快速にnpm installが進行していきますが、
  • だんだん遅くなり、
  • やがて永眠します…

(なんだか、メモリリークを大リファクタリングした昔の仕事を彷彿とさせるなぁ…)

トライアンド全部エラー

ネット上には、同様に犠牲となった多数の猛者たちの夢の跡が散見されるのですが、

  • npm install --no-bin-links ← すでにやっとるがな!
  • rm -f package-lock.json ← すでにやっとるがな!!
  • docker desktopの性能設定を上げる
  • npm cache clean --force
  • .npmignore を作る
  • npm rebuild
  • npm config set registry http://registry.npmjs.org/
  • package.jsonをすべて手書きのnpm installにする

ええ、全部やってみましたとも:anger:

対処方法

よかろう!!
貴様がその気なら、こちらにも考えがあるわ!!!

というわけで、超スーパー泥臭対応で解決しました。

  1. docker-nodeコンテナのワークディレクトリをdocker-compose.ymlなどでvolumeマウントしておく。
  2. 何度もnpm installする。
  3. コケてもハングアップしても /node_modules は絶対削除せずに、何度もリトライ。
  4. npm installコマンドは、/node_modules にすでにあるものを飛ばして次のモジュールをインストールする。
  5. やがて、/node_modules が完成された姿として満たされていく・・・!
  6. そしてあなたは、ついに暁の空を目撃するであろう。(npm installを完遂したことになり次の処理に移れる)
  7. 血と汗とともに完成した /node_modules を(volumeマウント経由でdockerコンテナから確保し、)/windows_node_modules などとして大事に大事に「よしよしいい子だ~」と言って秘蔵しておく。
  8. ビルドスクリプトを修正し、次回からは npm install を実行させるのではなく、/windows_node_modules を mv windows_node_modules node_modules で済ませるようにする。

あとがき

はーマジ鬼門だわ:anger::anger::anger:
現象から想像するに、Windows * (npm on Docker) 固有の問題なのかねぇ…。
今度余裕あればnpmじゃなくてyarnで試してみようかな
(意外と動いたりしそうで怖い)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Stripeでchargesの後にtransfersする方法 | Node.js

やりたいこと(重要)

・プラットフォームのサービスを作っている
・購入者が決済 => プラットフォームへお金が振り込まれる
・最終的に、出品者(子アカウント)へお金を送金したい

方法

これで、フロントで決済したクレカが、プラットフォームへチャージ(決済)されます

      stripe.charges.create(
        {
          amount: 1000,
          currency: 'jpy',
          source: "tok_bypassPending", //チャージ後即座に送金可能にする。本当ならカードのtok情報
          description: '支払い',
          transfer_group: "ORDER1", //最終的にこの値を使って出品者(子アカウント)へお金を送金する
        },
        function(err, charge) {
          console.log("エラー");
          console.log(err);

          console.log("チャージ");
          console.log(charge);
        }
      );

で、これでチャージすると、本番環境の場合、四日後に送金可能になります。

それで、プラットフォーム内でサービスが完結し、出品者(子アカウント)へお金を送金したい場合は、

こうします↓

      stripe.transfers.create(
        {
          amount: 100, //今回は送金可能金額1000円から100円だけ送金する
          currency: 'jpy',
          destination: "ここに子アカウントのid",
          transfer_group: 'ORDER1', //ここの値を使って出金可能金額から送金する
        },
        function(err, transfer) {
          console.log("transfer");
          console.log(transfer);

          console.log("err");
          console.log(err);
        }
      );

これでOkです。

実際にプラットフォームからお金が引かれてることを確認する

curl https://api.stripe.com/v1/balance \
  -u sk_test_OOOOOOOOOOOO:

これをターミナルとかに打ち込んでください。

すると、こんな感じで情報が出ます。

% curl https://api.stripe.com/v1/balance \
  -u sk_test_OOOOOOOOOOOO:
{
  "object": "balance",
  "available": [
    {
      "amount":900,
      "currency": "jpy",
      "source_types": {
        "card": 900
      }
    }
  ],
  "connect_reserved": [
    {
      "amount": 0,
      "currency": "jpy"
    }
  ],
  "livemode": false,
  "pending": [
    {
      "amount": 0,
      "currency": "jpy",
      "source_types": {
        "card": 0
      }
    }
  ]
}

クレカでチャージして決済した時、プラットフォームにお金が振り込まれますが、それで、四日後にここが反映されます。→"available": [

それで、transfersしてtransfer_group指定した金額がavailableだった場合、お金を子アカウントに送金できます。

以上。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【感想】Vue.js & FirebaseでTwitterライクなSNSアプリを作ろう

はじめに

※有料です。

開発環境

  • Vue.js

  • Node.js

  • Firebase

今回作ったもの

  • Twitterのようにユーザーが投稿できるSNSのようなものを実装しました。
    SNS.PNG

  • 教材の通りにデプロイまで完了しています。

感想

  • Googleアカウントでのサインイン
  • 投稿の新規作成、リスト表示、更新、削除です。

上記の2点が機能として今回この教材で実装でき、それらについて学ぶことが出来ます。
要するにCRUDの実装とGoogleアカウントを用いたユーザー登録ですね。

個人的にはこういう個人開発に近しいものを「いざ作ろう!」となっても開発するのってすごくハードルが高いと思っていて、このようなアプリが教材形式で学ぶことが出来るのは最近始めた初学者の方や今回だとフロント周りを軽くしか触っていない自分とかにはハードルが下がってとても良いと思うんですよね。

開発の流れやこの機能を実装するにはどうしたらいいだろう?とか考えたり、その教材で使用する技術について勉強になりますし良いことしかないと思います。

正直な話自分がプログラミングを勉強し始めた時ぐらいにこういう教材などがあって気軽に学べてデプロイまでできるような環境があったらもっとフロント周りをゴリゴリやって開発していた気がします。(笑)

今からでも全然遅くないとは思っていますが。(笑)

教材を作って頂いた製作者の方やこのサイトを運営されてる方に見られるか分かりませんが、このような環境と教材を提供していただいて感謝しています。

最後に

自分は普段はインフラ・クラウド・セキュリティの方面を主に勉強していてフロント周りは軽く触ったことがあるくらいだったのですが、特に問題もなく教材通りに学びながら1日かからずにデプロイまで出来ました。(普通は時間をかけてゆっくりやるものだと思いますが、自分はサクサクやっていたのであまり参考にはならないかもしれません。)

今後もTechpitで学んだことを感想としてアウトプットしたり、自分が普段やってる方面のことなどをアウトプットしていきたいと思っています。

暇な時に流し読みでも記事を読んでいただけたらと思っています。(笑)

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

FirebaseからGoogleSpreadSheetに書き込みをし、その更新をメール通知する

はじめに

当記事は、FirebaseのCloudFunctionからGoogleSpreadSheetにFirestoreへ新規追加されたデータ内容の書き込みをし、その更新をメール通知する実装についての備忘録です。

CloudFunctionの導入は省略しますが、宜しければこちらを参考にしてください。

FirebaseからGoogeleSpreadSheetに書き込みを行う

大まかな手順
・FIrebaseの設定
・GoogeleSpreadSheet APIの取得
・CloudFunctionの実行

FIrebaseの設定

FirebaseからGoogleSpreadSheetに書き込みを許可するために、
幾つかデフォルトの設定から変更をする必要があります。

①Firebaseコンソールから「プロジェクトの設定」(歯車のボタン)をクリック

②「サービスアカウント」のタブをクリック

③その他のサービスアカウントの項にある、Googleサービスアカウントへのリンクをクリック

④名前の項が「App Engine default service account」のタブの、プロジェクトID@appspot.gserviceaccount.com をコピー

⑤書き込みたいスプレッドシートを開き、右上の「共有」ボタンをクリックして表示されたダイアログの「ユーザーやグループを追加」に先ほどコピーした、プロジェクトID@appspot.gserviceaccount.com を入力

GoogeleSpreadSheet APIの取得

①GoogleCloudPlatformのナビゲージョンメニュー(左上のハンバーガーボタン)から「APIとサービスをクリック」

②ヘッダーの検索欄から「Google Sheets API」を探し、利用するプロジェクト名と一致しているか確認した上で、APIを有効にします

CloudFunctionの実行

①プロジェクトの「functions」のディレクトリへ移動
※以上のディレクトリからのみ、CloudFunctionはデプロイ出来ます

②ターミナルで「googleapis」をnpm install

$ npm install googleapis

②index.jsにコードを書いていく

index.js
const functions = require("firebase-functions");
//npm installしたgoogleAPIを宣言
const googleAPI = require("googleapis");

exports.appendSpreadSheet = functions
  .region("asia-northeast1")
  //この実装では、Cloud Firestoreの「hoge」というコレクションに値が追加されたら、スプレッドシートに書き込みをします
  .firestore.document("hoge/{hogeId}")
  .onCreate((snap, context) => {
    const foo = snap.data();
    googleAPI.auth
      .getClient({
        scopes: ["https://www.googleapis.com/auth/spreadsheets"],
      })
      .then((auth) => {
        const sheets = google.sheets("v4");
        sheets.spreadsheets.values.append({
          auth,
         //シートのURLの https://docs.google.com/spreadsheets/Idはここの部分/edit#gid=0
          spreadsheetId: "xxxxxxxxx",
          //書き込み先のシート名
          range: "書き込むシートの名前",
          //セル範囲
          //公式を参照→ https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/append?hl=ja#InsertDataOption
          valueInputOption: "RAW",
          insertDataOption: "INSERT_ROWS",
          resource: {
            values: [
              [
                //ドキュメントキー
                hoge.hogeId,
                //書き込みたいドキュメントの中身
                foo.name,
                foo.age,
              ],
            ],
          },
        });
      });
  });

以上を記述した後、functionをデプロイすることで、
任意のデータベースに値が追加(あるいは変更などでも実装可能)される度に、スプレッドシートにデータの書き込みがされます。

メール通知を加える

大まかな手順
・Gmailのセキュリティーレベルを下げる
・nodemailerのnpm install
・環境変数の設定
・CloudFunctionの実行

Gmailのセキュリティーレベルを下げる

①Googleアカウント内の安全性の低いアプリのアクセスにて、安全性の低いアプリの許可:有効にする。

②メール送受信に利用するGoogleアカウントでログインした上で、Gmailアカウントへのアクセス許可する。

nodemailerのnpm install

①ターミナルで「nodemailer」をnpm install

$ npm install nodemailer

環境変数の設定

①ターミナルで下記コマンドを打つ

firebase functions:config:set gmail.email="xxxxxxxxxx@gmail.com" gmail.password="xxxxxxxxxx"

以上を設定することで、安全にメールアドレスとパスワードをファイル上で変数定義出来ます。(この例の場合、emailならば、functions.config().gmail.emailで呼び出し)

CloudFunctionの実行

①index.jsに追記

index.js
const functions = require("firebase-functions");
const googleAPI = require("googleapis");
//npm installしたnodemailerと環境変数内のアドレスとパスワードを宣言
const nodemailer = require("nodemailer");
const gmailEmail = functions.config().gmail.email;
const gmailPassword = functions.config().gmail.password;
//送信するGmailアドレスの設定
const mailTransport = nodemailer.createTransport({
  host: "smtp.gmail.com",
  port: 465,
  secure: true,
  auth: {
    user: gmailEmail,
    pass: gmailPassword
  }
});

exports.appendSpreadSheet = functions
  .region("asia-northeast1")
  //この実装では、Cloud Firestoreの「hoge」というコレクションに値が追加されたら、スプレッドシートに書き込みをします
  .firestore.document("hoge/{hogeId}")
  .onCreate((snap, context) => {
    const foo = snap.data();
    googleAPI.auth
      .getClient({
        scopes: ["https://www.googleapis.com/auth/spreadsheets"],
      })
      .then((auth) => {
        const sheets = google.sheets("v4");
        sheets.spreadsheets.values.append({
          auth,
          spreadsheetId: "xxxxxxxxx",
          range: "書き込むシートの名前",
          valueInputOption: "RAW",
          insertDataOption: "INSERT_ROWS",
          resource: {
            values: [
              [
                //ドキュメントキー
                hoge.hogeId,
                //書き込みたいドキュメントの中身
                foo.name,
                foo.age,
              ],
            ],
          },
        });
      }).then(() => {
        let mailOptions = {
          from: gmailEmail,
          to: gmailEmail,
          subject: "メールタイトル",
          text: "メール本文"
        };
        mailTransport.sendMail(mailOptions, (err, info) => {
          if (err) {
            console.error(err);
            return;
          }
          console.log("success");
        });
      });
  });

以上、追記した内容をデプロイ後、Firestoreに値が追加される度に、メール通知がされます。
もしメールが届かない場合はCloudFunctionのログを読んだ上で、Googleアカウントのセキュリティのブロックを疑ってみると良いかもしれません。

おわりに

私が所属するチームは少数なので、作業を自動化することで、ヒューマンエラーを減らしたり、捻出した時間を他の作業に割けるのでとても助かりました。

こちらの記事を参考にさせていただきました。ありがとうございます!
スプレッドシートとの連携 
メールの送信 
Gmailのセキュリティ

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む