本快速入门指南将教你如何使用 gulp 构建 TypeScript,然后将 Browserify、terser 或 Watchify 添加到 gulp 管道中。本指南还展示了如何使用 Babelify 添加 Babel 功能。
最小项目
让我们从一个新的目录开始。我们现在将其命名为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
然后在你的项目开发依赖项中安装typescript
、gulp
和gulp-typescript
。 Gulp-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
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 移动到浏览器。为此,我们希望将所有模块捆绑到一个 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);
这里基本上有三个更改,但它们需要您稍微重构代码。
- 我们将
browserify
实例包装在对watchify
的调用中,然后保留结果。 - 我们调用了
watchedBrowserify.on('update', bundle);
,以便 Browserify 在您的 TypeScript 文件之一发生更改时运行bundle
函数。 - 我们调用了
watchedBrowserify.on('log', fancy_log);
以记录到控制台。
将 (1) 和 (2) 结合起来意味着我们必须将对 browserify
的调用移出 default
任务。并且我们必须为 default
的函数命名,因为 Watchify 和 Gulp 都需要调用它。使用 (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
本身只有一个调用 - 对 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
的文件,因此我们需要将 .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 生成的代码非常相似。