- 投稿日:2020-07-04T22:34:56+09:00
curlを使ってjavascriptを有効にした場合のhtmlソースを取得する
domcurlというツールがあります。webscrapingに非常に便利なツールです。
phantomjs
などで要件を満たせない場合におすすめです。domcurlはPuppeteerを使う小さなNodeJSアプリケーションで、 npm i domcurlコマンドを発行することでインストールできます。 curlコマンドのように、簡単なdomcurl [url]を発行してリソースを取得し、JSをページ上で実行することができます。
$ npm i domcurl $ ./node_modules/domcurl/index.js --url https://example.com
- 投稿日:2020-07-04T22:21:12+09:00
コマンドラインから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 --versionset.jsvar 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
- 投稿日:2020-07-04T20:30:51+09:00
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
を打ち込むと解決できました。おそらく前に他のパッケージをインストールする時にパスを弄ったのが原因ではないかと思っています。
- 投稿日:2020-07-04T17:37:20+09:00
webpack.config.js の書き方をしっかり理解しよう
webpack.config.js
僕の中で少し苦手なイメージのある
webpack
について、改めて向き合って理解していこうと思います。
webpack
に苦手意識がある人のほとんどは、このwebpack.config.js
について理解していない人がほとんど。なので、今回は下記のwebpack.config.js
について丁寧に説明していきます。webpack.config.jsconst 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 ] }
entry
とoutput
結論から言うと、
entry:
は、webpackがビルドする際に開始点となるJSファイルを設定しています。
output:
は、ビルドファイルの設定。どこにどのようなファイルを出力すればよいか設定しています。具体的にみていきます。
webpack.config.jsconst 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
として使用できています。
__dirname
はNode.js
で用意されているグローバル変数で、現在実行中のソースコードが格納されているディレクトリパスが格納されています。簡単に言うと、手軽に絶対パスの記述ができるものです。
output
の設定
path:
とfilename:
がありますね。こちらも結論から言うと
path:
は、どのディレクトリに出力するか指定しています。
filename:
は、どのファイルに出力するか指定しています。なので、
「./src
というディレクトリ内のmain.js
というファイルに出力してね。」という設定をしています。
devtool
まず、結論です。
devtool:
を設定することによって、ソースマッピングのスタイルを選択して、デバッグプロセスを強化します。指定可能な値はstring
とfalse
です。
(参照:公式ドキュメントの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 ではmodule
はJavaScript
やCSS
などのファイルを指す。
ここでは、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
(JavaScript
やCSS
など)を設定するってことです。
今回で言うと、拡張子が.js
なので、test: /.js$/
と設定しています。このまま一気に説明した方が理解がしやすいと思うので、一気に説明していきます。
Rule.loader
この2つですが、簡単にいうと
まずloader: 'babel-loader'
と設定することで、test: /.js$/
で設定したjsファイル
を'babel-loader'
として読み込む設定をしています。
plugins
最後
plugins:
です。
pluginsオプションは、さまざまな方法でwebpackビルドプロセスをカスタマイズするために使用されます。externalPlugins
というプラグインがカスタマイズされています。公式ドキュメントによると、
webpackには豊富なプラグインインターフェイスがあります。 webpack自体のほとんどの機能は、このプラグインインターフェイスを使用します。これにより、Webpackが柔軟になります。最後
最後の方は駆け足で説明することになりましたが、少しでも理解の手助けになれば幸いです。
こんなことを最後にいうことではありませんが、webpackについては公式ドキュメントに結構丁寧に説明が書いてあるので、そこをみれば理解できるかと思います。何か間違い等ありましたら教えていただけると幸いです。
- 投稿日:2020-07-04T16:50:34+09:00
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 になっています!
ちなみに、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.js2020年7月4日現在、こちらも v1.1.0 がインストールされました。
この方法で実行すると、必要なファイルが同じフォルダ内に揃うため、不要になったらフォルダを丸ごと削除するだけでお掃除が完了します。新要素を確認してみる
Version 1.1 released ブログを参照しつつ、新要素を確認しましたので、ざっくり翻訳と一緒にメモを残しておきます。
エディターの更新
情報サイドバーの再設計
情報サイドバーには、フローのツリービューが含まれています。これをアウトライナーと呼びます。フローをナビゲートして、すばやく要素を見つける別の方法を提供します。
各ノードには、ワークスペースでノードに移動するためのボタン、ノードを有効/無効にするためのボタンがあります。また Inject および Debug ノードの場合は、それらのアクションをトリガーするためのボタンもあります。ノードをダブルクリックすると、編集ダイアログが表示されます。詳細 (英語) を参照してください。
新しいヘルプ サイドバー
アウトライナーのためのスペースを作るため、サイドバーのヘルプ セクションが独自のサイドバータブに移動しました。ヘルプを独自のタブに配置することで、ワークスペースで適切なタイプのノードを選択しなくても、使用可能なすべてのヘルプトピックを参照できるようになりました。
また、将来エディターに、他のヘルプトピックを追加するスペースも提供します。
詳細 (英語) を参照してください。
ノードのグループ化
フローを整理するために、エディターでノードをグループ化できます。
グループには、カスタムの境界線と背景色、およびオプションのラベルを付けることができます。
グループは新しいタイプのノードとしてフローに追加されます。ユーザーがこの機能を使用し始めると、まだアップグレードしていないユーザーとフローを共有することが難しくなります。これを助けるため、グループノード タイプを登録するがまったく何もしない 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 ローカル環境での実行例がこちら:
詳細 (英語) を参照してください。個別の設定の上書き
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 ノードは、送信するメッセージに任意のプロパティを設定できるようになりました。
topic
とpayload
だけに限定されません。
Function ノードのライフサイクル
Function ノードでは、ノードのデプロイ時と停止時に実行する必要のあるコードを提供できるようになりました。 これにより、メッセージの処理を開始する前にノードの状態を初期化できます。
コードの各部分は別々のスコープにあることに注意してください。どれかの中で変数を宣言して、他からアクセスすることはできません。それらの間で情報を共有するには、コンテキストを使用する 必要があります。メイン関数も非同期になっているので、トップレベルで await を使用できます。
Debug ノードのステータス
Debug ノードは、Debug サイドバーに何を渡すかに関係なく、ステータスメッセージを設定できるようになりました。スペースのあるサイドバーに完全な情報を表示しながら、ステータスの短い要約をデバッグする場合に役立ちます。
デバッグノードについて補足ですが、多数のノードを一度にアクティブ化/非アクティブ化できるように、エディターにいくつかのアクションを追加しました。アクションリスト (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
トリガーノード
トリガーノードは、オプションで別の出力に「2番目のメッセージ」を送信できるようになりました。
メッセージの個別のストリームを処理する場合、msg.topic
を使用してストリームを識別する必要がなくなります。任意のメッセージプロパティを使用できます。というわけで
Node-RED どんどん使いやすく改良されていく感じで、良いですね!更新された機能、実際にいろいろ試してみたいと思っています。
それではまた!
- 投稿日:2020-07-04T16:35:10+09:00
Node.js 依存モジュールのファイルはケースセンシティブの件
皆さん開発の時ほとんど macOS を使ってるんでしょうか、だが macOS のファイル名はケースインセンシティブ(大小文字は区別しない)。つまり同じフォルダ下に
package.json
とpackagE.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 foundoption に何度も確認しまして確かにスキーマは入ってるが。
どうしようと思って、 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#L936Node.js の require は一回しか実行しない、その原因は Node.js はモジュールをメモリに保存して、その後コードの中で require したらすぐ使えるという意図で設計されました。
ソースコードからも見えて、Node.js はファイル名でキャッシュしますが、ここの filename は require のファイル名 + 絶対パス。なので Node.js は2つモジュールとみなすが、windows だと、 filename は path.resolve で toLowerCase で同じファイル名にするが、Linux だとケースセンシティブでモジュール見つからないで弾かれますが、この問題は macOS しか出ませんね。
ま、デプロイまで問題出るよりラッキーですね。
- 投稿日:2020-07-04T14:13:01+09:00
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:$PATHterminalルートディレクトリにて $source .bash_profile $which node /Users/macuser/.nodebrew/current/bin/node ←nodebrewが適用されている $node -v v12.18.2できた!!
- 投稿日:2020-07-04T13:54:21+09:00
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 したい、現場からお送りしました。
参考情報
- 投稿日:2020-07-04T12:24:59+09:00
npm runでCannot find module '@babel/compat-data/corejs3-shipped-proposals'のエラー
npm updateで解決。