COVID-19の封鎖により、私たちの多くは家に閉じ込められました。おそらく、単なるキャビン熱が私たちが経験する最悪の種類の熱であることを望んでいます。私たちの多くは、これまで以上に多くのビデオコンテンツを消費しています。現在、運動は特に重要ですが、ノートパソコンが手が届きにくいときに、古き良きリモコンの豪華さに懐かしさを感じることもあります。
そこで、このプロジェクトが登場します。更新がないために役に立たない古いスマートフォンであっても、次のNetflix / YouTube / Amazon PrimeVideoなどの便利なリモコンに変換する機会です。ビンジウォッチング。これはNode.jsバックエンドチュートリアルでもあります。ExpressフレームワークとPug(以前のJade)テンプレートエンジンを使用してバックエンドJavaScriptの基本を学ぶチャンスです。
それが気が遠くなるように聞こえるなら、完全な Node.js プロジェクトは最後に発表されます。読者は学習に興味がある分だけ学ぶ必要があり、経験豊富な読者がスキップできるように、いくつかの基本についてかなりの数の穏やかな説明があります。
読者は、「なぜNode.jsバックエンドのコーディングに取り掛かるのか」と疑問に思うかもしれません。 (もちろん、学習の機会は別として。)「そのためのアプリはもうありませんか?」
確かに、それらはたくさんあります。しかし、これが望ましくない可能性がある主な理由は2つあります。
これらの問題は長い間存在しており、GitHubで見つかった2014年の同様のプロジェクトの動機にもなりました。 nvm
Node.jsの古いバージョンを簡単にインストールでき、いくつかの依存関係をアップグレードする必要がある場合でも、Node.jsは下位互換性があるという高い評価を得ていました。
残念ながら、bitrotが勝ちました。頑固なアプローチとNode.jsバックエンドの互換性は、Grunt、Bower、およびその他の数十のコンポーネントの古いバージョン間での無限の非推奨と不可能な依存関係ループに匹敵しませんでした。数時間後、最初から始める方がはるかに簡単であることが明らかになりませんでした。この著者自身のアドバイスは 車輪の再発明 それにもかかわらず。
まず、このNode.jsプロジェクトは現在Linuxに固有であり、特にLinux Mint19とLinuxMint 19.3で開発およびテストされていますが、他のプラットフォームのサポートも確実に追加される可能性があることに注意してください。それ 五月 すでにMacで動作します。
の現代版を想定 Node.js がインストールされ、プロジェクトルートとして機能する新しいディレクトリでコマンドプロンプトが開かれると、Expressを開始する準備が整います。
npx express-generator --view=pug
注:ここでは、npx
は、Node.jsに同梱されているNode.jsパッケージマネージャーであるnpm
に付属している便利なツールです。 Expressのアプリケーションスケルトンジェネレーターを実行するために使用しています。この記事の執筆時点で、ジェネレーターはExpress / Node.jsプロジェクトを作成します。これは、Jadeプロジェクトであっても、デフォルトではJadeと呼ばれるテンプレートエンジンをプルします。 自分の名前を「パグ」に変更 バージョン2.0以降。そのため、最新の状態ですぐにPugを使用し、さらに非推奨の警告を回避するために、--view=pug
のコマンドラインオプションであるexpress-generator
を使用します。 npx
によって実行されているスクリプト。
それが完了したら、Node.jsプロジェクトの新しく入力された依存関係リストからいくつかのパッケージをpackage.json
にインストールする必要があります。これを行う従来の方法は、npm i
を実行することです。 (i
「インストール」の場合)。しかし、まだいくつかはの速度を好む 糸 、したがって、それがインストールされている場合は、yarn
を実行するだけです。パラメータなし。
この場合、(できればすぐに修正される)を無視しても安全です。 非推奨の警告 ローカルネットワーク上で必要に応じてアクセスが維持されている限り、Pugのサブ依存関係の1つから。
簡単なyarn start
またはnpm start
、その後に localhost:3000
に移動します ブラウザで、基本的なExpressベースのNode.jsバックエンドが機能することを示しています。 Ctrl+C
で殺すことができます。
とともに リモート すでに途中で終わったので、注意を向けましょう コントロール 部。 Node.jsバックエンドを実行するマシンをプログラムで制御し、キーボードのキーを押しているふりをすることができるものが必要です。
そのために、xdotool
をインストールしますを使用して その公式の指示 。ターミナルでのコマンド例の簡単なテスト:
xdotool search 'Mozilla Firefox' windowactivate --sync key --clearmodifiers ctrl+l
…MozillaFirefoxがその時点で開いていると仮定すると、それが言っていることを正確に実行する必要があります。それは良い!すぐにわかるように、Node.jsプロジェクトでxdotool
などのコマンドラインツールを呼び出すのは簡単です。
これはすべての人に当てはまるわけではありませんが、個人的には、最近の物理的なリモコンの多くには、これまでに使用するボタンの約5倍のボタンがあります。そのため、このプロジェクトでは、3 x 3のグリッドがあり、大きくてターゲットが簡単なボタンを備えたフルスクリーンレイアウトを検討しています。これらの9つのボタンが何であるかは個人の好み次第です。
最も単純な機能でさえ、キーボードショートカットは全体で同一ではないことが判明しました Netflix 、 Youtube 、および アマゾンプライムビデオ 。また、これらのサービスは、ネイティブの音楽プレーヤーアプリのように一般的なメディアキーでは機能しません。また、一部の機能がすべてのサービスで利用できるとは限りません。
したがって、必要なのは、サービスごとに異なるリモコンレイアウトを定義し、それらを切り替える方法を提供することです。
いくつかのプリセットを使用して、簡単なプロトタイプを作成してみましょう。複数のファイルからのこのデータを含めるため、それらをcommon/preset_commands.js
—「共通」に配置します。
module.exports = { // We could use ️ but some older phones (e.g., Android 5.1.1) won't show it, hence ️ instead 'Netflix': { commands: { '-': 'Escape', '+': 'f', '': 'Up', '⇤': 'XF86Back', '️': 'Return', '': 'Down', '': 'Left', '': 'Right', '': 'm', }, }, 'YouTube': { commands: { '⇤': 'shift+p', '⇥': 'shift+n', '': 'Up', 'CC': 'c', '️': 'k', '': 'Down', '': 'j', '': 'l', '': 'm', }, }, 'Amazon Prime Video': { window_name_override: 'Prime Video', commands: { '⇤': 'Escape', '+': 'f', '': 'Up', 'CC': 'c', '️': 'space', '': 'Down', '': 'Left', '': 'Right', '': 'm', }, }, 'Generic / Music Player': { window_name_override: '', commands: { '⇤': 'XF86AudioPrev', '⇥': 'XF86AudioNext', '': 'XF86AudioRaiseVolume', '': 'r', '️': 'XF86AudioPlay', '': 'XF86AudioLowerVolume', '': 'Left', '': 'Right', '': 'XF86AudioMute', }, }, };
キーコード値は次のようになります xev
を使用して見つかりました 。 (私にとって、「オーディオミュート」と「オーディオ再生」はこの方法では検出できなかったので、私も相談しました メディアキーのリスト 。)
読者はspace
の大文字小文字の違いに気付くかもしれませんおよびReturn
—この理由に関係なく、xdotool
についてはこの詳細を尊重する必要があります。正しく動作します。これに関連して、明示的に記述されたいくつかの定義があります。たとえば、shift+p
P
にもかかわらず私たちの意図を明確に保つためだけに、うまくいくでしょう。
POST
へのエンドポイントが必要ですtoは、xdotool
を使用してキーストロークをシミュレートします。送信できるキーのグループは異なるため(サービスごとに1つ)、特定のエンドポイントを呼び出しますgroup
。生成されたusers
を再利用します名前を変更してエンドポイントroutes/users.js
routes/group.js
に移動し、app.js
で対応する変更を加えます。
// ... var indexRouter = require('./routes/index'); var groupRouter = require('./routes/group'); // ... app.use('/', indexRouter); app.use('/group', groupRouter); // ...
ザ・ キー 機能はxdotool
を使用していますroutes/group.js
のシステムシェル呼び出しを介して。ハードコーディングしますYouTube
テスト目的のためだけに、今のところ選択するメニューとして。
const express = require('express'); const router = express.Router(); const debug = require('debug')('app'); const cp = require('child_process'); const preset_commands = require('../common/preset_commands'); /* POST keystroke to simulate */ router.post('/', function(req, res, next) { const keystroke_name = req.body.keystroke_name; const keystroke_code = preset_commands['YouTube'].commands[keystroke_name]; const final_command = `xdotool search 'YouTube' windowactivate --sync key --clearmodifiers ${keystroke_code}`; debug(`Executing ${final_command}`); cp.exec(final_command, (err, stdout, stderr) => { debug(`Executed ${keystroke_name}`); return res.redirect(req.originalUrl); }); }); module.exports = router;
ここでは、要求されたキー「名前」をPOST
から取得します。 req.body
という名前のパラメーターの下にあるリクエストの本文(keystroke_name
)。 ️
のようになります。次に、それを使用して、preset_commands['YouTube']
のcommands
から対応するコードを検索します。オブジェクト。
最後のコマンドは複数の行にあるため、各行の終わりにあるは、すべての部分を1つのコマンドに結合します。
search 'YouTube'
タイトルに「YouTube」が含まれる最初のウィンドウを取得します。windowactivate --sync
フェッチされたウィンドウをアクティブにし、キーストロークを受信する準備ができるまで待機します。key --clearmodifiers ${keystroke_code}
キーストロークを送信します。送信内容に干渉する可能性のあるCapsLockなどの修飾キーを一時的にクリアしてください。この時点で、コードは有効な入力を提供していることを前提としています。これについては後で詳しく説明します。
簡単にするために、コードでは、タイトルに「YouTube」が含まれるアプリケーションウィンドウが1つだけ開いていることも前提としています。一致するものが複数ある場合、目的のウィンドウにキーストロークを送信する保証はありません。それが問題になる場合は、リモートコントロールするウィンドウ以外のすべてのウィンドウのブラウザタブを切り替えるだけで、ウィンドウのタイトルを変更できると便利です。
これでサーバーを再起動できますが、今回はデバッグを有効にして、debug
の出力を確認できます。呼び出します。これを行うには、DEBUG=old-fashioned-remote:* yarn start
を実行するだけです。またはDEBUG=old-fashioned-remote:* npm start
。実行されたら、YouTubeでビデオを再生し、別のターミナルウィンドウを開いて、cURL呼び出しを試してください。
curl --data 'keystroke_name=️' http://localhost:3000/group
POST
を送信します要求されたキーストローク名を本体に含む要求を、バックエンドがリッスンしているポート3000
のローカルマシンに送信します。そのコマンドを実行すると、Executing
に関するメモが出力されます。およびExecuted
npm
でウィンドウ、そしてさらに重要なことに、ブラウザを起動し、そのビデオを一時停止します。そのコマンドを再度実行すると、同じ出力が得られ、一時停止を解除する必要があります。
私たちのバックエンドは完全には完成していません。また、次のことができるようにする必要があります。
preset_commands
からリモコンレイアウトのリストを作成します。common/preset_commands.js
を使用し、そこでフィルタリングすることもできます。これは、Node.jsバックエンドの潜在的な利点の1つであり、ここでは使用しません。 。)これらの機能は両方とも、Node.jsバックエンドチュートリアルが、構築するPugベースのフロントエンドと交差する場所です。
方程式のバックエンド部分は、routes/index.js
を変更することを意味しますこのように見えるように:
const express = require('express'); const router = express.Router(); const preset_commands = require('../common/preset_commands'); /* GET home page. */ router.get('/', function(req, res, next) { const group_names = Object.keys(preset_commands); res.render('index', { title: 'Which Remote?', group_names, portrait_css: `.group_bar { height: calc(100%/${Math.min(4, group_names.length)}); line-height: calc(100vh/${Math.min(4, group_names.length)}); }`, landscape_css: `.group_bar { height: calc(100%/${Math.min(2, group_names.length)}); line-height: calc(100vh/${Math.min(2, group_names.length)}); }`, }); }); module.exports = router;
ここでは、group_names
を呼び出して、リモコンのレイアウト名(Object.keys
)を取得します。私たちのpreset_commands
ファイル。次に、それらと必要なその他のデータを、res.render()
を介して自動的に呼び出されるPugテンプレートエンジンに送信します。
keys
の意味を混同しないように注意してくださいここに鍵があります ストローク 送信します:Object.keys
すべてを含む配列(順序付きリスト)を提供します キー の キーと値のペア JavaScriptでオブジェクトを構成するもの:
const my_object = { 'a key': 'its corresponding value', 'another key': 'its separate corresponding value', };
common/preset_commands.js
を見ると、上記のパターンと キー (オブジェクトの意味で)は、グループの名前です:'Netflix'
、'YouTube'
など。対応する値はmy_object
のような単純な文字列ではありません。上記があります。これらはオブジェクト全体であり、独自のキーがあります。つまり、commands
そしておそらくwindow_name_override
。
ここで渡されるカスタムCSSは、確かに、ちょっとしたハックです。最新のフレックスボックスベースのソリューションを使用する代わりにそれが必要な理由は、さらに素晴らしい古い化身のモバイルブラウザの素晴らしい世界との互換性を高めるためです。この場合、注意すべき主な点は、横向きモードでは、画面1つあたり2つ以下のオプションを表示することで、ボタンを大きく維持していることです。ポートレートモードでは、4つ。
しかし、それは実際にどこでHTMLに変換され、ブラウザーに送信されるのでしょうか。ここでviews/index.pug
入ってくる、これは次のようになります。
extends layout block header_injection style(media='(orientation: portrait)') #{portrait_css} style(media='(orientation: landscape)') #{landscape_css} block content each group_name in group_names span(class='group_bar') a(href='/group/?group_name=' + group_name) #{group_name}
最初の行が重要です:extends layout
これは、Pugがこのファイルをviews/layout.pug
のコンテキストで取得することを意味します。これは、ここおよび別のビューで再利用する一種の親テンプレートです。 link
の後に数行追加する必要があります最終的なファイルが次のようになるように行します。
doctype html html head title= title link(rel='stylesheet', href='/stylesheets/style.css') block header_injection meta(name='viewport', content='user-scalable=no') body block content
ここではHTMLの基本については説明しませんが、HTMLに慣れていない読者のために、このPugコードは、ほぼすべての場所で見られる標準料金のHTMLコードを反映しています。ザ・ テンプレート その側面はtitle= title
で始まり、HTMLタイトルをtitle
に対応する値に設定します。 res.render
を介してPugを渡すオブジェクトのキー。
後でblock
を使用して2行をテンプレート化する別の側面を見ることができます。 header_injection
という名前を付けています。このようなブロックは、現在のブロックを拡張するテンプレートで置き換えることができるプレースホルダーです。 (関係ありませんが、meta
行は、モバイルブラウザーの簡単な回避策であるため、ユーザーがボリュームコントロールを連続して何度もタップすると、電話はズームインまたはズームアウトを控えます。)
block
sに戻る:これがviews/index.pug
の理由ですblock
にあるのと同じ名前で独自のviews/layout.pug
sを定義します。このheader_injection
の場合、これにより、電話機が置かれる縦向きまたは横向きに固有のCSSを使用できます。
content
ここに、Webページの主要な表示部分を配置します。この場合は次のようになります。
group_names
をループします渡す配列、
を作成しますCSSクラスgroup_bar
を持つそれぞれの要素それに適用され、そして
内にリンクを作成しますgroup_name
に基づいています。CSSクラスgroup_bar
views/layout.pug
を介してプルされたファイル、つまりpublic/stylesheets/style.css
で定義できます。
html, body, form { padding: 0; margin: 0; height: 100%; font: 14px 'Lucida Grande', Helvetica, Arial, sans-serif; } .group_bar, .group_bar a, .remote_button { box-sizing: border-box; border: 1px solid white; color: greenyellow; background-color: black; } .group_bar { width: 100%; font-size: 6vh; text-align: center; display: inline-block; } .group_bar a { text-decoration: none; display: block; }
この時点で、npm start
の場合はまだ実行中です、http://localhost:3000/
に移動しますデスクトップブラウザでは、NetflixとYouTubeの2つの非常に大きなボタンが表示され、残りは下にスクロールして利用できます。
ただし、この時点でクリックすると、リンク先のルートがまだ定義されていないため、機能しません(GET
の/group
)。
そのために、これをroutes/group.js
に追加します決勝の直前module.exports
ライン:
router.get('/', function(req, res, next) { const group_name = req.query.group_name || ''; const group = preset_commands[group_name]; return res.render('group', { keystroke_names: Object.keys(group.commands), group_name, title: `${group_name.match(/([A-Z])/g).join('')}-Remote` }); });
これにより、エンドポイントに送信されるグループ名が取得され(たとえば、?group_name=Netflix
の末尾に/group/
を配置することにより)、それを使用してcommands
の値が取得されます。対応するグループから。その値(group.commands
)はオブジェクトであり、そのオブジェクトのキーは、リモコンのレイアウトに表示する名前(keystroke_names
)です。
注:経験の浅い開発者は、その仕組みの詳細に立ち入る必要はありませんが、title
の価値はのビットを使用します 正規表現 グループ/レイアウト名を頭字語に変換するには、たとえば、YouTubeリモコンのブラウザタイトルはYT-Remote
になります。そうすれば、電話で試す前にホストマシンでデバッグしている場合、xdotool
はありません。制御しようとしているウィンドウではなく、リモコンのブラウザウィンドウ自体を取得します。一方、私たちの電話では、リモコンをブックマークしたい場合は、タイトルが短く短くなります。
以前のres.render
との遭遇と同様に、これはテンプレートviews/group.pug
と混合するためにデータを送信しています。そのファイルを作成し、次のように入力します。
extends layout block header_injection script(type='text/javascript', src='/javascript/group-client.js') block content form(action='/group?group_name=' + group_name, method='post') each keystroke_name in keystroke_names input(type='submit', name='keystroke_name', value=keystroke_name, class='remote_button')
views/index.pug
と同様に、views/layout.pug
の2つのブログを上書きします。今回は、ヘッダーに挿入するのはCSSではなく、クライアント側のJavaScriptです。これについては後ほど説明します。 (そして、はい、気難しい瞬間に、私は誤って複数形に変更されたjavascripts
…の名前を変更しました)
メインcontent
これは、keystroke_name
ごとに1つずつ異なる送信ボタンの束で構成されたHTMLフォームです。各ボタンは、フォームで送信する値として表示されているキーストローク名を使用してフォームを送信します(POST
リクエストを行います)。
また、メインのスタイルシートファイルにはもう少しCSSが必要です。
.remote_button { float: left; width: calc(100%/3); height: calc(100%/3); font-size: 12vh; }
以前、エンドポイントを設定したときに、次のコマンドでリクエストの処理を終了しました。
return res.redirect(req.originalUrl);
これは事実上、ブラウザがフォームを送信すると、Node.jsバックエンドが応答して、フォームが送信されたページ、つまりメインのリモコンレイアウトに戻るようにブラウザに指示することを意味します。ページを切り替えることなく、よりエレガントになります。ただし、老朽化したモバイルブラウザの奇妙で素晴らしい世界との最大限の互換性が必要です。このように、フロントエンドJavaScriptがまったく機能していなくても、Node.jsバックエンドプロジェクト すべき まだ機能します。
フォームを使用してキーストロークを送信することの欠点は、ブラウザーが待機してから、追加のラウンドトリップを実行する必要があることです。ページとその依存関係は、Node.jsバックエンドから要求されて配信される必要があります。次に、ブラウザで再度レンダリングする必要があります。
読者は、これがどれほどの効果をもたらすのか疑問に思うかもしれません。結局のところ、ページは小さく、その依存関係は非常に最小限であり、最終的なNode.jsプロジェクトはローカルのwifi接続を介して実行されます。低レイテンシのセットアップである必要がありますか?
結局のところ、少なくともWindows Phone8.1とAndroid4.4.2を実行している古いスマートフォンでテストした場合、残念ながら、すばやくタップして再生音量を数ノッチ上げたり下げたりする一般的なケースでは、その影響は非常に顕著です。ここで、HTMLフォームを介した手動のPOST
の優雅なフォールバックを損なうことなく、JavaScriptが役立ちます。
この時点で、最終的なクライアントJavaScript(public/javascript/group-client.js
に配置される)は、サポートされなくなった古いモバイルブラウザーと互換性がある必要があります。しかし、それはあまり必要ありません。
(function () { function form_submit(event) { var request = new XMLHttpRequest(); request.open('POST', window.location.pathname + window.location.search, true); request.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded'); request.send('keystroke_name=' + encodeURIComponent(event.target.value)); event.preventDefault(); } window.addEventListener('DOMContentLoaded', function() { var inputs = document.querySelectorAll('input'); for (var i = 0; i ここで、form_submit
関数は非同期呼び出しを介してデータを送信するだけであり、最後の行はブラウザの通常の送信動作を妨げます。これにより、サーバーの応答に基づいて新しいページが読み込まれます。このスニペットの後半は、ページが読み込まれるまで待機してから、すべての送信ボタンを接続してform_submit
を使用します。全部が包まれている IIFE 。
最後の仕上げ
いくつかあります 変更 Node.jsバックエンドチュートリアルコードの最終バージョンの上記のスニペットに、主にエラー処理を改善する目的で:
- Node.jsバックエンドは、送信されたグループとキーストロークの名前をチェックして、それらが存在することを確認するようになりました。このコードは、
GET
の両方に再利用される関数内にありますおよびPOST
routes/group.js
の関数。 - パグを利用します
error
そうでない場合はテンプレート。 - フロントエンドのJavaScriptとCSSは、サーバーからの応答を待っている間、ボタンの輪郭を一時的に灰色にし、信号が
xdotool
を通過するとすぐに緑色になります。問題なく戻って、期待どおりに機能しなかった場合は赤になります。 - Node.jsバックエンドは、スタックトレースが停止すると、スタックトレースを出力します。これは、上記の場合に発生する可能性が低くなります。
読者は、Node.jsプロジェクト全体を熟読(および/または複製)することができます。 GitHubで 。
Node.jsバックエンドチュートリアル、ステップ5:実際のテスト
実行中のホストと同じwifiネットワークに接続された実際の電話で試してみましょうnpm start
そして映画や音楽プレーヤー。スマートフォンのウェブブラウザでホストのローカルIPアドレス(:3000
の接尾辞が付いている)を指定するだけです。これは、hostname -I | awk '{print }'
を実行することで簡単に見つけることができます。ホスト上の端末で。
Windows Phone 8.1ユーザーが気付く可能性のある問題の1つは、192.168.2.5:3000
のようなものに移動しようとすることです。エラーポップアップが表示されます:

ありがたいことに、落胆する必要はありません。単に接頭辞http://
を付けるだけです。または末尾に/
を追加しますそれ以上の苦情なしにアドレスを取得するためにそれを取得します。

そこでオプションを選択すると、動作するリモコンが表示されます。

さらに便利なように、ユーザーはルーターのDHCP設定を調整して、常に同じIPアドレスをホストに割り当て、レイアウト選択画面やお気に入りのレイアウトをブックマークすることができます。
プルリクエストへようこそ
誰もがこのプロジェクトをそのまま好きになるとは限らないでしょう。コードをさらに掘り下げたい人のために、改善のためのいくつかのアイデアがあります:
C言語が発明されたのはいつですか
- レイアウトを微調整したり、DisneyPlusなどの他のサービス用に新しいレイアウトを追加したりするのは簡単です。
- 「ライトモード」レイアウトと切り替えオプションを好む人もいるかもしれません。
- Netflixを取り消すと、元に戻せないため、実際に「よろしいですか?」を使用できます。ある種の確認。
- プロジェクトは確かに恩恵を受けるでしょう ウィンドウズ サポート。
xdotool
のドキュメントにはOSXが記載されていますが、このプロジェクトは最新のMacで機能しますか(または機能しますか?) - 高度なくつろぎのために、Netflix / Amazonプライムビデオの映画を1つ選んだり、コンピューターでYouTubeプレイリストを作成したりする代わりに、映画を検索して閲覧する方法。
- 提案された変更のいずれかが元の機能を壊した場合の自動テストスイート。
このNode.jsバックエンドチュートリアルと、結果として改善されたメディアエクスペリエンスを楽しんでいただけたと思います。ハッピーストリーミング—そしてコーディング!
関連: Node.js / TypeScript REST APIの構築、パート1:Express.js 基本を理解する
Node.jsはバックエンド用ですか?
はい。 Node.jsは、JavaScriptコードを実行するコマンドラインプログラムであり、通常、Webホストで、Webページの提供、データベースへの接続などに使用されます。
Node.jsはバックエンドに十分ですか?
絶対に。正しく設計されたNode.jsバックエンドは、あらゆるテクノロジーと同様に拡張できます。とはいえ、アプリのデータベースレイヤーへのアクセスなど、他の重要なコンポーネントと統合されることがよくあります。
Express.jsとは何ですか?
ExpressはNode.jsのモジュールであり、一般的なWebサーバー機能の記述に必要な定型コードの量を削減します。それはそれ自身の成熟したサブエコシステムを持っています。ほとんどのNode.jsWebサーバーはExpressを使用します。
パグ/ジェイドとは何ですか?
Pug(以前のJade)は、Expressと統合するテンプレートエンジンです。実際、何年もの間、Expressプロジェクトジェネレーターが新しいプロジェクトに含めるデフォルトのテンプレートエンジンでした。
xdotoolとは何ですか?
コマンドラインプログラムxdotoolは、実行中のコンピューターでのキーストロークをシミュレートします。このプロジェクトでは、電話がWebページを介してコンピューター上でそのようなアクションを実行し、それをリモコンに変えます。