お品書き
- TypeScriptをサーバー側で差分コンパイル。
- nodemonでNodeの自動再起動
- BrowserSyncでフロントエンドも自動リロード
概要
- TypeScriptとnodemonが絡んだサンプルの作成。
- とりあえず使えるもの
実際の設定
devDependencies
package.json(一部抜粋)
"devDependencies" {
"browser-sync": "^2.13.0",
"gulp": "^3.9.1",
"gulp-nodemon": "^2.1.0",
"gulp-typescript": "^2.13.6"
}
インストール
npm i -D browser-sync gulp gulp-nodemon gulp-typescript
TypeScriptの差分コンパイル
参考→ gulp-tscとgulp-typescriptの利用方法の違いについて
残念ながらgulp-tscは当の昔にdeprecatedされてしまったようです。なので今後はgulpに組み込むときはgulp-typescriptのみを使っていくようですが、こっちのほうがtsconfig.jsonから設定を取り込めたり、差分コンパイルできたり何かと便利です。
tsconfig.json
{
"compilerOptions": {
"diagnostics": true,
"emitDecoratorMetadata": true,
"experimentalDecorators": true,
"module": "commonjs",
"moduleResolution": "node",
"target": "es2015"
},
"exclude": [
"node_modules",
"bower_components",
"jspm_packages"
]
}
target
はとりあえずes2015で最新の機能をフル活用するようにしていますがここら辺は様々な事情で変えていく必要があるかもしれません。例えばどうしてもIE向けに作る必要があるときとか、古いNode向けとか。
gulpfile.js(TypeScript部)
const gulpts = require("gulp-typescript");
const tsProject = gulpts.createProject(
"tsconfig.json", {
sortOutput: true,
typescript: require('typescript')
});
gulp.task("serverCompile", () => {
gulp.src(['server/ts/**/*.ts'])
.pipe(gulpts(tsProject))
.js
.pipe(gulp.dest('server/js/'));
});
gulp.task("clientCompile", () => {
gulp.src(['public/**/*.ts'])
.pipe(gulpts(tsProject))
.js
.pipe(gulp.dest('public/'));
});
ここら辺は好みでしょうが自分はpublic
とserver
の二つのディレクトリでサーバー処理部分とクライアント処理部分を分けさらにそれぞれの中にts
、js
とディレクトリを分けています。
BrowserSync
厄介者その1
gulpfile.js(BrowserSync部)
const browserSync = require("browser-sync").create();
const reload = browserSync.reload;
gulp.task("browser-sync", ['nodemon'], () => {
browserSync.init(null, {
proxy:"localhost:3000",
open:false,
port:"7000",
files: [
"public/**/*.*"
],
serveStatic:['public/**/*.*'],
minify:true
});
});
何が厄介ってときどきport
が暴れだしたりproxy
が暴れだしたりするところでしょう。具体的には番号が一つずれてたり。とりあえずそんな時はCtrl+Cで様子見。このBrowserSyncをnodemonで実際に動作させてNodeの再起動時にもブラウザを自動リロードできるようになります。
nodemon
厄介者その2
gulpfile.js(nodemon部)
const gulpts = require("gulp-nodemon");
const path = require("path");
gulp.task('nodemon', (cb) => {
let called = false;
return nodemon({
script: 'server/js/',
watch:'server/',
ext: 'js html css ts pug',
tasks: (changedFiles) => {
let tasks = [];
changedFiles.forEach(file => {
if (path.extname(file) === '.ts' && !~tasks.indexOf("serverCompile"))
tasks.push("serverCompile");
});
return tasks;
}
}).on('start', () => {
if (!called) {
called = true;
cb();
}
}).on('restart', () => {
setTimeout(() => {
reload();
}, 500);
});
});
なんとなくtasks
使わなくてもできそうなものなんだけどそれだとコンパイルに連動して動作しません。それにwatch
やscript
の指定ミスると動作が遅くなったり、こけたり。あと最初pathの存在に気づかなくて延々と悩んだり。いよいよ締めのdefault
です。
default
gulp.task("default", ['clientCompile','browser-sync'], () => {
console.log("gulp start");
// client tasks
gulp.watch('public/**/*.ts',['clientCompile']);
});
実はここもひと悶着ありました。gulp.watch('public/**/*.ts',['clientCompile'])
これをどこに持ってくるかで。nodmonのところに持って行ってみたり。browser-syncのところに持って行ってみたり。
感想
JavaScriptは神秘的。