定义
tsup
是一个基于 ESBuild
实现在零配置的情况下快速打包 Typescript
模块的库,支持 .ts、.tsx
的转换~
它基于esbuild
,但是同时也选择融合其他的构建工具共同参与,弥补了esbuild
的不足。比如tree shaking
的功能依赖的是rollup
~
基本使用
npm i react react-dom
npm i @types/react @types/react-dom -D
npm i tsup -D
新建index.tsx
:
import * as React from 'react'
import * as Server from 'react-dom/server'
let Greet = () => <h1>Hello, world!</h1>
console.log(Server.renderToString(<Greet />))
新建tsup.config.ts
:
import { defineConfig } from 'tsup'
export default defineConfig({
// 入口文件
entry: ['index.tsx'],
// 是否生成对应的调试源文件
sourcemap: true,
// 打包之前是否先清空dist文件
clean: true,
})
执行:
npm run tsup
就会生成下列文件:
- dist
- index.js
- index.js.map
压缩代码
export default defineConfig ((options) => {
return {
// ...
// 是否压缩代码
minify: true,
}
})
是否拆分打码
// content.ts
export const str = 'Hello tsup';
// index.ts
const str = import('./content');
console.log({ str });
默认情况下打包是拆分文件的,即有两个文件:
import { defineConfig } from 'tsup'
export default defineConfig ({
// 入口文件
entry: ['index.ts'],
// 是否生成对应的调试源文件
sourcemap: false,
// 打包之前是否先清空dist文件
clean: true,
// 是否压缩代码
// minify: true,
// 输出格式
format: "esm"
})
如果想让两个文件输出变成一个文件输出,可以修改为:
import { defineConfig } from 'tsup'
export default defineConfig ({
// ...
// 输出格式
format: "esm",
// 是否进行拆分
splitting: false,
})
Tree Shaking
官网说可以通过如下配置达到tree shaing
:
export default defineConfig({
treeshake: true,
})
但是我发现我不配置的话也是可以的(设置成false
也是可以的):
// index.ts
function test() {
console.log(123);
}
let name = '测试测试';
function fn() {
console.log(name);
}
fn();
打包出来的结果删除了test
函数。
另外这里的tree shaking
就是借助的是rollup
而非esbuild
。顺带一提,由于 ESBuild 天生不支持到 es5
的语法降级,所以这里借助的是SWC
,在由 esbuild
将代码编译为 es2020
后由 SWC
接管语法降级部分再次编译降级为 es5
语法。
开启监听模式
"scripts": {
"dev": "npx tsup --watch"
},
执行npm run dev
,修改index.ts
之后会自动编译。
增加忽略监听的配置:
import { defineConfig } from 'tsup'
export default defineConfig ({
// ...
// 忽略监听的文件
ignoreWatch: ['assets', 'public']
})
这样执行的时候会显示:
CLI Watching for changes in "."
CLI Ignoring changes in "**/{.git,node_modules}/**" | "dist" | "assets" | "public"
抹平 cjs
和 mjs
由于在 cjs
中就需要用到 __dirname
而 mjs
则需要用到 import.meta.url
,所以需要开启注入垫片,编译后的代码才可以正常工作。
import { defineConfig } from 'tsup'
export default defineConfig ({
// ...
// 是否开启垫片
shims: true
})
复制文件
新建public/index.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<script src="./index.js"></script>
</body>
</html>
配置:
import { defineConfig } from 'tsup'
export default defineConfig ({
// ...
// 复制文件到dist目录中
publicDir: './public
})
这样打包的dist
文件中为:
- dist
- index.html
- index.js
支持环境变量
// package.json
"scripts": {
"dev": "npx tsup --watch --env.NODE_ENV development",
"build": "npx tsup --env.NODE_ENV production"
},
// ts.config.js
import { defineConfig } from 'tsup'
export default defineConfig ((options: {[key: string]: any}) => {
const { NODE_ENV } = options.env;
console.log('NODE_ENV', NODE_ENV, NODE_ENV === 'production');
return {
// ...
minify: NODE_ENV === 'production',
// ...
}
})
是否生成DTS文件
// index.ts
export const name: string = 'Armouy';
import { defineConfig } from 'tsup'
export default defineConfig ({
// ...
// 是否生成dts文件
dts: true
})
这样打包出来的文件就多了一个index.d.ts
:
declare const name: string;
export { name };
指定外部模块
import { defineConfig } from 'tsup'
export default defineConfig ({
// ...
// 指定哪些模块应该被视为外部模块
external: ['react', 'react-dom']
})
配置loader
import { defineConfig } from 'tsup'
export default defineConfig ({
// ...
loader: {
// .png 为后缀的文件将按 base64 处理
'.png': 'base64',
// .webp为后缀的文件将按 file 处理
'.webp': 'file',
// ...
},
})
成功回调
import { defineConfig } from 'tsup'
export default defineConfig ({
// ...
// 打包成功后的回调函数
async onSuccess() {
console.log('success')
},
})
ts.config.ts
import { defineConfig } from 'tsup'
export default defineConfig ((options: {[key: string]: any}) => {
const { NODE_ENV } = options.env;
console.log('NODE_ENV', NODE_ENV, NODE_ENV === 'production');
return {
// 入口文件
entry: ['index.ts'],
// 是否生成对应的调试源文件
sourcemap: false,
// 打包之前是否先清空dist文件
clean: true,
// 是否压缩代码
minify: NODE_ENV === 'production',
// 输出格式
format: "cjs",
// 是否进行拆分
splitting: true,
// 忽略监听的文件
ignoreWatch: ['assets', 'public'],
// 是否开启垫片
shims: true,
// 复制文件到dist目录中
publicDir: './public',
// 是否生成dts文件
dts: true,
// 指定哪些模块应该被视为外部模块
external: ['react', 'react-dom'],
loader: {
// .png 为后缀的文件将按 base64 处理
'.png': 'base64',
// .webp为后缀的文件将按 file 处理
'.webp': 'file',
},
// 打包成功后的回调函数
async onSuccess() {
console.log('success')
},
}
})
参考链接
如有错误欢迎指出,感谢阅读~