子プロセスの生成・終了を管理するサンプルアプリ
背景
アプリが保持する状態が変化したときに、それを音声でつたえる仕組みが欲しくなった(青色になったら音が鳴る歩行者信号のような機能をイメージしてください)。
本記事では、上記機能を実現したときのメモを記す。
機能と方針
実現したい機能を示す。
- 前もって複数の音声ファイルを用意しておき、状態変化に応じて適切な音声ファイルを再生する
- ある状態Aから別の状態Bに遷移したら「状態Bに遷移しました」と音声で通知する。
- 状態Bに遷移を示す音声再生中(例えば「状態Bに」と発話された直後など)に状態Cへ遷移したら直前の音声ファイル再生を止め、新たな状態遷移を示す音声を再生する
上記実現のために今回選んだ方針を以下に示す。
- 状態遷移時に子プロセスを生成し、音声再生アプリ(例:aplay)を起動する
- ワーカスレッドを立て、上記子プロセスの終了を待ち受ける
- 音声再生中に新たな状態遷移が起きた場合はkillを使い、音声再生中の子プロセスを終了したあと、新しい状態への遷移をしめすための子プロセスを生成する。
ソースコード
以下に今回作成したリポジトリのリンクである。
n-hachi/sound-switcher
ここでは、本記事作成時の最新コミットn-hachi/sound-switcher at 4c2f8275880be9592c58fb074f8d2631c118d9bdを前提に記載する。
今回重要なコードはsrc/lib.cppである。
#include "sound/lib.hpp" #include <fcntl.h> #include <signal.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #include <iostream> #include <thread> #include <vector> void SoundSwitcher::Stop() { // If pid_ is less equal than 0, there is no child process. if (pid_ <= 0) { return; } // If pid is more than 0, stop child process. kill(pid_, SIGTERM); // If thread is joinable if (is_running_ && th_.joinable()) { th_.join(); } // Set false value to is_running is_running_ = false; } void SoundSwitcher::ThreadFunc() { // Setup flag is_running_ = true; waitpid(pid_, NULL, 0); } void SoundSwitcher::Start(const int num) { // If child process has already executed, stop it at first. Stop(); pid_ = vfork(); if (pid_ == -1) { std::cerr << "Error: vfork" << std::endl; return; } if (pid_ == 0) { if (Size() <= 0) { return; } int fd = open("/dev/null", O_WRONLY | O_CREAT, 0666); dup2(fd, 1); dup2(fd, 2); const char **argv = new const char *[3]; argv[0] = "/usr/bin/aplay"; argv[1] = map_.at(num).c_str(); argv[2] = NULL; const char *cmd = argv[0]; execvp(cmd, (char **)argv); } if (pid_ > 0) { // Wait for child process exit. std::thread th(&SoundSwitcher::ThreadFunc, this); th_ = std::move(th); } } void SoundSwitcher::Insert(const std::string &path) { int size = (int)map_.size(); map_.insert(std::pair<int, std::string>(size, path)); } size_t SoundSwitcher::Size() const { return map_.size(); } std::map<int, std::string> SoundSwitcher::map() { return map_; }
ここから各種メソッドを説明する
Insertメソッド
ファイル(この例では音声ファイル)のパスを引数に取りマップに格納する。
マップには、現状のマップのサイズをkey、ファイルパスをvalueとして値を格納する。
key値は後述するstartメソッドで音声ファイルを指定するために使う。
Stopメソッド
子プロセスのPIDが有効な値の場合=すでに子プロセスを生成している場合、子プロセスに対してシグナルを発行し子プロセスを停止する。
子プロセスの終了がきっかけでワーカスレッドが終了する(ワーカスレッド内で実行したwaitpidによる停止が解除される)ためthread::joinでスレッド完了を待つ。
Startメソッド
はじめにStopメソッドを使い、管理中の子プロセスが存在するなら停止する。
vforkを使い子プロセスを生成する。ここから親プロセスと子プロセスで処理が分かれる。
子プロセスはStartメソッドの引数として与えられた値とmap型の変数から再生するファイルパスを取得し、aplayを実行(exec)する。
親プロセスは子プロセスの終了を検知するためのワーカスレッドを作成する
以上が概要である。
終わりに
多分、好ましくない書き方など多くあると思うのでアドバイスなどあればコメントしていただけると嬉しいです。
express使用時のapp.use(express.static(__dirname + '/public'))の意味
背景
他者がつくったアプリを拝見していたときに app.use(express.static(__dirname + '/public')) と書かれた箇所があり、この文の意味が分からなかったので調べた。
説明
Express での静的ファイルの提供に説明があった。
イメージ、CSS ファイル、JavaScript ファイルなどの静的ファイルを提供するには、Express に標準実装されている express.static ミドルウェア関数を使用します。
静的アセットファイルを格納しているディレクトリーの名前を express.static ミドルウェア関数に渡して、ファイルの直接提供を開始します。例えば、public というディレクトリー内のイメージ、CSS ファイル、JavaScript ファイルを提供するには、次のコードを使用します。
(中略)
ただし、express.static 関数に指定するパスは、node プロセスを起動するディレクトリーに対して相対的です。別のディレクトリーから Express アプリケーションを実行する場合は、提供するディレクトリーの絶対パスを使用する方が安全です。
試してみる
app.use(express.static('public'))とapp.se(express.static(__dirname+'/public'))の違いを確認するリポジトリを作成した。
n-hachi/prac_express_app_use
以下に確認方法を記す
前準備
アプリのインストールおよび起動準備
git clone https://github.com/n-hachi/prac_express_app_use cd prac_express_app_use npm install
case1:リポジトリのトップディレクトリでnodeを実行する
# case1 node index.js
この状態なら http://localhost:8000/path1 と http://localhost:8000/path2 ともにアクセスできる。
case2:リポジトリのトップ以外のディレクトリでnodeを実行する
まずcase1で走らせたnodeプロセスを終了する
mkdir tmp cd tmp node ../index.js
case1とは異なり http://localhost:8000/path1 はアクセスできるが http://localhost:8000/path2 はCannot GET /path2/と表示される。
これはファイルtmp/path2/index.htmlが存在しないために発生する。
まとめ
app.use(express.static(__dirname + '/public'))の意味を勉強した。
あと__dirnameをつけないときはapp.use(express.static('public'))のようにpublicの前にスラッシュが不要なのだが、__dirnameを付加するときはpublicの前にスラッシュが必要なことに気づかず、数分なやんでしまった。
もし同じような動きになったときはスラッシュの有無を確認してほしい。
autocmdの設定をvim実行時に削除する方法
背景
自分は.vimrcに以下一行を追加することでファイル保存時に各行末尾に存在する空白を自動で削除するようにしている。
" Delete tailing blanks. autocmd BufWritePre * :%s/\s\+$//ge
- 参考:よく使うのにすぐ忘れる 行末の空白削除コマンド - Qiitaへのコメント
この方法は他者が作成したコードの末尾に空白が存在する場合、意図していない箇所が書き換わってしまいgit diffを実行した場合に関係ないところまで表示されてしまい困るという課題がある。
上記理由からautocmdの設定を削除する方法を調べた。
参考箇所
autocmd - Vim日本語ドキュメントの "3. 自動コマンドの除去" に以下のように書かれている
:au[tocmd]! [group] {event} {pat} {event} と {pat} に関連づけられた全ての自動コマンドを 除去する。
解決方法
vim起動時に以下を実行することで自動末尾空白が消されることがなくなった
:autocmd! BufWritePre *
もうちょっと良い方法があるかも?
node_modules内パッケージのエントリーポイント定義方法
背景
最近node.jsを勉強しており、他者が作成したパッケージに含まれるファイルの中でどれがエントリーポイントとなるのかわからなかったので調べた。
パッケージのエントリーポイント
※Modules: Packages | Node.js v16.1.0 Documentationの一部を訳し以下に記す。
※訳に誤りがあれば指摘いただきたい。
パッケージ内のファイルpackage.jsonはエントリーポイントを定義する2つのフィールドE、"main"と"exports"を定義することができる。
"main"はどのバージョンにも対応しているがパッケージのメインエントリポイントのみ定義可能な制限を持つ。
"exports"は"main"の代替を提供する。 "exports"はパッケージのメインエントリポイントを定義するのと同時に、パッケージをカプセル化し、"exports "で定義されたもの以外のエントリーポイントを防ぐ。
※この部分は訳した結果、完全には理解できていないです。
まとめるとpackage.json内の"main"もしくは"exports"フィールドで指定するようだ。
具体例
ここで今回の調査のきっかけになったパッケージを見てみる。
grpc-node/packages/grpc-js at master · grpc/grpc-node
このリポジトリはgrpcをjavascriptで使うために必要なパッケージらしい。
ここで var grpc = require('@grpc/grpc-js');という一文が記載されている。
grpc-jsに含まれるpackage.jsonを見てみる。
ローカルの環境ではnode_modules/@grpc/grpc-js/package.jsonに当たる。
エントリーポイントに関連する部分は"main": "build/src/index.js",である(github上の対応する箇所)。
これによってnode_modules/@grpc/grpc-js/build/src/index.jsがエントリポイントと設定される。
まとめ
package.jsonに含められた"main"と"exports"フィールドによってエントリポイントは定義される。
"main"と"exports"の違いがわかってないので、今後必要になったタイミングで調べていきたい。
create-react-appのメモ
背景
最近 create-react-app を使ったアプリ作成を勉強している。
その過程で、どのファイルが最初に呼ばれるのか(エントリーポイントといえばよいのだろうか?)がわからなくなったので調べてみた。
このメモを作成したときに使ったnpxのバージョンは以下の通り。
$ npx -v 6.12.0
前準備
環境を構築する
$ npx create-react-app myapp
$ cd myapp
上記コマンドにより下記構成が作成される。(※内容が多すぎるためnode_modules は表示していない。)
$ tree -I node_modules . ├── package.json ├── package-lock.json ├── public │ ├── favicon.ico │ ├── index.html │ ├── logo192.png │ ├── logo512.png │ ├── manifest.json │ └── robots.txt ├── README.md └── src ├── App.css ├── App.js ├── App.test.js ├── index.css ├── index.js ├── logo.svg ├── reportWebVitals.js └── setupTests.js 2 directories, 17 files
この状態で npm start を実行するとブラウザが立ち上がりlocalhost上で動作するページが起動する。
npm startの概要
npm start に関連する内容は package.json に記載されている。
ここでは関連する部分のみ抜粋する。
{ "scripts": { "start": "react-scripts start", "build": "react-scripts build", "test": "react-scripts test", "eject": "react-scripts eject" } }
※ここからは予想を含む。
上記"scripts"要素内の記載からキー:"start"に対応する値:react-scripts startが実行される。
react-scriptsは./node_modules/.bin/react-scriptsに配置された実行ファイルが使われる。
Folder Structure | Create React App に以下記述を見つけた。
For the project to build, these files must exist with exact filenames:
・public/index.html is the page template;
・src/index.js is the JavaScript entry point.
この内容から、public/index.htmlとsrc/index.jsが必須ファイルであると予想がたつ。
またreact-scriptsはデフォルトのエントリポイントとしてpublic/index.htmlを扱っているのだろうと推測できる。
stackoverflowの記事
上記推測の裏付けを取るため調べたら関連しそうな記事を見つけた
以下に一番評価された回答の概要を示す(訳はかなり雑です、すいません)。
1. package.json内、start要素
package.json内のstart要素から探索を始めた。
"start": "react-script start"
2. react-scripts
上記内容からnode_modules/.bin以下に存在するreact-scriptsに到達した。
以下に関連する箇所を記載する。
switch (script) { case 'build': case 'eject': case 'start': case 'test': { const result = spawn.sync( 'node', [require.resolve('../scripts/' + script)].concat(args), { stdio: 'inherit' } );
上記内容から../scripts/ディレクトリ以下のスクリプトを探した。
3. start.js
続いてnpm startに関連すると予想されるファイル、node_modules/react-scripts/scripts/start.jsを開いた。
このファイル内でwebpackの設定ファイルを見つけた。
これらはnode_modules/react-scripts/config/webpack.config.dev.jsに記載されていた。
以下に関連した箇所を抜粋する。
entry: [ // Finally, this is your app's code: paths.appIndexJs, ], plugins: [ // Generates an `index.html` file with the <script> injected. new HtmlWebpackPlugin({ inject: true, template: paths.appHtml, }),
よってwebpack configに含まれているpaths.appIndexJsで参照されるファイルがエントリファイル(エントリポイント?)
である。
4. paths.js
関連する最後のファイルはpaths.js(おそらくnode_modules/react-scripts/config/paths.js)である。
const appDirectory = fs.realpathSync(process.cwd()); const resolveApp = relativePath => path.resolve(appDirectory, relativePath); module.exports = { ... appHtml: resolveApp('public/index.html'), appIndexJs: resolveApp('src/index.js'), ... }
5. appHtmlおよびappIndexJs
以上からアプリケーションディレクトリ内のappHtmlはファイルpublic/index.htmlであり、appIndexJsはファイルsrc/index.jsである。
まとめ
※公式ページの記載を見つけられなかったので、以下内容は調べた結果からの予想です。
npx create-react-appを使いアプリをつくる場合、public/index.htmlとsrc/index.jsは自動的に読み込まれると予想する。
最後に誤りなどあれば指摘ください。
Express web framework (Node.js/JavaScript)の勉強 part4、 directory-structure
The generated projectを読み進める。
日本語版の資料をかいつまんだような内容なので、詳細を知りたい人はこっちを見ることを勧める。
ディレクトリ構造
expressおよび関連するコマンドを実行することで以下のようなディレクトリ構造になる。
注意:一部コマンドの出力結果は省略している。
$ express express-locallibrary-tutorial --view=pug --git
create : express-locallibrary-tutorial/
create : express-locallibrary-tutorial/public/
create : express-locallibrary-tutorial/public/javascripts/
create : express-locallibrary-tutorial/public/images/
create : express-locallibrary-tutorial/public/stylesheets/
create : express-locallibrary-tutorial/public/stylesheets/style.css
create : express-locallibrary-tutorial/routes/
create : express-locallibrary-tutorial/routes/index.js
create : express-locallibrary-tutorial/routes/users.js
create : express-locallibrary-tutorial/views/
create : express-locallibrary-tutorial/views/error.pug
create : express-locallibrary-tutorial/views/index.pug
create : express-locallibrary-tutorial/views/layout.pug
create : express-locallibrary-tutorial/.gitignore
create : express-locallibrary-tutorial/app.js
create : express-locallibrary-tutorial/package.json
create : express-locallibrary-tutorial/bin/
create : express-locallibrary-tutorial/bin/www
change directory:
$ cd express-locallibrary-tutorial
install dependencies:
$ npm install
run the app:
$ DEBUG=express-locallibrary-tutorial:* npm start
$ cd express-locallibrary-tutorial
$ npm install
up to date, audited 123 packages in 2s
6 packages are looking for funding
run `npm fund` for details
3 low severity vulnerabilities
To address all issues, run:
npm audit fix --force
Run `npm audit` for details.
$ tree -F
.
├── app.js
├── bin/
│ └── www*
├── node_modules/
│ ├── たくさんのサブディレクトリおよびファイル(表示は省略)
│ ︙
│
├── package.json
├── package-lock.json
├── public/
│ ├── images/
│ ├── javascripts/
│ └── stylesheets/
│ └── style.css
├── routes/
│ ├── index.js
│ └── users.js
└── views/
├── error.pug
├── index.pug
└── layout.pug
405 directories, 4784 files
nodemon
今後express-locallibrary-tutorial以下を編集していくのだが、編集するたびアプリを起動し直すのは面倒である。
この煩わしさを解消するnodemonというツールがある
下記コマンドを実行し、nodemonをインストールする。
npm install -g nodemon
もし開発環境以下(?)にインストールしたい場合は-gの代わりに--save-devを使う。
nodemonを使ってアプリを起動すると、ファイル編集時に自動で反映してくれるためアプリの再起動の手間が省ける。
nodemon ./bin/www
package.json
package.jsonはアプリの依存情報を保持する
nodemonをインストールした直後のpackage.jsonの内容を以下に示す。
タイミングによってバージョン番号は変化するので、次同じコマンドを実行しても下記と同じ結果になるとは限らない(と思う)。
{
"name": "express-locallibrary-tutorial",
"version": "0.0.0",
"private": true,
"scripts": {
"start": "node ./bin/www",
},
"dependencies": {
"cookie-parser": "~1.4.4",
"debug": "~2.6.9",
"express": "~4.16.1",
"http-errors": "~1.6.3",
"morgan": "~1.9.1",
"nodemon": "^2.0.7",
"pug": "2.0.0-beta11"
}
}
npm run-script
参考:npm-run-script | npm Docs
npm run-scriptコマンドによってpackage.jsonの"scripts"オブジェクトに記載されたコマンドを実行できる。
上記の場合、"scripts"というオブジェクトの中にキー"start"、バリュー"node ./bin/www"が存在しているため、npm run-script startと入力するとnode ./bin/wwwが実行される。
引数なしの場合は、以下のように利用可能なコマンドが表示される。
$ npm run-script
Lifecycle scripts included in express-locallibrary-tutorial:
start
node ./bin/www
以下npm run-script -hの実行結果からわかるようにrun-scriptはrunというエイリアスを持っている。
入力文字の短さからnpm runを使ったほうが良いだろう(npm run-scriptのほうがnpm runより良いケースってあるのだろうか?)。
$ npm run-script -h npm run-script <command> [-- <args>] aliases: run, rum, urn
scripts
package.json内のscriptsを以下のように編集する
"scripts": {
"start": "node ./bin/www",
"devstart": "nodemon ./bin/www",
"serverstart": "DEBUG-express-lcallibrary-tutorial:* npm run devstart"
}
"start"で始まる行の末尾にカンマ(,)が追記されていることに注意する。
以降はnpm run serverstartと実行することでnodemonでアプリが実行される
/bin/www
ファイル/bin/wwwはアプリケーションのエントリポイントである。
下記コードによって、後述するapp.jsを呼び出す。
#!/usr/bin/env node
/**
* Module dependencies.
*/
var app = require('../app');
残りのコードでapp.jsを使用するHTTPサーバの設定、ポートの設定、リスニングやサーバエラーのレポートを開始するらしい。
/app.js
expressアプリケーションオブジェクト(appという名前が慣習である)を生成、アプリケーションおよびミドルウェアの設定、appをエクスポートする。
上記した/bin/wwwはエクスポートされたappを使用する。
var express = require('express');
...
var app = express();
...
module.exports = app;
app.jsの詳細を見ていく。
最初にいくつかのnodeライブラリを取り込む。
var createError = require('http-errors');
var express = require('express');
var path = require('path');
var cookieParser = require('cookie-parser');
var logger = require('morgan');
その後require()を使い、routesディレクトリからモジュールを取り込む。
これらファイルには、特定のURLへのリクエストを受け取った場合の処理が書かれている。
var indexRouter = require('./routes/index');
var usersRouter = require('./routes/users');
次にappオブジェクトをexpressモジュールを使い作成し、view(template)エンジンを設定する。
エンジンの設定は2段階に分かれる。
最初に値'views'を使ってテンプレートが保存されているフォルダを指定する。
その後、値'view engine'を使いテンプレートライブラリを指定する。
参考:Using template engines with Express
var app = express();
// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'pug');
続いてapp.use()を使いミドルウェアライブラリをリクエストハンドリングの連鎖に加える。
app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));
更に特定のパスへの要求を別のルータへ対応付ける。
app.use('/', indexRouter);
app.use('/users', usersRouter);
最後はエラーとHTTP404レスポンスを返却するためのミドルウェアを追加する。
// catch 404 and forward to error handler
app.use(function(req, res, next) {
next(createError(404));
});
// error handler
app.use(function(err, req, res, next) {
// set locals, only providing error in development
res.locals.message = err.message;
res.locals.error = req.app.get('env') === 'development' ? err : {};
// render the error page
res.status(err.status || 500);
res.render('error');
});
以上でexpressアプリケーションオブジェクト(app)の設定は完了する。
最後にmodule.exportsにappを追加することで、/bin/wwwからアクセスできるようにする。
module.exports = app;
Router
/routes以下にはusers.jsとindex.jsがあるが基本的に処理が同じなので、ここではindex.jsのみを見ていく。
最初にexpressモジュールをロードしexpress.routerオブジェクトを取得する。
var express = require('express');
var router = express.Router();
/* GET users listing. */
router.get('/', function(req, res, next) {
res.send('respond with a resource!!');
});
module.exports = router;
Views(templates)
views(template)は/viewsディレクトリに格納され、拡張子.pugを持つ。
Response.render()メソッドは特定のテンプレートを描画するために使われ、レスポンスとして結果を送信する。
以下/routes/index.jsの例ではルートレンダーはテンプレートindex(index.pug)を使い、テンプレート変数titleを渡している。
/* GET home page. */
router.get('/', function(req, res, next) {
res.render('index', { title: 'Express' });
});
上記コードに対応するテンプレート/views/index.pugを以下に示す。
ここでは数変titleの箇所に値Expressが挿入される。
extends layout
block content
h1= title
p Welcome to #{title}
まとめ
個人的にこの章は今までメインでやってきたこと(組み込み寄り)と比べて多くの差異を感じた。
特に重要に違いを感じた点を以下にまとめる。
npm expressでアプリケーションの雛形が作成されること。app.jsではルーターやビューの設定、その他ライブラリのインポートなどを行うこと。routesディレクトリ以下にはルーター(router)が配置され、ルーターは特定のパスへの要求を受理したときに対応する処理へのルーティングを担当すること。- 変数
resはrenderメソッドを使うとテンプレートを使って描画する。 viewsディレクトリにはビュー(view)のテンプレートが配置され、これらは描画の際に使われること。
これらは繰り返し実装しないと身につかなさそうだ。
Express web framework (Node.js/JavaScript)の勉強 part3、 express-generator
Express Tutorial Part 2: Creating a skeleton website を読み進める
ジェネレータのインストール
はじめに下記コマンドを実行しジェネレータをインストールする。
npm install express-generator -g
ジェネレータのオプション
ジェネレータは下記オプションを持つ
$ express -h
Usage: express [options] [dir]
Options:
--version output the version number
-e, --ejs add ejs engine support
--pug add pug engine support
--hbs add handlebars engine support
-H, --hogan add hogan.js engine support
-v, --view <engine> add view <engine> support (dust|ejs|hbs|hjs|jade|pug|twig|vash) (defaults to jade)
--no-view use static html instead of view engine
-c, --css <engine> add stylesheet <engine> support (less|stylus|compass|sass) (defaults to plain css)
--git add .gitignore
-f, --force force on non-empty directory
-h, --help output usage information
プロジェクトの生成
ジェネレータを使いプロジェクトの雛形をつくる。
参考元 の例では express-locallibrary-tutorial をプロジェクト名としているので、それに倣う。
$ express express-locallibrary-tutorial --view=pug --git
create : express-locallibrary-tutorial/
create : express-locallibrary-tutorial/public/
create : express-locallibrary-tutorial/public/javascripts/
create : express-locallibrary-tutorial/public/images/
create : express-locallibrary-tutorial/public/stylesheets/
create : express-locallibrary-tutorial/public/stylesheets/style.css
create : express-locallibrary-tutorial/routes/
create : express-locallibrary-tutorial/routes/index.js
create : express-locallibrary-tutorial/routes/users.js
create : express-locallibrary-tutorial/views/
create : express-locallibrary-tutorial/views/error.pug
create : express-locallibrary-tutorial/views/index.pug
create : express-locallibrary-tutorial/views/layout.pug
create : express-locallibrary-tutorial/.gitignore
create : express-locallibrary-tutorial/app.js
create : express-locallibrary-tutorial/package.json
create : express-locallibrary-tutorial/bin/
create : express-locallibrary-tutorial/bin/www
change directory:
$ cd express-locallibrary-tutorial
install dependencies:
$ npm install
run the app:
$ DEBUG=express-locallibrary-tutorial:* npm start
第1引数で指定した名前のディレクトリがカレントディレクトリ以下に作成される。
--gitオプションで.gitignoreも同時に作られる。
この.gitignore は中身が充実しており、これを使うのが好ましいと判断したため--gitオプションを付加して実行した。
以下に expressが作る.gitignore を残す。
expressが作成する.gitignore
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (https://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# Yarn Integrity file
.yarn-integrity
# dotenv environment variables file
.env
# next.js build output
.next
まとめ
expressを使うことでアプリケーションの雛形を作成できる
引数によってビューアなどを切り替えることが可能
--gitオプションによって.gitignoreも同時に作られる