使用 Gulp + Webpack 打造一个完整的 TypeScript 库构建流程
在前端开发中,我们经常需要开发自己的 工具函数库、Hooks 库 或者 组件库,并发布到 npm。这样的库通常有几个常见的需求:
- 提供 ES Module(ESM)版本,方便现代项目
import
使用; - 提供 CommonJS(CJS)版本,兼容 Node.js 或老项目
require
使用; - 提供 类型声明文件(.d.ts),方便 TypeScript 用户;
- 额外提供一个 UMD 包,可以让用户直接通过
<script>
从 CDN 引入,全局访问;
本文将带你基于 Gulp + TypeScript + Babel + Webpack 打造一条完整的构建流水线 🚦。
🔧 为什么选择 Gulp + Webpack
- Gulp:擅长文件处理和任务流,适合执行「清理 → 编译 → 转换 → 输出」一系列步骤(或更多自定义复杂步骤)。
- Webpack:擅长打包成单个文件,特别是 UMD 格式,方便浏览器直接使用。
两者结合的好处是:
👉 Gulp 做 模块构建(ESM/CJS/d.ts),保证 npm 使用;
👉 Webpack 做 UMD 打包,保证浏览器/CDN 使用。
这样,我们的库就能“一鱼多吃”,覆盖所有使用场景。
📂 项目构建需求
- 清理旧的构建产物(
es/
、lib/
、dist/
) - 输出 ESM 版本 → 放在
es/
- 输出 CJS 版本 → 放在
lib/
- 生成 类型声明文件 d.ts
- 复制
README.md
到子包目录 - 调用 Webpack 输出 UMD 包 → 放在
dist/
最终目录结构如下:
packages/hooks/
├── es/ # ESM 构建结果
├── lib/ # CJS 构建结果
├── dist/ # UMD 构建结果
│ └── index.umd.js
├── README.md # 子包说明文档
└── package.json
🛠️ 构建脚本
1. Gulp 脚本(gulpfile.js)
const gulp = require('gulp');
const del = require('del');
const babel = require('gulp-babel');
const ts = require('gulp-typescript');
const webpack = require('webpack');
const webpackConfig = require('./webpack.config.js');// 清理目录
gulp.task('clean', async () => {await del(['lib/**', 'es/**', 'dist/**']);
});// 编译 ESM
gulp.task('es', () => {const tsProject = ts.createProject('tsconfig.pro.json', { module: 'ESNext' });return tsProject.src().pipe(tsProject()).pipe(babel()).pipe(gulp.dest('es/'));
});// 编译 CJS
gulp.task('cjs', () => {return gulp.src('es/**/*.js').pipe(babel({ configFile: '../../.babelrc' })).pipe(gulp.dest('lib/'));
});// 类型声明
gulp.task('declaration', () => {const tsProject = ts.createProject('tsconfig.pro.json', {declaration: true,emitDeclarationOnly: true,});return tsProject.src().pipe(tsProject()).pipe(gulp.dest('es/')).pipe(gulp.dest('lib/'));
});// 复制 README
gulp.task('copyReadme', async () => {await gulp.src('../../README.md').pipe(gulp.dest('../../packages/hooks'));
});// 调用 webpack 打包 UMD
gulp.task('umd', (done) => {webpack(webpackConfig, (err, stats) => {if (err) console.error(err);console.log(stats?.toString({ colors: true }));done();});
});// 默认构建任务
exports.default = gulp.series('clean', 'es', 'cjs', 'declaration', 'copyReadme', 'umd');
2. Webpack 配置(webpack.config.js)
const path = require('path');module.exports = {entry: './src/index.js',output: {filename: 'index.umd.js',path: path.resolve(__dirname, 'dist'),libraryTarget: 'umd', // 输出UMD格式globalObject: 'this', // 兼容node和浏览器library: 'MyLibrary', // 挂载到全局对象 window.MyLibrary},mode: 'production',resolve: {extensions: ['.ts', '.js', '.json'],},module: {rules: [{test: /\.(ts|js)$/,exclude: /node_modules/,use: 'babel-loader',},],},externals: {react: 'React', // react 作为外部依赖,不打包进来},
};
📦 构建产物 & 使用方式
构建产物包括三种:
-
ESM(现代前端项目)
import { useMyHook } from 'my-hooks/es';
-
CJS(Node.js 或老项目)
const { useMyHook } = require('my-hooks/lib');
-
UMD(CDN / 浏览器脚本)
<script src="https://cdn.xxx.com/my-hooks/dist/index.umd.js"></script> <script>const { useMyHook } = window.MyLibrary; </script>
⚡ 整体构建命令
# 编译 ESM/CJS/d.ts + 打包 UMD
gulp
这样一条命令,就完成了从 源码 → npm 包 → 浏览器包 的全流程。
✨ 总结
- 用 Gulp 控制任务流,适用于多产物输出(ESM / CJS / d.ts);
- 用 Webpack 打包成一个独立的 UMD 文件,方便 CDN 与浏览器使用;
- 两者结合,覆盖所有使用场景,构建过程既灵活又全面。
如果你觉得这篇文章对你有帮助,欢迎点赞、收藏或留言交流 😊