このクイックスタートガイドでは、gulpでTypeScriptをビルドし、Browserify、terser、またはWatchifyをgulpパイプラインに追加する方法を説明します。このガイドでは、Babelifyを使用してBabel機能を追加する方法も示します。
npmでNode.jsをすでに使用していることを前提としています。
最小限のプロジェクト
まず、新しいディレクトリから始めましょう。ここではproj
と名付けますが、好きな名前に変更できます。
shell
mkdir projcd proj
まず、プロジェクトを次のように構成します。
proj/ ├─ src/ └─ dist/
TypeScriptファイルはsrc
フォルダーから始まり、TypeScriptコンパイラーを通じてdist
に配置されます。
これを足場にしましょう。
shell
mkdir srcmkdir dist
プロジェクトの初期化
次に、このフォルダーをnpmパッケージにします。
shell
npm init
一連のプロンプトが表示されます。エントリポイントを除いて、デフォルトを使用できます。エントリポイントには、./dist/main.js
を使用します。生成されたpackage.json
ファイルで、いつでも戻って変更できます。
依存関係のインストール
次に、npm install
を使用してパッケージをインストールできます。まず、gulp-cli
をグローバルにインストールします(Unixシステムを使用している場合は、このガイドのnpm install
コマンドの先頭にsudo
を付ける必要がある場合があります)。
shell
npm install -g gulp-cli
次に、プロジェクトのdevDependenciesにtypescript
、gulp
、gulp-typescript
をインストールします。Gulp-typescriptは、TypeScript用のgulpプラグインです。
shell
npm install --save-dev typescript gulp@4.0.0 gulp-typescript
簡単な例を作成する
Hello Worldプログラムを作成しましょう。src
に、ファイルmain.ts
を作成します。
ts
function hello(compiler: string) {console.log(`Hello from ${compiler}`);}hello("TypeScript");
プロジェクトのルートproj
に、ファイルtsconfig.json
を作成します。
{" ": ["src/main.ts"]," ": {" ": true," ": "es5"}}
gulpfile.js
を作成する
プロジェクトのルートに、ファイルgulpfile.js
を作成します。
js
var gulp = require("gulp");var ts = require("gulp-typescript");var tsProject = ts.createProject("tsconfig.json");gulp.task("default", function () {return tsProject.src().pipe(tsProject()).js.pipe(gulp.dest("dist"));});
結果のアプリをテストする
shell
gulpnode dist/main.js
プログラムは「Hello from TypeScript!」と出力します。
コードにモジュールを追加する
Browserifyに入る前に、コードを構築し、モジュールを追加しましょう。これは、実際のアプリで使用する可能性が高い構成です。
src/greet.ts
というファイルを作成します。
ts
export function sayHello(name: string) {return `Hello from ${name}`;}
次に、src/main.ts
のコードを、greet.ts
からsayHello
をインポートするように変更します。
ts
import { sayHello } from "./greet";console.log(sayHello("TypeScript"));
最後に、src/greet.ts
をtsconfig.json
に追加します。
{" ": ["src/main.ts", "src/greet.ts"]," ": {" ": true," ": "es5"}}
gulp
を実行し、Nodeでテストして、モジュールが機能することを確認してください。
shell
gulpnode dist/main.js
ES2015のモジュール構文を使用しましたが、TypeScriptはNodeが使用するCommonJSモジュールを出力することに注意してください。このチュートリアルではCommonJSを使用しますが、オプションオブジェクトでmodule
を設定してこれを変更できます。
Browserify
次に、このプロジェクトをNodeからブラウザに移行しましょう。これを行うには、すべてのモジュールを1つのJavaScriptファイルにバンドルする必要があります。幸いなことに、それがまさにBrowserifyの機能です。さらに、Nodeで使用されるCommonJSモジュールシステムを使用できます。これはTypeScriptのデフォルトの出力です。つまり、TypeScriptとNodeの設定は、基本的に変更なしでブラウザに転送されます。
まず、browserify、tsify、およびvinyl-source-streamをインストールします。tsifyはBrowserifyプラグインで、gulp-typescriptと同様にTypeScriptコンパイラーへのアクセスを提供します。vinyl-source-streamを使用すると、Browserifyのファイル出力を、vinylと呼ばれるgulpが理解できる形式に戻すことができます。
shell
npm install --save-dev browserify tsify vinyl-source-stream
ページを作成する
src
にindex.html
というファイルを作成します。
html
<!DOCTYPE html><html><head><meta charset="UTF-8" /><title>Hello World!</title></head><body><p id="greeting">Loading ...</p><script src="bundle.js"></script></body></html>
次に、main.ts
を変更してページを更新します。
ts
import { sayHello } from "./greet";function showHello(divName: string, name: string) {const elt = document.getElementById(divName);elt.innerText = sayHello(name);}showHello("greeting", "TypeScript");
showHello
を呼び出すと、sayHello
が呼び出され、段落のテキストが変更されます。次に、gulpfileを次のように変更します。
js
var gulp = require("gulp");var browserify = require("browserify");var source = require("vinyl-source-stream");var tsify = require("tsify");var paths = {pages: ["src/*.html"],};gulp.task("copy-html", function () {return gulp.src(paths.pages).pipe(gulp.dest("dist"));});gulp.task("default",gulp.series(gulp.parallel("copy-html"), function () {return browserify({basedir: ".",debug: true,entries: ["src/main.ts"],cache: {},packageCache: {},}).plugin(tsify).bundle().pipe(source("bundle.js")).pipe(gulp.dest("dist"));}));
これにより、copy-html
タスクが追加され、default
の依存関係として追加されます。つまり、default
が実行されるたびに、最初にcopy-html
を実行する必要があります。また、default
をgulp-typescriptの代わりにtsifyプラグインを使用してBrowserifyを呼び出すように変更しました。都合の良いことに、両方ともTypeScriptコンパイラーに同じオプションオブジェクトを渡すことができます。
bundle
を呼び出した後、source
(vinyl-source-streamのエイリアス)を使用して、出力バンドルにbundle.js
という名前を付けます。
gulpを実行し、ブラウザでdist/index.html
を開いてページをテストします。「TypeScriptからのこんにちは」がページに表示されるはずです。
Browserifyにdebug: true
を指定したことに注意してください。これにより、tsifyは、バンドルされたJavaScriptファイル内にソースマップを出力します。ソースマップを使用すると、バンドルされたJavaScriptではなく、元のTypeScriptコードをブラウザでデバッグできます。ブラウザのデバッガーを開き、main.ts
内にブレークポイントを設定することで、ソースマップが機能していることをテストできます。ページを更新すると、ブレークポイントでページが一時停止し、greet.ts
をデバッグできるようになります。
Watchify、Babel、およびTerser
Browserifyとtsifyでコードをバンドルしているので、browserifyプラグインを使用してビルドにさまざまな機能を追加できます。
-
Watchifyはgulpを起動し、ファイルの保存時にインクリメンタルにコンパイルを継続します。これにより、ブラウザで編集-保存-更新のサイクルを継続できます。
-
Babelは、ES2015以降をES5およびES3に変換する非常に柔軟なコンパイラーです。これにより、TypeScriptがサポートしていない広範でカスタマイズされた変換を追加できます。
-
Terserは、ダウンロードにかかる時間を短縮するために、コードを圧縮します。
Watchify
まず、Watchifyを使用してバックグラウンドコンパイルを提供します。
shell
npm install --save-dev watchify fancy-log
次に、gulpfileを次のように変更します。
js
var gulp = require("gulp");var browserify = require("browserify");var source = require("vinyl-source-stream");var watchify = require("watchify");var tsify = require("tsify");var fancy_log = require("fancy-log");var paths = {pages: ["src/*.html"],};var watchedBrowserify = watchify(browserify({basedir: ".",debug: true,entries: ["src/main.ts"],cache: {},packageCache: {},}).plugin(tsify));gulp.task("copy-html", function () {return gulp.src(paths.pages).pipe(gulp.dest("dist"));});function bundle() {return watchedBrowserify.bundle().on("error", fancy_log).pipe(source("bundle.js")).pipe(gulp.dest("dist"));}gulp.task("default", gulp.series(gulp.parallel("copy-html"), bundle));watchedBrowserify.on("update", bundle);watchedBrowserify.on("log", fancy_log);
基本的には3つの変更がありますが、コードを少しリファクタリングする必要があります。
browserify
インスタンスをwatchify
の呼び出しでラップし、結果を保持しました。- TypeScriptファイルが変更されるたびにBrowserifyが
bundle
関数を実行するように、watchedBrowserify.on('update', bundle);
を呼び出しました。 - コンソールにログを記録するために、
watchedBrowserify.on('log', fancy_log);
を呼び出しました。
(1)と(2)を合わせると、browserify
の呼び出しをdefault
タスクから移動する必要があることを意味します。また、WatchifyとGulpの両方が呼び出す必要があるため、default
の関数に名前を付ける必要があります。(3)でログを追加するのはオプションですが、セットアップをデバッグするのに非常に役立ちます。
これでGulpを実行すると、起動して実行を維持する必要があります。main.ts
でshowHello
のコードを変更して保存してみてください。次のような出力が表示されるはずです。
shell
proj$ gulp[10:34:20] Using gulpfile ~/src/proj/gulpfile.js[10:34:20] Starting 'copy-html'...[10:34:20] Finished 'copy-html' after 26 ms[10:34:20] Starting 'default'...[10:34:21] 2824 bytes written (0.13 seconds)[10:34:21] Finished 'default' after 1.36 s[10:35:22] 2261 bytes written (0.02 seconds)[10:35:24] 2808 bytes written (0.05 seconds)
Terser
まずTerserをインストールします。Terserの目的はコードをマングルすることなので、ソースマップを機能させ続けるために、vinyl-bufferとgulp-sourcemapsもインストールする必要があります。
shell
npm install --save-dev gulp-terser vinyl-buffer gulp-sourcemaps
次に、gulpfileを次のように変更します。
js
var gulp = require("gulp");var browserify = require("browserify");var source = require("vinyl-source-stream");var terser = require("gulp-terser");var tsify = require("tsify");var sourcemaps = require("gulp-sourcemaps");var buffer = require("vinyl-buffer");var paths = {pages: ["src/*.html"],};gulp.task("copy-html", function () {return gulp.src(paths.pages).pipe(gulp.dest("dist"));});gulp.task("default",gulp.series(gulp.parallel("copy-html"), function () {return browserify({basedir: ".",debug: true,entries: ["src/main.ts"],cache: {},packageCache: {},}).plugin(tsify).bundle().pipe(source("bundle.js")).pipe(buffer()).pipe(sourcemaps.init({ loadMaps: true })).pipe(terser()).pipe(sourcemaps.write("./")).pipe(gulp.dest("dist"));}));
terser
自体には1つの呼び出ししかありません。buffer
とsourcemaps
の呼び出しは、ソースマップが機能し続けるようにするためのものです。これらの呼び出しにより、以前のようにインラインソースマップを使用する代わりに、個別のソースマップファイルが作成されます。これでGulpを実行して、bundle.js
が読めないメチャクチャなものに最小化されていることを確認できます。
shell
gulpcat dist/bundle.js
Babel
まず、BabelifyとES2015用のBabelプリセットをインストールします。Terserと同様に、Babelifyはコードをマングルするため、vinyl-bufferとgulp-sourcemapsが必要になります。デフォルトでは、Babelifyは.js
、.es
、.es6
、および.jsx
の拡張子を持つファイルのみを処理するため、Babelifyへのオプションとして.ts
拡張子を追加する必要があります。
shell
npm install --save-dev babelify@8 babel-core babel-preset-es2015 vinyl-buffer gulp-sourcemaps
次に、gulpfileを次のように変更します。
js
var gulp = require("gulp");var browserify = require("browserify");var source = require("vinyl-source-stream");var tsify = require("tsify");var sourcemaps = require("gulp-sourcemaps");var buffer = require("vinyl-buffer");var paths = {pages: ["src/*.html"],};gulp.task("copy-html", function () {return gulp.src(paths.pages).pipe(gulp.dest("dist"));});gulp.task("default",gulp.series(gulp.parallel("copy-html"), function () {return browserify({basedir: ".",debug: true,entries: ["src/main.ts"],cache: {},packageCache: {},}).plugin(tsify).transform("babelify", {presets: ["es2015"],extensions: [".ts"],}).bundle().pipe(source("bundle.js")).pipe(buffer()).pipe(sourcemaps.init({ loadMaps: true })).pipe(sourcemaps.write("./")).pipe(gulp.dest("dist"));}));
また、TypeScriptがES2015をターゲットにする必要もあります。次に、BabelはTypeScriptが出力するES2015コードからES5を生成します。tsconfig.json
を変更しましょう。
{" ": ["src/main.ts"]," ": {" ": true," ": "es2015"}}
BabelのES5出力は、このような単純なスクリプトの場合、TypeScriptの出力と非常に似ているはずです。