20200704のNode.jsに関する記事は9件です。

curlを使ってjavascriptを有効にした場合のhtmlソースを取得する

domcurlというツールがあります。webscrapingに非常に便利なツールです。phantomjsなどで要件を満たせない場合におすすめです。

domcurlはPuppeteerを使う小さなNodeJSアプリケーションで、 npm i domcurlコマンドを発行することでインストールできます。 curlコマンドのように、簡単なdomcurl [url]を発行してリソースを取得し、JSをページ上で実行することができます。

https://paul.kinlan.me/domcurl/

$ npm i domcurl
$ ./node_modules/domcurl/index.js  --url https://example.com
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

コマンドラインからjavascriptでレンダリングされたHTMLソースを取得する方法

curlからは、javascriptを有効にしたブラウザと同じHTMLソースを取得することが難しいことがあります。このような場合、phantomjsを使用すると便利です。

$ npm i -g phantomjs phantom

公式サイトにてバイナリも配布されてるので、nodeからのインストールが依存関係などで失敗する場合、こちらをダウンロード、解凍して実行権限を与えると良いでしょう。

https://phantomjs.org/download.html

$ curl -sLO https://bitbucket.org/ariya/phantomjs/downloads/phantomjs-2.1.1-linux-x86_64.tar.bz2
$ aunpack phantomjs-2.1.1-linux-x86_64.tar.bz2
$ cd phantomjs-2.1.1-linux-x86_64/bin/
$ chmod +x phantomjs
$ ./phantomjs --version
set.js
var system = require('system');
var page   = require('webpage').create();argument
var url    = system.args[1];
page.open(url, function () {
  console.log(page.content);
  phantom.exit();
});
$ phantomjs set.js https://google.com
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

npm ERR! code ELOOP が出たときの対処法

npm install を使った時に

npm WARN checkPermissions Missing write access to /Users/[ユーザー名]/node_modules/[ファイル名]
npm WARN [ユーザー名]@1.0.0 No description
npm WARN [ユーザー名]@1.0.0 No repository field.
npm ERR! code ELOOP

というエラーが出現してハマりました。これを仮説で解決できたので同じエラーでハマった方向けに書いておきます。

まず一番上にnpm WARN checkPermissions Missing write access to /Users/[ユーザー名]/node_modules/[ファイル名]

と書いてあります。

この意味は「ファイルにアクセスできない」という意味です。

この理由として考えられるのは

①ファイルへのアクセス権が無い
②ファイルそのものが無い
③ファイルパスがおかしい

のどれかです。

①の場合の対処法は公式にも書いてあります。

https://docs.npmjs.com/resolving-eacces-permissions-errors-when-installing-packages-globally

ただこれはエラーコードが違いますし、実際にやってみても治りませんでした。

②の場合はファイルをどうにかして追加できれば治りそうですが、この場合ではインストールそのものができないので解決は無理です。

そこで、Node.jsを一旦全て削除することにしました。(パスを書き換えるだけで解決できそうでしたが、ファイルの場所がよく分からないのと確実に治すためにそうしました。)

/Users/[ユーザー名]/node_modules/[ファイル名]
に関連するファイルを全て削除しました。

具体的には

.npm-global
.nodebrew
.npmrc
.zprofile
.node-modules

の5つです。

さらに、
https://qiita.com/gaipoi/items/406d6c4b1ccd1733318a
に従ってNode.jsを全て削除しました。

その後インストーラーでNode.jsを再インストール。

最後にターミナルで
export NODE_PATH=/usr/local/lib/node_modules
を打ち込むと解決できました。

おそらく前に他のパッケージをインストールする時にパスを弄ったのが原因ではないかと思っています。

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

webpack.config.js の書き方をしっかり理解しよう

webpack.config.js

僕の中で少し苦手なイメージのあるwebpackについて、改めて向き合って理解していこうと思います。
webpackに苦手意識がある人のほとんどは、このwebpack.config.jsについて理解していない人がほとんど。なので、今回は下記のwebpack.config.jsについて丁寧に説明していきます。

webpack.config.js
const path = require('path')
const webpack = require('webpack')

module.exports = {
  entry: {
    index: path.join(__dirname, 'src', 'index.js')
  },
  output: {
    path: path.join(__dirname, 'out'),
    filename: 'main.js'
  },
  devtool: 'cheap-module-eval-source-map',
  target: 'node',
  module: {
    rules: [
      {
        test: /.js$/,
        loader: 'babel-loader'
      }
    ]
  },
  plugins: [
    externalPlugins
  ]
}

entryoutput

結論から言うと、
entry:は、webpackがビルドする際に開始点となるJSファイルを設定しています。
output:は、ビルドファイルの設定。どこにどのようなファイルを出力すればよいか設定しています。

具体的にみていきます。

webpack.config.js
const path = require('path')
const webpack = require('webpack')

module.exports = {
  entry: {
    index: path.join(__dirname, 'src', 'index.js')
  },
  output: {
    path: path.join(__dirname, 'out'),
    filename: 'main.js'
  },
...
}

entryの設定

早速説明していきます。
簡単に理解できますので、安心してください(笑)

ここでは、webpackがビルドした際に
./src/index.jsというファイルを探して読み込んでね。」という設定をしています。

まずpath.joinでパスを連結してくれていて、上記だと./src/index.jsというパスにしてくれています。

これを使うメリットとしては、
macやwindowsなどの開発環境によって/¥になったりするんですけど、それを防ぐことができます。
そしてNode.jsの標準モジュールのpathを読み込ませて使用しているので、path.joinとして使用できています。

__dirnameNode.jsで用意されているグローバル変数で、現在実行中のソースコードが格納されているディレクトリパスが格納されています。簡単に言うと、手軽に絶対パスの記述ができるものです。

outputの設定

path:filename:がありますね。

こちらも結論から言うと
path:は、どのディレクトリに出力するか指定しています。
filename:は、どのファイルに出力するか指定しています。

なので、
./srcというディレクトリ内のmain.jsというファイルに出力してね。」という設定をしています。

devtool

まず、結論です。
devtool:を設定することによって、ソースマッピングのスタイルを選択して、デバッグプロセスを強化します。指定可能な値はstringfalseです。
(参照:公式ドキュメントのdevtool

分からない用語が出てきた?ソースマッピングですかね?

分からなければ、しっかり調べていきましょう。

ソースマップについて

ソースマップとは、Babelなどトランスパイル後と前のコードの内容を紐付けしてデバッグしやするするもの。

トランスパイルについて
JavaSciprtではwebpackでコンパイルなどをする時に同時にトランスパイルという処理を行います。
具体的に何をしているのかというと、互換性のあるコードに変換をする処理。
(例)「CoffeeScriptとかを記載して、Javascriptへトランスパイルする。」みたいな感じです。
一般的にはBabelというライブラリを使います。

devtool: 'cheap-module-eval-source-map'

まとめると、ここでは'cheap-module-eval-source-map'を設定しており、公式ドキュメントによると、ビルドと再ビルトの処理速度としては遅めに処理されるようです。

webpack.config.js
...
module.exports = {
...
  devtool: 'cheap-module-eval-source-map',
...
}

target

結論から言うと、
target:を設定することによって、特定の環境をターゲットにするようにwebpackに指示してくれます。ここでは、'node'と設定しているので、Node.jsのような環境で使用するためにコンパイルしてます。

webpack.config.js
...
module.exports = {
...
  target: 'node',
...
}

module

module:オプションは、プロジェクト内のさまざまなタイプのモジュールがどのように処理されるかを設定しています。「webpack が特定のmoduleをどう扱うか」を決めるってことです。webpack ではmoduleJavaScriptCSSなどのファイルを指す。
ここでは、Ruleモジュールについて設定されているので、詳しくみていきます。

webpack.config.js
...
module.exports = {
...
  module: {
    rules: [
      {
        test: /.js$/,
        loader: 'babel-loader'
      }
    ]
  },
...
}

Rule

まず結論から、
rule:を設定すると、「条件」、「結果」、「ネスト」されたルール3つの部分に分けることができます。

Rule.test

公式ドキュメントによると、テストアサーションに合格したすべてのモジュールを含めます。 Rule.testオプションを指定した場合、Rule.resourceも指定できません。
と書いてありましたが、ちょっと「??」のままでした。

いろいろ調べてみた結果を簡単にいうと、
Rule.testで拡張子を設定する」というイメージです。
webpackでいうmodule(JavaScriptCSSなど)を設定するってことです。
今回で言うと、拡張子が.jsなので、test: /.js$/と設定しています。

このまま一気に説明した方が理解がしやすいと思うので、一気に説明していきます。

Rule.loader

この2つですが、簡単にいうと
まずloader: 'babel-loader'と設定することで、test: /.js$/で設定したjsファイル'babel-loader'として読み込む設定をしています。

plugins

最後plugins:です。
pluginsオプションは、さまざまな方法でwebpackビルドプロセスをカスタマイズするために使用されます。externalPluginsというプラグインがカスタマイズされています。

公式ドキュメントによると、
webpackには豊富なプラグインインターフェイスがあります。 webpack自体のほとんどの機能は、このプラグインインターフェイスを使用します。これにより、Webpackが柔軟になります。

最後

最後の方は駆け足で説明することになりましたが、少しでも理解の手助けになれば幸いです。
こんなことを最後にいうことではありませんが、webpackについては公式ドキュメントに結構丁寧に説明が書いてあるので、そこをみれば理解できるかと思います。

何か間違い等ありましたら教えていただけると幸いです。

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

Node-RED Version1.1 の更新まとめ (1.1 released ブログのざっくり翻訳)

Node-RED Version 1.1 released されましたね!更新内容をざっくり翻訳して実際に眺めてみましたので、簡単にまとめておきます。

Node-RED v1.1 環境を用意する

Node-RED をちょっと試したい場合、IBM Cloud の無料スターターキットか、ローカルでのフォルダを指定したインストールがお勧めです。

IBM Cloud でサービス作成してみる

IBM Cloud では無料のライトプランで Node-RED 環境を構築できるので、新規に再作成してみました。2020年7月4日現在、v1.1.0 になっています!
image.png
ちなみに、Node-RED スターターキットの作成方法が変わって、アプリ作成とデプロイなどを別に実施する必要があって、お手軽感がだいぶ薄まった気がします。でもまぁ、無料で使える環境であることは変わらないので、今後ともお世話になるとは思います。

ローカルでサービス作成してみる

ローカルで試したい場合は、こちらのページ を参考に、数分あればお試し環境を用意できます。Windows の場合ですが以下のように実行しました:

md node-red-test
cd node-red-test
npm init -y
npm install --unsafe-perm --save node-red
md .node-red
echo 2> .node-red/settings.js
node_modules\.bin\node-red -u .node-red -s .node-red/settings.js

2020年7月4日現在、こちらも v1.1.0 がインストールされました。
image.png
この方法で実行すると、必要なファイルが同じフォルダ内に揃うため、不要になったらフォルダを丸ごと削除するだけでお掃除が完了します。

新要素を確認してみる

Version 1.1 released ブログを参照しつつ、新要素を確認しましたので、ざっくり翻訳と一緒にメモを残しておきます。

エディターの更新

情報サイドバーの再設計

情報サイドバーには、フローのツリービューが含まれています。これをアウトライナーと呼びます。フローをナビゲートして、すばやく要素を見つける別の方法を提供します。
image.png
各ノードには、ワークスペースでノードに移動するためのボタン、ノードを有効/無効にするためのボタンがあります。また Inject および Debug ノードの場合は、それらのアクションをトリガーするためのボタンもあります。ノードをダブルクリックすると、編集ダイアログが表示されます。

詳細 (英語) を参照してください。

新しいヘルプ サイドバー

アウトライナーのためのスペースを作るため、サイドバーのヘルプ セクションが独自のサイドバータブに移動しました。ヘルプを独自のタブに配置することで、ワークスペースで適切なタイプのノードを選択しなくても、使用可能なすべてのヘルプトピックを参照できるようになりました。
image.png
また、将来エディターに、他のヘルプトピックを追加するスペースも提供します。
image.png

詳細 (英語) を参照してください。

ノードのグループ化

フローを整理するために、エディターでノードをグループ化できます。
image.png
グループには、カスタムの境界線と背景色、およびオプションのラベルを付けることができます。
image.png
グループは新しいタイプのノードとしてフローに追加されます。ユーザーがこの機能を使用し始めると、まだアップグレードしていないユーザーとフローを共有することが難しくなります。

これを助けるため、グループノード タイプを登録するがまったく何もしない node-red-node-group を公開しました。このモジュールをインストールすると、Node-RED の古いバージョンがグループを含むフローをインポートできるようになりますが、エディターにグループは表示されません。また、モジュールは必要のないときには登録されないため、インストールしたままで 1.1 にアップグレードしても問題はありません。

詳細 (英語) を参照してください。

ランタイム機能

node-red-admin ビルトイン

node-red-admin コマンドラインツールは、プロジェクトの開始時から存在していますが、あまり知られていませんでした。Node-RED ランタイムをリモートで管理するため使用できます。

より便利に使えるよう、この機能は node-red コマンドに統合されました。以下のように実行します:

node-red admin

この機能で提供される便利なコマンドの1つは、adminAuth のためパスワードをハッシュするものです。使用するパスワードの入力を求められ、設定ファイルに貼り付けることができるハッシュが返されます。

$ node-red admin hash-pw

Windows ローカル環境での実行例がこちら:
image.png
詳細 (英語) を参照してください。

個別の設定の上書き

node-red コマンドは、個々の設定を上書きする -D オプションをサポートするようになりました。例えば異なるレベルのロギングで一時的に実行するには、次のように指定します:

node-red -D logging.console.level=trace

詳細 (英語) を参照してください。

httpAdminMiddleware 設定

少し前に httpNodeMiddleware オプションが追加され、カスタムミドルウェアをHTTP入力ノードルートに追加できるようになりました。詳細はこちら。今回のリリースで、エディター自体を含むすべての管理ルートに対して同じことを行う httpAdminMiddleware を追加します。

これは例えば、すべての管理リクエストにカスタム http ヘッダーを追加するため使用できます。ほとんどのエンドユーザーが必要とするものではありませんが、独自のアプリケーションにエディターを埋め込むユーザーのための機能です。

詳細 (英語) を参照してください。

カスタムadminAuthトークンの処理

adminAuth は、admin api に渡された認証トークンの検証に使用できる、カスタムトークン関数をサポートするようになりました。これにより、Node-RED 管理セキュリティを他の認証システムと統合するため、いくつかのより柔軟なオプションを利用できます。

詳細 (英語) を参照してください。

他の場所からのノードのインストール

新しいノードをインストールするための管理 API が拡張され、「url」パラメータをサポートするようになりました。これは、インストールするノードを含む tgz ファイルへの完全な URL である必要があります。

これはまだドキュメントに記載されていませんので、現時点では、元のデザインノートを参照してください。

HTTPS証明書の更新

https 証明書を定期的に更新するようにランタイムを構成できます。この機能の利用には、Node.js 12以降が必要です。

デフォルト設定ファイルは、この構成に関するサンプルを含んでいます。

詳細 (英語) を参照してください。

ノードの更新

JSONata $moment のサポート

$moment 関数により、JSONata 式内のモーメント日付/時間ライブラリのサポートを追加しました。

これにより、Node-RED のコアに、以前から要望のあったタイムゾーン認識が追加されます。例えば次の式でオークランドの現在の時刻を取得できます:

$moment().tz("Pacific/Auckland")

2時間後の時刻を取得したい場合は、次のように記述できます:

$moment().add(2, "hours")

また日付の解析で、より良い処理ができます:

$moment($.payload, "YYYY-MM-DD")

Moment ライブラリを Function ノードのデフォルトの組み込みとして利用可能にすることも検討していますが、これは将来のリリースで対応予定です。

※ JSONata に関しては、以前に 言語ガイドを翻訳 しましたので、ご参照ください

ノードのプロパティを挿入する

Inject ノードは、送信するメッセージに任意のプロパティを設定できるようになりました。topicpayload だけに限定されません。
image.png

Function ノードのライフサイクル

Function ノードでは、ノードのデプロイ時と停止時に実行する必要のあるコードを提供できるようになりました。 これにより、メッセージの処理を開始する前にノードの状態を初期化できます。
image.png
コードの各部分は別々のスコープにあることに注意してください。どれかの中で変数を宣言して、他からアクセスすることはできません。それらの間で情報を共有するには、コンテキストを使用する 必要があります。

メイン関数も非同期になっているので、トップレベルで await を使用できます。

Debug ノードのステータス

Debug ノードは、Debug サイドバーに何を渡すかに関係なく、ステータスメッセージを設定できるようになりました。スペースのあるサイドバーに完全な情報を表示しながら、ステータスの短い要約をデバッグする場合に役立ちます。
image.png
デバッグノードについて補足ですが、多数のノードを一度にアクティブ化/非アクティブ化できるように、エディターにいくつかのアクションを追加しました。

アクションリスト (Ctrl / Cmd-Shift-Pまたは表示->動作一覧) でそれらを検索し、キーボードショートカットを割り当てることができます。

  • core:activate-selected-debug-nodes
  • core:activate-all-debug-nodes
  • core:activate-all-flow-debug-nodes
  • core:deactivate-selected-debug-nodes
  • core:deactivate-all-debug-nodes
  • core:deactivate-all-flow-debug-nodes

image.png

トリガーノード

トリガーノードは、オプションで別の出力に「2番目のメッセージ」を送信できるようになりました。
image.png
メッセージの個別のストリームを処理する場合、msg.topic を使用してストリームを識別する必要がなくなります。任意のメッセージプロパティを使用できます。

というわけで

Node-RED どんどん使いやすく改良されていく感じで、良いですね!更新された機能、実際にいろいろ試してみたいと思っています。

それではまた!

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

Node.js 依存モジュールのファイルはケースセンシティブの件

皆さん開発の時ほとんど macOS を使ってるんでしょうか、だが macOS のファイル名はケースインセンシティブ(大小文字は区別しない)。つまり同じフォルダ下に package.jsonpackagE.json は一緒にいられない。

ほとんどの人は知ってるかにもかかわらず、あまりこれに注意を払ってないのではないかなと思って、だってみんなの母語は英語ではないし、インポートの際は intelliSense も結構賢く補足してもらってるので、あんまりここに転んだことはないと思います。転んでもすぐ忘れるんだろう。

よく会った問題はこれです?

Linux でデプロイ時にモジュールは見つからない

多分誰がメモ帳で書いたコード

const list = require('./List');

でも List のファイル名はlist.js

そしたらすべての List を list に変えなきゃいけない。

細かい点で解決には難しくないが、時間ちょっと無駄しましたね。

でも今日話したいのは僕の午後をまるごと無駄しましてこの技術的な内容あまりない記事を書くことになったこれです?

require('./a.js') !== require('./A.js')

TypeORM を使ってる時新しいスキーマ(テーブル)を入れたが、デバッグの時ずーとそのスキーマが見つからないエラーに怒られて

TypeORM EntityMetadataNotFound: No metadata for "***" was found

option に何度も確認しまして確かにスキーマは入ってるが。

どうしようと思って、 node_modules に入って直接ソースコードを改ざんしてデバッグすることになった。

console.log でスキーマはたしかに入ってますが、

https://github.com/typeorm/typeorm/blob/master/src/connection/Connection.ts

    /**
     * Gets entity metadata for the given entity class or schema name.
     */
    getMetadata(target: Function|EntitySchema<any>|string): EntityMetadata {
        const metadata = this.findMetadata(target);
        if (!metadata)
            throw new EntityMetadataNotFoundError(target);

        return metadata;
    }
    /**
     * Finds exist entity metadata by the given entity class, target name or table name.
     */
    protected findMetadata(target: Function|EntitySchema<any>|string): EntityMetadata|undefined {
        return this.entityMetadatas.find(metadata => {
            console.log(metadata.target, target, metadata.target === target) // ←ここ
            if (metadata.target === target)
                return true;
            if (target instanceof EntitySchema) {
                return metadata.name === target.options.name;
            }
            if (typeof target === "string") {
                if (target.indexOf(".") !== -1) {
                    return metadata.tablePath === target;
                } else {
                    return metadata.name === target || metadata.tableName === target;
                }
            }

            return false;
        });
    }

左と右は同じく Function xxx がリファレンスは同じではない。

これは事件ですね。んでファイル両方の import を一行一行で確認して、最終的に import のパスに問題を見つかった。
自分がインポートした際に、一つは Class 名をそのままコピペしたが、もう一つはファイル名でしたが、Class 名は PascalCase が、ファイル名は camelCase でした。

そしたらなぜ同じファイルで使う時ファイル名が違ったらリファレンスは違うになりますか?

Node.js のソースコードに見てきました。
https://github.com/nodejs/node/blob/master/lib/internal/modules/cjs/loader.js#L936

Node.js の require は一回しか実行しない、その原因は Node.js はモジュールをメモリに保存して、その後コードの中で require したらすぐ使えるという意図で設計されました。
ソースコードからも見えて、Node.js はファイル名でキャッシュしますが、ここの filename は require のファイル名 + 絶対パス。

なので Node.js は2つモジュールとみなすが、windows だと、 filename は path.resolve で toLowerCase で同じファイル名にするが、Linux だとケースセンシティブでモジュール見つからないで弾かれますが、この問題は macOS しか出ませんね。

ま、デプロイまで問題出るよりラッキーですね。

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

Node.jsのバージョンを切り替えてnode -vしてもバージョンが切り替わっていない!

Node.jsのバージョン切り替えで詰まった話。

バージョンを設定して、確認すると

terminal
$nodebrew use v12.18.2

$nodebrew ls
v10.16.3
v12.4.0
v12.18.2
v14.5.0

current: v12.18.2 // nodebrewでは選択されている

順調っ!

terminal
$node -v
v10.16.3

あれっ?設定されていない?
環境変数PATHに設定されているディレクトリを確認してみる。

terminal
$which node
/usr/local/bin/node ← Systemのnode
  • システムのnodeを参照していることが原因だった

解決法

環境変数を追加

/.bash_profile
...
export PATH=$HOME/.nodebrew/current/bin:$PATH
terminal
ルートディレクトリにて
$source .bash_profile

$which node
/Users/macuser/.nodebrew/current/bin/node ←nodebrewが適用されている

$node -v
v12.18.2

できた!!

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

Cloud Firestore で特定の collection のドキュメント全件数を count する方法

概要

Cloud Firestore で特定の collection のドキュメント全件数を count するサンプルコードをご紹介します。

前提知識: count() クエリは無い

まず、前提として Firestore には db.collection("users").count() みたいな count() クエリはありません。

結論: FieldValue.increment(1) を活用する

count() クエリが無いため、以下のように db.collection("users") のドキュメントが増減するタイミングで、ドキュメント全件数を管理する db.collection("counters") の値を FieldValue.increment() で増減させて、これでドキュメント全件数を管理します。

db.collection("counters").doc("user").update({ count: FieldValue.increment(1) })

サンプルコード: 特定 collection のドキュメント全件数 count

const admin = require("firebase-admin");
admin.initializeApp();
const db = admin.firestore();
const FieldValue = admin.firestore.FieldValue;

db.collection("users")
  .add({
    name: 'test'
  })
  .then(() => {
    return db
      .collection("counters")
      .doc("user")
      .update({ count: FieldValue.increment(1) })
      .finally(() => {
        return res.status(200).send("OK");
      });
  })
  .catch((err) => {
    console.error(err);
    return res.status(500).send("NG");
  });

以上、Cloud Firestore で特定の collection のドキュメント全件数を count したい、現場からお送りしました。

参考情報

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

npm runでCannot find module '@babel/compat-data/corejs3-shipped-proposals'のエラー

npm updateで解決。

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