Gulp

本快速入门指南将教你如何使用 gulp 构建 TypeScript,然后将 BrowserifyterserWatchify 添加到 gulp 管道中。本指南还展示了如何使用 Babelify 添加 Babel 功能。

我们假设您已经在使用 Node.jsnpm

最小项目

让我们从一个新的目录开始。我们现在将其命名为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 [email protected] 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”。

请注意,我们为 Browserify 指定了 debug: true。这会导致 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 和 ES2015 的 Babel 预设。与 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 日