使用 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 与浏览器使用;
- 两者结合,覆盖所有使用场景,构建过程既灵活又全面。
如果你觉得这篇文章对你有帮助,欢迎点赞、收藏或留言交流 😊
更多推荐

所有评论(0)