Gulp

本快速入門指南將教您如何使用 gulp 建置 TypeScript,然後將 BrowserifyterserWatchify 加入 gulp 管線。本指南也會說明如何使用 Babel 功能,方法是使用 Babelify

我們假設您已經在使用 Node.js 搭配 npm

最小專案

讓我們從一個新目錄開始。我們先將其命名為 proj,但您可以將其變更為您想要的任何名稱。

shell
mkdir proj
cd proj

首先,我們將專案結構設定如下

proj/ ├─ src/ └─ dist/

TypeScript 檔案會從 src 資料夾開始,執行 TypeScript 編譯器,最後會在 dist 中結束。

讓我們建立腳手架

shell
mkdir src
mkdir dist

初始化專案

現在我們會將這個資料夾轉換成 npm 套件。

shell
npm init

你會收到一系列提示。你可以使用預設值,但入口點除外。對於你的入口點,請使用 ./dist/main.js。你隨時可以返回並在為你產生的 package.json 檔案中變更這些內容。

安裝我們的相依性

現在我們可以使用 npm install 來安裝套件。首先在全球安裝 gulp-cli(如果你使用 Unix 系統,你可能需要在這個指南中的 npm install 指令前面加上 sudo)。

shell
npm install -g gulp-cli

然後在專案的開發相依性中安裝 typescriptgulpgulp-typescriptGulp-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
gulp
node 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
gulp
node dist/main.js

請注意,即使我們使用 ES2015 模組語法,TypeScript 發射的卻是 Node 使用的 CommonJS 模組。我們會在這個教學課程中使用 CommonJS,但您可以在選項物件中設定 module 來變更此設定。

Browserify

現在讓我們將這個專案從 Node 移至瀏覽器。為此,我們想要將所有模組組合成一個 JavaScript 檔案。幸運的是,這正是 Browserify 的功能。更棒的是,它讓我們可以使用 Node 使用的 CommonJS 模組系統,這是 TypeScript 預設的發射。這表示我們的 TypeScript 和 Node 設定基本上不變更就能轉移到瀏覽器。

首先,安裝 browserify、tsify 和 vinyl-source-stream。tsify 是 Browserify 外掛程式,與 gulp-typescript 一樣,可存取 TypeScript 編譯器。vinyl-source-stream 可讓我們將 Browserify 的檔案輸出轉換回 gulp 可理解的格式,稱為 vinyl

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,以使用 tsify 外掛程式呼叫 Browserify,而非 gulp-typescript。很方便的是,它們都允許我們將相同的選項物件傳遞給 TypeScript 編譯器。

呼叫 bundle 之後,我們使用 source(我們的 vinyl-source-stream 別名)將我們的輸出套件命名為 bundle.js

透過執行 gulp,然後在瀏覽器中開啟 dist/index.html 來測試頁面。你應該會在頁面上看到「Hello from TypeScript」。

請注意,我們已將 debug: true 指定給 Browserify。這會導致 tsify 在捆綁的 JavaScript 檔案中發出原始碼對應表。原始碼對應表可讓你直接在瀏覽器中除錯原始 TypeScript 程式碼,而不是捆綁的 JavaScript。你可以透過為瀏覽器開啟除錯工具,並在 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);

這裡基本上有三個變更,但它們需要您重新整理您的程式碼。

  1. 我們將我們的 browserify 執行個體包裝在對 watchify 的呼叫中,然後保留結果。
  2. 我們呼叫 watchedBrowserify.on('update', bundle);,以便 Browserify 在您的 TypeScript 檔案之一變更時執行 bundle 函式。
  3. 我們呼叫 watchedBrowserify.on('log', fancy_log); 以記錄至主控台。

(1)和(2)一起表示我們必須將對 browserify 的呼叫移出 default 工作。而且我們必須為 default 函式提供一個名稱,因為 Watchify 和 Gulp 都需要呼叫它。使用(3)新增記錄是選用的,但對於除錯您的設定非常有用。

現在當您執行 Gulp 時,它應該會開始執行並持續執行。請嘗試變更 main.tsshowHello 的程式碼並儲存它。您應該會看到類似這樣的輸出

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 本身只有一個呼叫,而呼叫 buffersourcemaps 是為了確保原始碼對應持續運作。這些呼叫會提供一個單獨的原始碼對應檔案,而不是像以前一樣使用內嵌原始碼對應。現在您可以執行 Gulp 並檢查 bundle.js 是否已縮小成無法辨識的混亂狀態

shell
gulp
cat dist/bundle.js

Babel

首先安裝 Babelify 和 Babel 預設值 ES2015。與 Terser 一樣,Babelify 會混淆程式碼,因此我們需要 vinyl-buffer 和 gulp-sourcemaps。預設情況下,Babelify 僅會處理副檔名為 .js.es.es6.jsx 的檔案,因此我們需要將 .ts 副檔名新增為 Babelify 的選項。

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 的輸出非常類似,適用於如此簡單的腳本。

TypeScript 文件是一個開源專案。請協助我們改善這些頁面 發送 Pull Request

此頁面的貢獻者
BKBowden Kelly (51)
OTOrta Therox (15)
DRDaniel Rosenwasser (3)
RCRyan Cavanaugh (2)
MFMartin Fischer (1)
19+

最後更新:2024 年 3 月 21 日