Windows での最速 Node.js 環境構築
Windows での Node 環境のセットアップが楽になってるな。npm install -g windows-build-tools だけで済むようになってる。もう手動で Python とかインストールしなくていいのか。 https://t.co/r9KDFUp23Z
— tyru (@_tyru_) 2017年3月12日
というわけで Windows で Node.js 環境をセットアップする方法をまとめてみる(もしかして前からこれぐらい簡単だったのかもしれないけど…)。
1. Nodist をインストール
Node.js を直接インストールせず、まずは Nodist をインストールする。
今だと v0.8.8 が最新だった。
2. windows-build-tools をインストール
次に管理者権限で Powershell を起動*1して、npm install -g --production windows-build-tools
する。
3. 環境変数を init.cmd に移す
※この手順は必要ではないけど、自分は何か*2インストールした後は精神衛生上やることにしてるだけです。
インストール後に PATH や NODIST_* といった環境変数が勝手に足されると思いますが、 それをレジストリで設定した cmd.exe のスタートアップ時に実行されるコマンド(自分の場合は %USERPROFILE%\init.cmd)に記述して、足された環境変数を削除します。 詳しくは以下を参照してください。
え、終わり?
これで Windows での Node.js 環境は整う。
3番目のステップは省略可能なので実質 Nodist と windows-build-tools のインストールの2ステップと言っていい。
バージョンを切り替えたかったら nodist global (バージョン)
で切り替えることもできる。
しかし windows-build-tools をインストールするだけで Visual Studio や Python を自動インストールしてくれるのは本当に助かる(python コマンドとかがインストールされる訳ではなく、あくまで Node のライブラリのビルドに必要なランタイムのみインストールされる)。
ちなみに自分は node.exe や npm.exe は cmd.exe から起動してる。 MSYS をメインのシェルとして使ってるけど、そちらは vim と git 用。 PATH を通せば MSYS からも使えるんだろうけど、何となくトラブルが起きそうでやってない。*3
問題起きたら
ここ見れば解決する(はず)。
npm のアップグレード
npm をアップグレードしたかったらこんなのもあるらしい。
こちらも管理者権限で Powershell か cmd.exe を開いて
npm install -g --production npm-windows-upgrade npm-windows-upgrade
だけでアップグレードされるらしい。お手軽…
Promise の処理の流れ
メモ。Twitter に書いたことをそのまんま引用。
https://t.co/O2yTz3ZHGW then() の引数に null 指定したらスキップされるのか。知らんかった
— tyru (@_tyru_) 2017年2月15日
@_tyru_ Promise chain のどっかで エラーが起こるか reject された時の処理って拾うには一つ一つ then() の第2引数をしないといけないと勘違いしてた。途中の then() は onRejected が undefined だからスキップされるんだな
— tyru (@_tyru_) 2017年2月15日
function taskA() { console.log("Task A"); } function taskB() { console.log("Task B"); } function onRejected(error) { console.log("Catch Error: A or B", error); } function finalTask() { console.log("Final Task"); } var promise = Promise.resolve(); promise .then(taskA) .then(taskB) .catch(onRejected) .then(finalTask);
上記コードを現した図(ここから引用)。
https://t.co/QWYD79TIEX の図が参考になる pic.twitter.com/XXfZGIzwo0
— tyru (@_tyru_) 2017年2月21日
Express で書いてるコードを TypeScript 化した時に対処したこと
の続き。
今度は express-generator で自動生成されたバックエンドのコードを TypeScript 化してみる。
tsconfig.json に “allowJs”: true を指定する
express-generator のコードは bin/www から app.js を require() する形になっているが、
app.ts から app.js を生成したところ、app.js で module.exports = app しているのに 空の Object {}
がエクスポートされてしまう。
おそらく bin/www も TypeScript の仕組みに乗っからないと(TypeScript でトランスパイルしないと)
require() できないのだと何となく予測したので、bin/www も .ts 化しようと思った…
けどめんどいので –allowJs(引数)または “allowJs”: true(tsconfig.json)というので .js ファイルもトランスパイルできるらしい。
あと bin/www は shebang も付いてるので外してやる必要がある。
{ "compilerOptions": { ... "allowJs": true, ... }, ... }
ちなみに resolve の extensions に .js を指定しないと require() の時に .js を module として扱ってくれないので注意。
module.exports = { // ... resolve: { // note if using webpack 1 you'd also need a '' in the array as well extensions: ['.ts', '.js'] }, // ... };
target: “node” を指定する
module.exports = { // ... target: 'node', // ... };
よく分かってないけど target には以下を指定できる。デフォルトは web。
- “web” Compile for usage in a browser-like environment (default)
- “webworker” Compile as WebWorker
- “node” Compile for usage in a node.js-like environment (use require to load chunks)
- “async-node” Compile for usage in a node.js-like environment (use fs and vm to load chunks async)
- “node-webkit” Compile for usage in webkit, uses jsonp chunk loading but also supports build in node.js modules plus require(“nw.gui”) (experimental)
- “electron” Compile for usage in Electron – supports require-ing Electron-specific modules.
- “electron-renderer” Compile for electron renderer process, provide a target using JsonpTemplatePlugin, FunctionModulePlugin for browser environment and NodeTargetPlugin and ExternalsPlugin for commonjs and electron bulit-in modules. Note: need webpack >= 1.12.15.
webpack-node-externals を使って require() を展開しないようにする
webpack config のプロパティに externals というものがある。 これは 見つけた require() の中でトランスパイル時に require() 先のモジュールを展開するか(埋め込むか)決めるプロパティ。 externals にファイル名が指定されていれば require() は展開されず、実行時に node によって require される。
しかし一つ一つ指定していくのは面倒。 そこで webpack-node-externals というプラグインがあり、これがエクスポートする nodeExternals() という関数を実行して次のように externals に指定してやれば node_modules 以下のライブラリは一括で展開しないよう指定できる。
WebPackでnodeランタイム向けにビルドする | // sakura note
結果
前回のも含めて以下のようになった。
var path = require('path'); var glob = require('glob'); var nodeExternals = require('webpack-node-externals'); function getFrontendEntries() { // Move init.ts to the first element var INIT_TS = './src/front/init.ts'; var entries = glob.sync("./src/front/**/*.ts").sort(function (a, b) { return a === INIT_TS ? -1 : b === INIT_TS ? 1 : (a > b ? 1 : a === b ? 0 : -1) }); return entries; } function getBackendEntries() { // Transpile './src/back/(.+).[jt]s' into '$1' var entries = {}; glob.sync("./src/back/**/*.?s").forEach(function (entry) { entries[entry.replace(/.*src\/back\/(.+)\.[jt]s$/, '$1')] = entry; }); return entries; } module.exports = [ // Frontend { // 前回の module.exports // http://tyru.hatenablog.com/entry/2017/02/19/210947 entry: getFrontendEntries(), output: { path: path.resolve("./public/javascripts"), // filename: '[name].js' filename: 'bundle.js' }, resolve: { // note if using webpack 1 you'd also need a '' in the array as well extensions: ['.ts', '.js'] }, module: { // loaders will work with webpack 1 or 2; but will be renamed "rules" in // future loaders: [ { exclude: /(node_modules)/, test: /\.ts$/, loader: 'ts-loader' }, { test: /\.html$/, loader: 'html-loader?minimize' }, { test: /\.scss$/, loaders: ['style-loader', 'css-loader', 'sass-loader'] } ] } }, // Backend { // 今回追加するもの target: 'node', externals: [nodeExternals()], entry: getBackendEntries(), output: { path: path.resolve("."), filename: '[name].js' }, resolve: { // note if using webpack 1 you'd also need a '' in the array as well extensions: ['.ts', '.js'] }, module: { // loaders will work with webpack 1 or 2; but will be renamed "rules" in // future loaders: [ { exclude: /(node_modules)/, test: /\.[jt]s$/, loader: 'ts-loader', options: { transpileOnly: true } } ] } } ];
出力されるコードは必ず .js がつくので、npm start で起動するスクリプトにも .js を付けてやる。
{ ... "scripts": { ... "start": "node ./bin/www.js", ... }, ... }
参考記事
- webpackでnpmのbinつくっててfs.readFileSync is not a functionと言われる問題 - DRYな備忘録
- WebPackでnodeランタイム向けにビルドする | // sakura note
- TypeScriptSamples/imageboard at master · Microsoft/TypeScriptSamples · GitHub
- Samples · TypeScript の Express のサンプルアプリ
- “ImageBoard: A Node.js + Express + MongoDB application built using TypeScript on the server”