我們首先創(chuàng)建一個(gè)新目錄。
命名為proj
,也可以使用任何你喜歡的名字。
mkdir proj
cd proj
我們將以下面的結(jié)構(gòu)開始我們的工程:
proj/
+- src/
+- dist/
TypeScript文件放在src
文件夾下,經(jīng)過TypeScript編譯器編譯生成的目標(biāo)文件放在dist
目錄下。
下面讓我們來創(chuàng)建這些文件夾:
mkdir src
mkdir dist
現(xiàn)在讓我們把這個(gè)文件夾轉(zhuǎn)換成npm包:
npm init
你將看到有一些提示操作。
除了入口文件外,其余的都可以使用默認(rèn)項(xiàng)。
入口文件使用./dist/main.js
。
你可以隨時(shí)在package.json
文件里更改生成的配置。
現(xiàn)在我們可以使用npm install
命令來安裝包。
首先全局安裝TypeScript和Gulp。
(如果你正在使用Unix系統(tǒng),你可能需要使用sudo
命令來啟動npm install
命令行。)
npm install -g typescript gulp-cli
然后安裝gulp
和gulp-typescript
到開發(fā)依賴項(xiàng)。
Gulp-typescript是TypeScript的一個(gè)Gulp插件。
npm install --save-dev gulp gulp-typescript
讓我們寫一個(gè)Hello World程序。
在src
目錄下創(chuàng)建main.ts
文件:
function hello(compiler: string) {
console.log(`Hello from ${compiler}`);
}
hello("TypeScript");
在工程的根目錄proj
下新建一個(gè)tsconfig.json
文件:
{
"files": [
"src/main.ts"
],
"compilerOptions": {
"noImplicitAny": true,
"target": "es5"
}
}
gulpfile.js
文件在工程根目錄下,新建一個(gè)gulpfile.js
文件:
var gulp = require("gulp");
var ts = require("gulp-typescript");
var tsProject = ts.createProject("tsconfig.json");
gulp.task("default", function () {
return tsProject.src()
.pipe(ts(tsProject))
.js.pipe(gulp.dest("dist"));
});
gulp
node dist/main.js
程序應(yīng)該能夠打印出“Hello from TypeScript!”。
在使用Browserify前,讓我們先構(gòu)建一下代碼然后再添加一些混入的模塊。
這個(gè)結(jié)構(gòu)將是你在真實(shí)應(yīng)用程序中會用到的。
新建一個(gè)src/greet.ts
文件:
export function sayHello(name: string) {
return `Hello from ${name}`;
}
更改src/main.ts
代碼,從greet.ts
導(dǎo)入sayHello
:
import { sayHello } from "./greet";
console.log(sayHello("TypeScript"));
最后,將src/greet.ts
添加到tsconfig.json
:
{
"files": [
"src/main.ts",
"src/greet.ts"
],
"compilerOptions": {
"noImplicitAny": true,
"target": "es5"
}
}
確保執(zhí)行gulp
后模塊是能工作的,在Node.js下進(jìn)行測試:
gulp
node dist/main.js
注意,即使我們使用了ES2015的模塊語法,TypeScript還是會生成Node.js使用的CommonJS模塊。
我們在這個(gè)教程里會一直使用CommonJS模塊,但是你可以通過修改module
選項(xiàng)來改變這個(gè)行為。
現(xiàn)在,讓我們把這個(gè)工程由Node.js環(huán)境移到瀏覽器環(huán)境里。 因此,我們將把所有模塊捆綁成一個(gè)JavaScript文件。 所幸,這正是Browserify要做的事情。
更方便的是,它支持Node.js的CommonJS模塊,這也正是TypeScript默認(rèn)生成的類型。
也就是說TypeScript和Node.js的設(shè)置不需要改變就可以移植到瀏覽器里。
首先,安裝Browserify,tsify和vinyl-source-stream。
tsify是Browserify的一個(gè)插件,就像gulp-typescript一樣,它能夠訪問TypeScript編譯器。
vinyl-source-stream會將Browserify的輸出文件適配成gulp能夠解析的格式,它叫做vinyl。
npm install --save-dev browserify tsify vinyl-source-stream
在src
目錄下新建一個(gè)index.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
文件來更新這個(gè)頁面:
import { sayHello } from "./greet";
function showHello(divName: string, name: string) {
const elt = document.getElementById(divName);
elt.innerText = sayHello(name);
}
showHello("greeting", "TypeScript");
showHello
調(diào)用sayHello
函數(shù)更改頁面上段落的文字。
現(xiàn)在修改gulpfile文件如下:
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", ["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
任務(wù)并且把它加作default
的依賴項(xiàng)。
這樣,當(dāng)default
執(zhí)行時(shí),copy-html
會被首先執(zhí)行。
我們還修改了default
任務(wù),讓它使用tsify
插件調(diào)用Browserify,而不是gulp-typescript
。
方便的是,兩者傳遞相同的參數(shù)對象到TypeScript編譯器。
調(diào)用bundle
后,我們使用source
(vinyl-source-stream的別名)把輸出文件命名為bundle.js
。
測試此頁面,運(yùn)行gulp
,然后在瀏覽器里打開dist/index.html
。
你應(yīng)該能在頁面上看到“Hello from TypeScript”。
注意,我們?yōu)锽roswerify指定了debug: true
。
這會讓tsify
在輸出文件里生成source maps
。
source maps
允許我們在瀏覽器中直接調(diào)試TypeScript源碼,而不是在合并后的JavaScript文件上調(diào)試。
你要打開調(diào)試器并在main.ts
里打一個(gè)斷點(diǎn),看看source maps
是否能工作。
當(dāng)你刷新頁面時(shí),代碼會停在斷點(diǎn)處,從而你就能夠調(diào)試greet.ts
。
現(xiàn)在代碼已經(jīng)用Browserify和tsify捆綁在一起了,我們可以使用Browserify插件為構(gòu)建添加一些特性。
Watchify啟動Gulp并保持運(yùn)行狀態(tài),當(dāng)你保存文件時(shí)自動編譯。 幫你進(jìn)入到編輯-保存-刷新瀏覽器的循環(huán)中。
Babel是個(gè)十分靈活的編譯器,將ES2015及以上版本的代碼轉(zhuǎn)換成ES5和ES3。 你可以添加大量自定義的TypeScript目前不支持的轉(zhuǎn)換器。
我們啟動Watchify,讓它在后臺幫我們編譯:
npm install --save-dev watchify gulp-util
修改gulpfile文件如下:
var gulp = require("gulp");
var browserify = require("browserify");
var source = require('vinyl-source-stream');
var watchify = require("watchify");
var tsify = require("tsify");
var gutil = require("gulp-util");
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()
.pipe(source('bundle.js'))
.pipe(gulp.dest("dist"));
}
gulp.task("default", ["copy-html"], bundle);
watchedBrowserify.on("update", bundle);
watchedBrowserify.on("log", gutil.log);
共有三處改變,但是需要你略微重構(gòu)一下代碼。
browserify
實(shí)例包裹在watchify
的調(diào)用里,控制生成的結(jié)果。watchedBrowserify.on("update", bundle);
,每次TypeScript文件改變時(shí)Browserify會執(zhí)行bundle
函數(shù)。watchedBrowserify.on("log", gutil.log);
將日志打印到控制臺。(1)和(2)在一起意味著我們要將browserify
調(diào)用移出default
任務(wù)。
然后給函數(shù)起個(gè)名字,因?yàn)閃atchify和Gulp都要調(diào)用它。
(3)是可選的,但是對于調(diào)試來講很有用。
現(xiàn)在當(dāng)你執(zhí)行gulp
,它會啟動并保持運(yùn)行狀態(tài)。
試著改變main.ts
文件里showHello
的代碼并保存。
你會看到這樣的輸出:
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)
首先安裝Uglify。
因?yàn)閁glify是用于混淆你的代碼,所以我們還要安裝vinyl-buffer和gulp-sourcemaps來支持sourcemaps。
npm install --save-dev gulp-uglify vinyl-buffer gulp-sourcemaps
修改gulpfile文件如下:
var gulp = require("gulp");
var browserify = require("browserify");
var source = require('vinyl-source-stream');
var tsify = require("tsify");
var uglify = require('gulp-uglify');
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", ["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(uglify())
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest("dist"));
});
注意uglify
只是調(diào)用了自己—buffer
和sourcemaps
的調(diào)用是用于確保sourcemaps可以工作。
這些調(diào)用讓我們可以使用單獨(dú)的sourcemap文件,而不是之前的內(nèi)嵌的sourcemaps。
你現(xiàn)在可以執(zhí)行gulp
來檢查bundle.js
是否被壓縮了:
gulp
cat dist/bundle.js
首先安裝Babelify。
和Uglify一樣,Babelify也會混淆代碼,因此我們也需要vinyl-buffer和gulp-sourcemaps。
npm install --save-dev babelify vinyl-buffer gulp-sourcemaps
修改gulpfile文件如下:
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('copyHtml', function () {
return gulp.src(paths.pages)
.pipe(gulp.dest('dist'));
});
gulp.task('default', ['copyHtml'], function () {
return browserify({
basedir: '.',
debug: true,
entries: ['src/main.ts'],
cache: {},
packageCache: {}
})
.plugin(tsify)
.transform("babelify")
.bundle()
.pipe(source('bundle.js'))
.pipe(buffer())
.pipe(sourcemaps.init({loadMaps: true}))
.pipe(sourcemaps.write('./'))
.pipe(gulp.dest('dist'));
});
我們需要設(shè)置TypeScript目標(biāo)為ES2015。
Babel稍后會從TypeScript生成的ES2015代碼中生成ES5。
修改tsconfig.json
:
{
"files": [
"src/main.ts"
],
"compilerOptions": {
"noImplicitAny": true,
"target": "es2015"
}
}
對于這樣一段簡單的代碼來說,Babel的ES5輸出應(yīng)該和TypeScript的輸出相似。