robuild 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +265 -0
- package/dist/_chunks/build-Dn4aJvxA.mjs +388 -0
- package/dist/_chunks/types-1AA9vjTS.d.mts +96 -0
- package/dist/cli.d.mts +1 -0
- package/dist/cli.mjs +54 -0
- package/dist/config.d.mts +6 -0
- package/dist/config.mjs +7 -0
- package/dist/index.d.mts +10 -0
- package/dist/index.mjs +3 -0
- package/package.json +56 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) Sunny-117
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,265 @@
|
|
|
1
|
+
# tsbuild
|
|
2
|
+
|
|
3
|
+
⚡️ Bundle your TypeScript library with no config, powered by esbuild、swc、rollup ...
|
|
4
|
+
|
|
5
|
+
## 特点
|
|
6
|
+
|
|
7
|
+
1. 基于 esbuild 开发:无需关心内部构建逻辑,一键式构建
|
|
8
|
+
2. 覆盖常用的构建能力:通过 Plugin 式开发,完美支持 esbuild 的构建功能
|
|
9
|
+
3. 支持 ES5:借助 SWC 能力,支持构建至 ES5 环境
|
|
10
|
+
|
|
11
|
+
## 技术选型
|
|
12
|
+
|
|
13
|
+
- 包管理工具:pnpm;
|
|
14
|
+
- 命令行交互:cac;
|
|
15
|
+
- 基础构建工具:esbuild、rollup、swc;
|
|
16
|
+
- 文件读取工具:JoyCon;
|
|
17
|
+
- 代码runtime 转换工具:sucrase;
|
|
18
|
+
- 代码语法检查工具:typescript;
|
|
19
|
+
- 代码压缩:terser;
|
|
20
|
+
- 代码文件监听:chokidar;
|
|
21
|
+
- 静态站点:docusaurus;
|
|
22
|
+
- 测试工具:vitest;
|
|
23
|
+
|
|
24
|
+
## 安装
|
|
25
|
+
|
|
26
|
+
```bash
|
|
27
|
+
# 建议当前项目中安装
|
|
28
|
+
pnpm i tsbuild -D
|
|
29
|
+
|
|
30
|
+
# 也可以全局安装,但不推荐
|
|
31
|
+
pnpm i tsbuild -g
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
## 基础使用
|
|
35
|
+
|
|
36
|
+
```bash
|
|
37
|
+
tsbuild [...files]
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
文件默认会构建至 `dist`目录下。
|
|
41
|
+
|
|
42
|
+
## 支持多入口
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
tsbuild src/index.ts src/cli.ts
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
会在`dist`目录下产出`index.js`与`cli.js`。
|
|
49
|
+
|
|
50
|
+
也可以使用`CLI`的指令执行相同的功能
|
|
51
|
+
|
|
52
|
+
```bash
|
|
53
|
+
# 构建结果为 dist/index.js dist/cli.js
|
|
54
|
+
tsbuild --entry src/index.ts --entry src/cli.ts
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
也可以指定构建后的文件名称
|
|
58
|
+
|
|
59
|
+
```bash
|
|
60
|
+
# 构建结果为 dist/foo.js 和 dist/bar.js
|
|
61
|
+
tsbuild --entry.foo src/index.ts --entry.bar src/cli.ts
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
也可以在 `encode-config.ts` 中配置:
|
|
65
|
+
|
|
66
|
+
```typescript
|
|
67
|
+
export default defineConfig({
|
|
68
|
+
// 输出 dist/a.js 和 dist/b.js
|
|
69
|
+
entry: ['src/a.ts', 'src/b.ts'],
|
|
70
|
+
// 输出 dist/foo.js 和 dist/bar.js
|
|
71
|
+
entry: {
|
|
72
|
+
foo: 'src/a.ts',
|
|
73
|
+
bar: 'src/b.ts',
|
|
74
|
+
},
|
|
75
|
+
})
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
## 设置 exclude
|
|
79
|
+
|
|
80
|
+
默认情况下,除了生产环境下所依赖的模块(`peerDependencies`和`dependencies`)外,会自动构建其他的模块,如果不希望构建,可以使用`--external`避免构建。
|
|
81
|
+
|
|
82
|
+
## 自定义配置
|
|
83
|
+
|
|
84
|
+
可以使用如下配置
|
|
85
|
+
|
|
86
|
+
- `tsbuild.config.ts`
|
|
87
|
+
- `tsbuild.config.js`
|
|
88
|
+
- `tsbuild.config.cjs`
|
|
89
|
+
- `tsbuild.config.json`
|
|
90
|
+
- 在`package.json`中的`tsbuild`
|
|
91
|
+
|
|
92
|
+
也可以使用`defineConfig`来进行定制化配置。
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
import { defineConfig } from 'tsbuild'
|
|
96
|
+
|
|
97
|
+
export default defineConfig({
|
|
98
|
+
entry: ['src/index.ts'],
|
|
99
|
+
splitting: false,
|
|
100
|
+
sourcemap: true,
|
|
101
|
+
clean: true,
|
|
102
|
+
})
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
也可以在`package.json`中进行配置。
|
|
106
|
+
|
|
107
|
+
```json
|
|
108
|
+
{
|
|
109
|
+
"tsbuild": {
|
|
110
|
+
"entry": ["src/index.ts"],
|
|
111
|
+
"splitting": false,
|
|
112
|
+
"sourcemap": true,
|
|
113
|
+
"clean": true
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
## 生成声明文件
|
|
119
|
+
|
|
120
|
+
```bash
|
|
121
|
+
tsbuild index.ts --dts
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
以上指令会导出`./dist/index.js`和`./dist/index.d.ts`,当导出多种构建格式时,每种构建格式都会生成一个声明文件。
|
|
125
|
+
|
|
126
|
+
如果有多个入口文件,每个入口文件都会生成一个对应的`.d.ts`文件。因此,如果想对单个入口文件生成声明文件时,请使用 ` --dts <entry>`` 格式,例如 `--dts src/index.ts`。
|
|
127
|
+
|
|
128
|
+
请注意,`--dts`不会解析 `.d.ts` 文件中使用的外部(比如`node_modules`)类型,如果这是某种要求,可以使用 `--dts-resolve`。
|
|
129
|
+
|
|
130
|
+
## 只导出声明文件
|
|
131
|
+
|
|
132
|
+
`--dts-only` 指令等同于`tsc`的`emitDeclarationOnly`。可以使用此指令只生成声明文件。
|
|
133
|
+
|
|
134
|
+
## 生成 sourcemap
|
|
135
|
+
|
|
136
|
+
```bash
|
|
137
|
+
tsbuild index.ts --sourcemap
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
会导出 `./dist/index.js` and `./dist/index.js.map`。
|
|
141
|
+
|
|
142
|
+
如果有多个入口文件,每个入口文件都会生成相对于的`.map`文件。
|
|
143
|
+
|
|
144
|
+
## 构建产物格式
|
|
145
|
+
|
|
146
|
+
支持`ESM`、`CJS`和`IIFE`。
|
|
147
|
+
|
|
148
|
+
可以一次性构建多种类型:
|
|
149
|
+
|
|
150
|
+
```bash
|
|
151
|
+
tsbuild src/index.ts --format esm,cjs,iife
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
将会生成以下文件结构:
|
|
155
|
+
|
|
156
|
+
```bash
|
|
157
|
+
dist
|
|
158
|
+
├── index.mjs # esm
|
|
159
|
+
├── index.global.js # iife
|
|
160
|
+
└── index.js # cjs
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
如果`package.json`中的`type`配置为`module`,产出结果会有所不同:
|
|
164
|
+
|
|
165
|
+
```bash
|
|
166
|
+
dist
|
|
167
|
+
├── index.js # esm
|
|
168
|
+
├── index.global.js # iife
|
|
169
|
+
└── index.cjs # cjs
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
如果不想使用诸如`.mjs`或者`.cjs`这类文件后缀,或者当前环境不支持此后缀,可以使用`--legacy-output`
|
|
173
|
+
|
|
174
|
+
```bash
|
|
175
|
+
tsbuild src/index.ts --format esm,cjs,iife --legacy-output
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
会构建成:
|
|
179
|
+
|
|
180
|
+
```bash
|
|
181
|
+
dist
|
|
182
|
+
├── esm
|
|
183
|
+
│ └── index.js
|
|
184
|
+
├── iife
|
|
185
|
+
│ └── index.js
|
|
186
|
+
└── index.js
|
|
187
|
+
```
|
|
188
|
+
|
|
189
|
+
## 代码分割
|
|
190
|
+
|
|
191
|
+
目前代码分隔只支持`ESM`的产物类型,并且默认是开启的,如果想针对`CJS`的文件类型设置代码分隔,请设置`--splitting`,会启用`esbuild`的代码分隔功能。
|
|
192
|
+
|
|
193
|
+
对应地,如果想关闭代码分隔,请使用`--no-splitting`。
|
|
194
|
+
|
|
195
|
+
## 目标环境
|
|
196
|
+
|
|
197
|
+
此处默认使用`tsconfig`中的`compilerOptions.target`,也可以使用`--target`来手动声明。
|
|
198
|
+
|
|
199
|
+
## 支持 ES5
|
|
200
|
+
|
|
201
|
+
可以使用`--target es5`指令来将代码编译构建至 ES5 版本,代码首先会构建成`ES2020`,然后借助 SWC 编译成`ES5`。
|
|
202
|
+
|
|
203
|
+
## watch 模式
|
|
204
|
+
|
|
205
|
+
```bash
|
|
206
|
+
tsbuild src/index.ts --watch
|
|
207
|
+
```
|
|
208
|
+
|
|
209
|
+
启动`watch`模式,这意味着在初始构建后,tsbuild 会监听文件变化。
|
|
210
|
+
|
|
211
|
+
可以使用`--ignore-watch`来取消指定文件的监听。
|
|
212
|
+
|
|
213
|
+
```bash
|
|
214
|
+
tsbuild src src/index.ts --watch --ignore-watch folder1 --ignore-watch folder2
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## 成功回调
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
tsbuild src/index.ts --watch --onSuccess "node dist/index.js"
|
|
221
|
+
```
|
|
222
|
+
|
|
223
|
+
`--onSuccess`会返回`Promise`类型的函数,可以执行类似如下功能
|
|
224
|
+
|
|
225
|
+
```typescript
|
|
226
|
+
import { defineConfig } from 'tsbuild'
|
|
227
|
+
|
|
228
|
+
export default defineConfig({
|
|
229
|
+
async onSuccess() {
|
|
230
|
+
const server = http.createServer((req, res) => {
|
|
231
|
+
res.end('Encode Studio!')
|
|
232
|
+
})
|
|
233
|
+
server.listen(3000)
|
|
234
|
+
return () => {
|
|
235
|
+
server.close()
|
|
236
|
+
}
|
|
237
|
+
},
|
|
238
|
+
})
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## 压缩代码
|
|
242
|
+
|
|
243
|
+
可以使用`--minify`来压缩代码
|
|
244
|
+
|
|
245
|
+
```bash
|
|
246
|
+
tsbuild src/index.ts --minify
|
|
247
|
+
```
|
|
248
|
+
|
|
249
|
+
或者使用`terser`而不是 esbuild 来压缩代码,前提条件是要先安装`terser`
|
|
250
|
+
|
|
251
|
+
```bash
|
|
252
|
+
tsbuild src/index.ts --minify
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
## tree shaking
|
|
256
|
+
|
|
257
|
+
`esbuild`默认开启`tree shaking`,但是特殊情况下(如:[external 模块](https://github.com/evanw/esbuild/issues/1794)或者[未使用的引用](https://github.com/evanw/esbuild/issues/1435))等情况还是有些问题。
|
|
258
|
+
|
|
259
|
+
提供`--treeshake`指令来启用`rollup`的`tree shaking`。
|
|
260
|
+
|
|
261
|
+
针对更多帮助,请使用`tsbuild --help`。
|
|
262
|
+
|
|
263
|
+
## how-a-package-is-resolved
|
|
264
|
+
|
|
265
|
+
<img src="./assets/how-a-package-is-resolved.jpeg">
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import { mkdir, readFile, rm, symlink, writeFile } from "node:fs/promises";
|
|
2
|
+
import { basename, dirname, extname, isAbsolute, join, relative, resolve } from "node:path";
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
4
|
+
import { consola } from "consola";
|
|
5
|
+
import { colors } from "consola/utils";
|
|
6
|
+
import prettyBytes from "pretty-bytes";
|
|
7
|
+
import { builtinModules } from "node:module";
|
|
8
|
+
import { defu } from "defu";
|
|
9
|
+
import { resolveModulePath } from "exsolve";
|
|
10
|
+
import oxcParser from "oxc-parser";
|
|
11
|
+
import { rolldown } from "rolldown";
|
|
12
|
+
import { dts } from "rolldown-plugin-dts";
|
|
13
|
+
import { promises, readdirSync, statSync } from "node:fs";
|
|
14
|
+
import { gzipSync } from "node:zlib";
|
|
15
|
+
import { minify } from "oxc-minify";
|
|
16
|
+
import MagicString from "magic-string";
|
|
17
|
+
import oxcTransform from "oxc-transform";
|
|
18
|
+
import { glob } from "tinyglobby";
|
|
19
|
+
|
|
20
|
+
//#region src/utils.ts
|
|
21
|
+
function fmtPath(path) {
|
|
22
|
+
return resolve(path).replace(process.cwd(), ".");
|
|
23
|
+
}
|
|
24
|
+
function analyzeDir(dir) {
|
|
25
|
+
if (Array.isArray(dir)) {
|
|
26
|
+
let totalSize$1 = 0;
|
|
27
|
+
let totalFiles = 0;
|
|
28
|
+
for (const d of dir) {
|
|
29
|
+
const { size, files: files$1 } = analyzeDir(d);
|
|
30
|
+
totalSize$1 += size;
|
|
31
|
+
totalFiles += files$1;
|
|
32
|
+
}
|
|
33
|
+
return {
|
|
34
|
+
size: totalSize$1,
|
|
35
|
+
files: totalFiles
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
let totalSize = 0;
|
|
39
|
+
const files = readdirSync(dir, {
|
|
40
|
+
withFileTypes: true,
|
|
41
|
+
recursive: true
|
|
42
|
+
});
|
|
43
|
+
for (const file of files) {
|
|
44
|
+
const fullPath = join(file.parentPath, file.name);
|
|
45
|
+
if (file.isFile()) {
|
|
46
|
+
const { size } = statSync(fullPath);
|
|
47
|
+
totalSize += size;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
return {
|
|
51
|
+
size: totalSize,
|
|
52
|
+
files: files.length
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
async function distSize(dir, entry) {
|
|
56
|
+
const build$1 = await rolldown({
|
|
57
|
+
input: join(dir, entry),
|
|
58
|
+
plugins: [],
|
|
59
|
+
platform: "neutral",
|
|
60
|
+
external: (id) => id[0] !== "." && !id.startsWith(dir)
|
|
61
|
+
});
|
|
62
|
+
const { output } = await build$1.generate({ inlineDynamicImports: true });
|
|
63
|
+
const code = output[0].code;
|
|
64
|
+
const { code: minified } = await minify(entry, code);
|
|
65
|
+
return {
|
|
66
|
+
size: Buffer.byteLength(code),
|
|
67
|
+
minSize: Buffer.byteLength(minified),
|
|
68
|
+
minGzipSize: gzipSync(minified).length
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
async function sideEffectSize(dir, entry) {
|
|
72
|
+
const virtualEntry = {
|
|
73
|
+
name: "virtual-entry",
|
|
74
|
+
async resolveId(id, importer, opts) {
|
|
75
|
+
if (id === "#entry") return { id };
|
|
76
|
+
const resolved = await this.resolve(id, importer, opts);
|
|
77
|
+
if (!resolved) return null;
|
|
78
|
+
resolved.moduleSideEffects = null;
|
|
79
|
+
return resolved;
|
|
80
|
+
},
|
|
81
|
+
load(id) {
|
|
82
|
+
if (id === "#entry") return `import * as _lib from "${join(dir, entry)}";`;
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
const build$1 = await rolldown({
|
|
86
|
+
input: "#entry",
|
|
87
|
+
platform: "neutral",
|
|
88
|
+
external: (id) => id[0] !== "." && !id.startsWith(dir),
|
|
89
|
+
plugins: [virtualEntry]
|
|
90
|
+
});
|
|
91
|
+
const { output } = await build$1.generate({ inlineDynamicImports: true });
|
|
92
|
+
if (process.env.INSPECT_BUILD) {
|
|
93
|
+
console.log("---------[side effects]---------");
|
|
94
|
+
console.log(entry);
|
|
95
|
+
console.log(output[0].code);
|
|
96
|
+
console.log("-------------------------------");
|
|
97
|
+
}
|
|
98
|
+
return Buffer.byteLength(output[0].code.trim());
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
//#endregion
|
|
102
|
+
//#region src/builders/plugins/shebang.ts
|
|
103
|
+
const SHEBANG_RE = /^#![^\n]*/;
|
|
104
|
+
function shebangPlugin() {
|
|
105
|
+
return {
|
|
106
|
+
name: "robuild-shebang",
|
|
107
|
+
async writeBundle(options, bundle) {
|
|
108
|
+
for (const [fileName, output] of Object.entries(bundle)) {
|
|
109
|
+
if (output.type !== "chunk") continue;
|
|
110
|
+
if (hasShebang(output.code)) {
|
|
111
|
+
const outFile = resolve(options.dir, fileName);
|
|
112
|
+
await makeExecutable(outFile);
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
};
|
|
117
|
+
}
|
|
118
|
+
function hasShebang(code) {
|
|
119
|
+
return SHEBANG_RE.test(code);
|
|
120
|
+
}
|
|
121
|
+
async function makeExecutable(filePath) {
|
|
122
|
+
await promises.chmod(filePath, 493).catch(() => {});
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
//#endregion
|
|
126
|
+
//#region src/builders/bundle.ts
|
|
127
|
+
async function rolldownBuild(ctx, entry, hooks) {
|
|
128
|
+
const inputs = normalizeBundleInputs(entry.input, ctx);
|
|
129
|
+
if (entry.stub) {
|
|
130
|
+
for (const [distName, srcPath] of Object.entries(inputs)) {
|
|
131
|
+
const distPath = join(ctx.pkgDir, "dist", `${distName}.mjs`);
|
|
132
|
+
await mkdir(dirname(distPath), { recursive: true });
|
|
133
|
+
consola.log(`${colors.magenta("[stub bundle] ")} ${colors.underline(fmtPath(distPath))}`);
|
|
134
|
+
const srcContents = await readFile(srcPath, "utf8");
|
|
135
|
+
const parsed = oxcParser.parseSync(srcPath, srcContents);
|
|
136
|
+
const exportNames = parsed.module.staticExports.flatMap((e) => e.entries.map((e$1) => e$1.exportName.kind === "Default" ? "default" : e$1.exportName.name));
|
|
137
|
+
const hasDefaultExport = exportNames.includes("default");
|
|
138
|
+
const firstLine = srcContents.split("\n")[0];
|
|
139
|
+
const hasShebangLine = firstLine.startsWith("#!");
|
|
140
|
+
await writeFile(distPath, `${hasShebangLine ? `${firstLine}\n` : ""}export * from "${srcPath}";\n${hasDefaultExport ? `export { default } from "${srcPath}";\n` : ""}`, "utf8");
|
|
141
|
+
if (hasShebangLine) await makeExecutable(distPath);
|
|
142
|
+
await writeFile(distPath.replace(/\.mjs$/, ".d.mts"), `export * from "${srcPath}";\n${hasDefaultExport ? `export { default } from "${srcPath}";\n` : ""}`, "utf8");
|
|
143
|
+
}
|
|
144
|
+
return;
|
|
145
|
+
}
|
|
146
|
+
const rolldownConfig = defu(entry.rolldown, {
|
|
147
|
+
cwd: ctx.pkgDir,
|
|
148
|
+
input: inputs,
|
|
149
|
+
plugins: [shebangPlugin()],
|
|
150
|
+
platform: "neutral",
|
|
151
|
+
external: [
|
|
152
|
+
...builtinModules,
|
|
153
|
+
...builtinModules.map((m) => `node:${m}`),
|
|
154
|
+
...[...Object.keys(ctx.pkg.dependencies || {}), ...Object.keys(ctx.pkg.peerDependencies || {})].flatMap((p) => [p, new RegExp(`^${p}/`)])
|
|
155
|
+
]
|
|
156
|
+
});
|
|
157
|
+
if (entry.dts !== false) rolldownConfig.plugins.push(...dts({ ...entry.dts }));
|
|
158
|
+
await hooks.rolldownConfig?.(rolldownConfig, ctx);
|
|
159
|
+
const res = await rolldown(rolldownConfig);
|
|
160
|
+
const outDir = resolve(ctx.pkgDir, entry.outDir || "dist");
|
|
161
|
+
const outConfig = {
|
|
162
|
+
dir: outDir,
|
|
163
|
+
entryFileNames: "[name].mjs",
|
|
164
|
+
chunkFileNames: "_chunks/[name]-[hash].mjs",
|
|
165
|
+
minify: entry.minify
|
|
166
|
+
};
|
|
167
|
+
await hooks.rolldownOutput?.(outConfig, res, ctx);
|
|
168
|
+
const { output } = await res.write(outConfig);
|
|
169
|
+
await res.close();
|
|
170
|
+
const outputEntries = [];
|
|
171
|
+
const depsCache = /* @__PURE__ */ new Map();
|
|
172
|
+
const resolveDeps = (chunk) => {
|
|
173
|
+
if (!depsCache.has(chunk)) depsCache.set(chunk, /* @__PURE__ */ new Set());
|
|
174
|
+
const deps = depsCache.get(chunk);
|
|
175
|
+
for (const id of chunk.imports) {
|
|
176
|
+
if (builtinModules.includes(id) || id.startsWith("node:")) {
|
|
177
|
+
deps.add(`[Node.js]`);
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
const depChunk = output.find((o) => o.type === "chunk" && o.fileName === id);
|
|
181
|
+
if (depChunk) {
|
|
182
|
+
for (const dep of resolveDeps(depChunk)) deps.add(dep);
|
|
183
|
+
continue;
|
|
184
|
+
}
|
|
185
|
+
deps.add(id);
|
|
186
|
+
}
|
|
187
|
+
return [...deps].sort();
|
|
188
|
+
};
|
|
189
|
+
for (const chunk of output) {
|
|
190
|
+
if (chunk.type !== "chunk" || !chunk.isEntry) continue;
|
|
191
|
+
if (chunk.fileName.endsWith("ts")) continue;
|
|
192
|
+
outputEntries.push({
|
|
193
|
+
name: chunk.fileName,
|
|
194
|
+
exports: chunk.exports,
|
|
195
|
+
deps: resolveDeps(chunk),
|
|
196
|
+
...await distSize(outDir, chunk.fileName),
|
|
197
|
+
sideEffectSize: await sideEffectSize(outDir, chunk.fileName)
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
consola.log(`\n${outputEntries.map((o) => [
|
|
201
|
+
`${colors.magenta(`[bundle] `)}${colors.underline(fmtPath(join(outDir, o.name)))}`,
|
|
202
|
+
colors.dim(`${colors.bold("Size:")} ${prettyBytes(o.size)}, ${colors.bold(prettyBytes(o.minSize))} minified, ${prettyBytes(o.minGzipSize)} min+gzipped (Side effects: ${prettyBytes(o.sideEffectSize)})`),
|
|
203
|
+
o.exports.some((e) => e !== "default") ? colors.dim(`${colors.bold("Exports:")} ${o.exports.map((e) => e).join(", ")}`) : "",
|
|
204
|
+
o.deps.length > 0 ? colors.dim(`${colors.bold("Dependencies:")} ${o.deps.join(", ")}`) : ""
|
|
205
|
+
].filter(Boolean).join("\n")).join("\n\n")}`);
|
|
206
|
+
}
|
|
207
|
+
function normalizeBundleInputs(input, ctx) {
|
|
208
|
+
const inputs = {};
|
|
209
|
+
for (let src of Array.isArray(input) ? input : [input]) {
|
|
210
|
+
src = resolveModulePath(src, {
|
|
211
|
+
from: ctx.pkgDir,
|
|
212
|
+
extensions: [
|
|
213
|
+
".ts",
|
|
214
|
+
".js",
|
|
215
|
+
".mjs",
|
|
216
|
+
".cjs",
|
|
217
|
+
".json"
|
|
218
|
+
]
|
|
219
|
+
});
|
|
220
|
+
let relativeSrc = relative(join(ctx.pkgDir, "src"), src);
|
|
221
|
+
if (relativeSrc.startsWith("..")) relativeSrc = relative(join(ctx.pkgDir), src);
|
|
222
|
+
if (relativeSrc.startsWith("..")) throw new Error(`Source should be within the package directory (${ctx.pkgDir}): ${src}`);
|
|
223
|
+
const distName = join(dirname(relativeSrc), basename(relativeSrc, extname(relativeSrc)));
|
|
224
|
+
if (inputs[distName]) throw new Error(`Rename one of the entries to avoid a conflict in the dist name "${distName}":\n - ${src}\n - ${inputs[distName]}`);
|
|
225
|
+
inputs[distName] = src;
|
|
226
|
+
}
|
|
227
|
+
return inputs;
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
//#endregion
|
|
231
|
+
//#region src/builders/transform.ts
|
|
232
|
+
/**
|
|
233
|
+
* Transform all .ts modules in a directory using oxc-transform.
|
|
234
|
+
*/
|
|
235
|
+
async function transformDir(ctx, entry) {
|
|
236
|
+
if (entry.stub) {
|
|
237
|
+
consola.log(`${colors.magenta("[stub transform] ")} ${colors.underline(`${fmtPath(entry.outDir)}/`)}`);
|
|
238
|
+
await symlink(entry.input, entry.outDir, "junction");
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
const promises$1 = [];
|
|
242
|
+
for await (const entryName of await glob("**/*.*", { cwd: entry.input })) promises$1.push((async () => {
|
|
243
|
+
const entryPath = join(entry.input, entryName);
|
|
244
|
+
const ext = extname(entryPath);
|
|
245
|
+
switch (ext) {
|
|
246
|
+
case ".ts": {
|
|
247
|
+
const transformed = await transformModule(entryPath, entry);
|
|
248
|
+
const entryDistPath = join(entry.outDir, entryName.replace(/\.ts$/, ".mjs"));
|
|
249
|
+
await mkdir(dirname(entryDistPath), { recursive: true });
|
|
250
|
+
await writeFile(entryDistPath, transformed.code, "utf8");
|
|
251
|
+
if (SHEBANG_RE.test(transformed.code)) await makeExecutable(entryDistPath);
|
|
252
|
+
if (transformed.declaration) await writeFile(entryDistPath.replace(/\.mjs$/, ".d.mts"), transformed.declaration, "utf8");
|
|
253
|
+
return entryDistPath;
|
|
254
|
+
}
|
|
255
|
+
default: {
|
|
256
|
+
const entryDistPath = join(entry.outDir, entryName);
|
|
257
|
+
await mkdir(dirname(entryDistPath), { recursive: true });
|
|
258
|
+
const code = await readFile(entryPath, "utf8");
|
|
259
|
+
await writeFile(entryDistPath, code, "utf8");
|
|
260
|
+
if (SHEBANG_RE.test(code)) await makeExecutable(entryDistPath);
|
|
261
|
+
return entryDistPath;
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
})());
|
|
265
|
+
const writtenFiles = await Promise.all(promises$1);
|
|
266
|
+
consola.log(`\n${colors.magenta("[transform] ")}${colors.underline(`${fmtPath(entry.outDir)}/`)}\n${writtenFiles.map((f) => colors.dim(fmtPath(f))).join("\n\n")}`);
|
|
267
|
+
}
|
|
268
|
+
/**
|
|
269
|
+
* Transform a .ts module using oxc-transform.
|
|
270
|
+
*/
|
|
271
|
+
async function transformModule(entryPath, entry) {
|
|
272
|
+
let sourceText = await readFile(entryPath, "utf8");
|
|
273
|
+
const sourceOptions = {
|
|
274
|
+
lang: "ts",
|
|
275
|
+
sourceType: "module"
|
|
276
|
+
};
|
|
277
|
+
const parsed = oxcParser.parseSync(entryPath, sourceText, { ...sourceOptions });
|
|
278
|
+
if (parsed.errors.length > 0) throw new Error(`Errors while parsing ${entryPath}:`, { cause: parsed.errors });
|
|
279
|
+
const resolveOptions = {
|
|
280
|
+
...entry.resolve,
|
|
281
|
+
from: pathToFileURL(entryPath),
|
|
282
|
+
extensions: entry.resolve?.extensions ?? [
|
|
283
|
+
".ts",
|
|
284
|
+
".js",
|
|
285
|
+
".mjs",
|
|
286
|
+
".cjs",
|
|
287
|
+
".json"
|
|
288
|
+
],
|
|
289
|
+
suffixes: entry.resolve?.suffixes ?? ["", "/index"]
|
|
290
|
+
};
|
|
291
|
+
const magicString = new MagicString(sourceText);
|
|
292
|
+
const updatedStarts = /* @__PURE__ */ new Set();
|
|
293
|
+
const rewriteSpecifier = (req) => {
|
|
294
|
+
const moduleId = req.value;
|
|
295
|
+
if (!moduleId.startsWith(".")) return;
|
|
296
|
+
if (updatedStarts.has(req.start)) return;
|
|
297
|
+
updatedStarts.add(req.start);
|
|
298
|
+
const resolvedAbsolute = resolveModulePath(moduleId, resolveOptions);
|
|
299
|
+
const newId = relative(dirname(entryPath), resolvedAbsolute.replace(/\.ts$/, ".mjs"));
|
|
300
|
+
magicString.remove(req.start, req.end);
|
|
301
|
+
magicString.prependLeft(req.start, JSON.stringify(newId.startsWith(".") ? newId : `./${newId}`));
|
|
302
|
+
};
|
|
303
|
+
for (const staticImport of parsed.module.staticImports) rewriteSpecifier(staticImport.moduleRequest);
|
|
304
|
+
for (const staticExport of parsed.module.staticExports) for (const staticExportEntry of staticExport.entries) if (staticExportEntry.moduleRequest) rewriteSpecifier(staticExportEntry.moduleRequest);
|
|
305
|
+
sourceText = magicString.toString();
|
|
306
|
+
const transformed = oxcTransform.transform(entryPath, sourceText, {
|
|
307
|
+
...entry.oxc,
|
|
308
|
+
...sourceOptions,
|
|
309
|
+
cwd: dirname(entryPath),
|
|
310
|
+
typescript: {
|
|
311
|
+
declaration: { stripInternal: true },
|
|
312
|
+
...entry.oxc?.typescript
|
|
313
|
+
}
|
|
314
|
+
});
|
|
315
|
+
const transformErrors = transformed.errors.filter((err) => !err.message.includes("--isolatedDeclarations"));
|
|
316
|
+
if (transformErrors.length > 0) {
|
|
317
|
+
await writeFile("build-dump.ts", `/** Error dump for ${entryPath} */\n\n${sourceText}`, "utf8");
|
|
318
|
+
throw new Error(`Errors while transforming ${entryPath}: (hint: check build-dump.ts)`, { cause: transformErrors });
|
|
319
|
+
}
|
|
320
|
+
if (entry.minify) {
|
|
321
|
+
const res = minify(entryPath, transformed.code, entry.minify === true ? {} : entry.minify);
|
|
322
|
+
transformed.code = res.code;
|
|
323
|
+
transformed.map = res.map;
|
|
324
|
+
}
|
|
325
|
+
return transformed;
|
|
326
|
+
}
|
|
327
|
+
|
|
328
|
+
//#endregion
|
|
329
|
+
//#region src/build.ts
|
|
330
|
+
/**
|
|
331
|
+
* Build dist/ from src/
|
|
332
|
+
*/
|
|
333
|
+
async function build(config) {
|
|
334
|
+
const start = Date.now();
|
|
335
|
+
const pkgDir = normalizePath(config.cwd);
|
|
336
|
+
const pkg = await readJSON(join(pkgDir, "package.json")).catch(() => ({}));
|
|
337
|
+
const ctx = {
|
|
338
|
+
pkg,
|
|
339
|
+
pkgDir
|
|
340
|
+
};
|
|
341
|
+
consola.log(`📦 Building \`${ctx.pkg.name || "<no name>"}\` (\`${ctx.pkgDir}\`)`);
|
|
342
|
+
const hooks = config.hooks || {};
|
|
343
|
+
await hooks.start?.(ctx);
|
|
344
|
+
const entries = (config.entries || []).map((rawEntry) => {
|
|
345
|
+
let entry;
|
|
346
|
+
if (typeof rawEntry === "string") {
|
|
347
|
+
const [input, outDir] = rawEntry.split(":");
|
|
348
|
+
entry = input.endsWith("/") ? {
|
|
349
|
+
type: "transform",
|
|
350
|
+
input,
|
|
351
|
+
outDir
|
|
352
|
+
} : {
|
|
353
|
+
type: "bundle",
|
|
354
|
+
input: input.split(","),
|
|
355
|
+
outDir
|
|
356
|
+
};
|
|
357
|
+
} else entry = rawEntry;
|
|
358
|
+
if (!entry.input) throw new Error(`Build entry missing \`input\`: ${JSON.stringify(entry, null, 2)}`);
|
|
359
|
+
entry = { ...entry };
|
|
360
|
+
entry.outDir = normalizePath(entry.outDir || "dist", pkgDir);
|
|
361
|
+
entry.input = Array.isArray(entry.input) ? entry.input.map((p) => normalizePath(p, pkgDir)) : normalizePath(entry.input, pkgDir);
|
|
362
|
+
return entry;
|
|
363
|
+
});
|
|
364
|
+
await hooks.entries?.(entries, ctx);
|
|
365
|
+
const outDirs = [];
|
|
366
|
+
for (const outDir of entries.map((e) => e.outDir).sort()) if (!outDirs.some((dir) => outDir.startsWith(dir))) outDirs.push(outDir);
|
|
367
|
+
for (const outDir of outDirs) {
|
|
368
|
+
consola.log(`🧻 Cleaning up \`${fmtPath(outDir)}\``);
|
|
369
|
+
await rm(outDir, {
|
|
370
|
+
recursive: true,
|
|
371
|
+
force: true
|
|
372
|
+
});
|
|
373
|
+
}
|
|
374
|
+
for (const entry of entries) await (entry.type === "bundle" ? rolldownBuild(ctx, entry, hooks) : transformDir(ctx, entry));
|
|
375
|
+
await hooks.end?.(ctx);
|
|
376
|
+
const dirSize = analyzeDir(outDirs);
|
|
377
|
+
consola.log(colors.dim(`\nΣ Total dist byte size: ${colors.underline(prettyBytes(dirSize.size))} (${colors.underline(dirSize.files)} files)`));
|
|
378
|
+
consola.log(`\n✅ robuild finished in ${Date.now() - start}ms`);
|
|
379
|
+
}
|
|
380
|
+
function normalizePath(path, resolveFrom) {
|
|
381
|
+
return typeof path === "string" && isAbsolute(path) ? path : path instanceof URL ? fileURLToPath(path) : resolve(resolveFrom || ".", path || ".");
|
|
382
|
+
}
|
|
383
|
+
function readJSON(specifier) {
|
|
384
|
+
return import(specifier, { with: { type: "json" } }).then((r) => r.default);
|
|
385
|
+
}
|
|
386
|
+
|
|
387
|
+
//#endregion
|
|
388
|
+
export { build };
|
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import { ResolveOptions } from "exsolve";
|
|
2
|
+
import { InputOptions, MinifyOptions, OutputOptions, RolldownBuild, RolldownPluginOption } from "rolldown";
|
|
3
|
+
import { Options } from "rolldown-plugin-dts";
|
|
4
|
+
import { MinifyOptions as MinifyOptions$1 } from "oxc-minify";
|
|
5
|
+
import { TransformOptions } from "oxc-transform";
|
|
6
|
+
|
|
7
|
+
//#region src/types.d.ts
|
|
8
|
+
interface BuildContext {
|
|
9
|
+
pkgDir: string;
|
|
10
|
+
pkg: {
|
|
11
|
+
name: string;
|
|
12
|
+
} & Record<string, unknown>;
|
|
13
|
+
}
|
|
14
|
+
interface _BuildEntry {
|
|
15
|
+
/**
|
|
16
|
+
* Output directory relative to project root.
|
|
17
|
+
*
|
|
18
|
+
* Defaults to `dist/` if not provided.
|
|
19
|
+
*/
|
|
20
|
+
outDir?: string;
|
|
21
|
+
/**
|
|
22
|
+
* Avoid actual build but instead link to the source files.
|
|
23
|
+
*/
|
|
24
|
+
stub?: boolean;
|
|
25
|
+
}
|
|
26
|
+
type BundleEntry = _BuildEntry & {
|
|
27
|
+
type: "bundle";
|
|
28
|
+
/**
|
|
29
|
+
* Entry point(s) to bundle relative to the project root.
|
|
30
|
+
*/
|
|
31
|
+
input: string | string[];
|
|
32
|
+
/**
|
|
33
|
+
* Minify the output using rolldown.
|
|
34
|
+
*
|
|
35
|
+
* Defaults to `false` if not provided.
|
|
36
|
+
*/
|
|
37
|
+
minify?: boolean | "dce-only" | MinifyOptions;
|
|
38
|
+
/**
|
|
39
|
+
* Options passed to rolldown.
|
|
40
|
+
*
|
|
41
|
+
* See [rolldown config options](https://rolldown.rs/reference/config-options) for more details.
|
|
42
|
+
*/
|
|
43
|
+
rolldown?: InputOptions & {
|
|
44
|
+
plugins?: RolldownPluginOption[];
|
|
45
|
+
};
|
|
46
|
+
/**
|
|
47
|
+
* Declaration generation options.
|
|
48
|
+
*
|
|
49
|
+
* See [rolldown-plugin-dts](https://github.com/sxzz/rolldown-plugin-dts) for more details.
|
|
50
|
+
*
|
|
51
|
+
* Options are inferred from the `tsconfig.json` file if available.
|
|
52
|
+
*
|
|
53
|
+
* Set to `false` to disable.
|
|
54
|
+
*/
|
|
55
|
+
dts?: boolean | Options;
|
|
56
|
+
};
|
|
57
|
+
type TransformEntry = _BuildEntry & {
|
|
58
|
+
type: "transform";
|
|
59
|
+
/**
|
|
60
|
+
* Directory to transform relative to the project root.
|
|
61
|
+
*/
|
|
62
|
+
input: string;
|
|
63
|
+
/**
|
|
64
|
+
* Minify the output using oxc-minify.
|
|
65
|
+
*
|
|
66
|
+
* Defaults to `false` if not provided.
|
|
67
|
+
*/
|
|
68
|
+
minify?: boolean | MinifyOptions$1;
|
|
69
|
+
/**
|
|
70
|
+
* Options passed to oxc-transform.
|
|
71
|
+
*
|
|
72
|
+
* See [oxc-transform](https://www.npmjs.com/package/oxc-transform) for more details.
|
|
73
|
+
*/
|
|
74
|
+
oxc?: TransformOptions;
|
|
75
|
+
/**
|
|
76
|
+
* Options passed to exsolve for module resolution.
|
|
77
|
+
*
|
|
78
|
+
* See [exsolve](https://github.com/unjs/exsolve) for more details.
|
|
79
|
+
*/
|
|
80
|
+
resolve?: Omit<ResolveOptions, "from">;
|
|
81
|
+
};
|
|
82
|
+
type BuildEntry = BundleEntry | TransformEntry;
|
|
83
|
+
interface BuildHooks {
|
|
84
|
+
start?: (ctx: BuildContext) => void | Promise<void>;
|
|
85
|
+
end?: (ctx: BuildContext) => void | Promise<void>;
|
|
86
|
+
entries?: (entries: BuildEntry[], ctx: BuildContext) => void | Promise<void>;
|
|
87
|
+
rolldownConfig?: (cfg: InputOptions, ctx: BuildContext) => void | Promise<void>;
|
|
88
|
+
rolldownOutput?: (cfg: OutputOptions, res: RolldownBuild, ctx: BuildContext) => void | Promise<void>;
|
|
89
|
+
}
|
|
90
|
+
interface BuildConfig {
|
|
91
|
+
cwd?: string | URL;
|
|
92
|
+
entries?: (BuildEntry | string)[];
|
|
93
|
+
hooks?: BuildHooks;
|
|
94
|
+
}
|
|
95
|
+
//#endregion
|
|
96
|
+
export { BuildConfig, BuildEntry, BundleEntry, TransformEntry };
|
package/dist/cli.d.mts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { };
|
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { build } from "./_chunks/build-Dn4aJvxA.mjs";
|
|
3
|
+
import { consola } from "consola";
|
|
4
|
+
import { parseArgs } from "node:util";
|
|
5
|
+
import { loadConfig } from "c12";
|
|
6
|
+
|
|
7
|
+
//#region src/cli.ts
|
|
8
|
+
const args = parseArgs({
|
|
9
|
+
args: process.argv.slice(2),
|
|
10
|
+
allowPositionals: true,
|
|
11
|
+
options: {
|
|
12
|
+
dir: {
|
|
13
|
+
type: "string",
|
|
14
|
+
default: "."
|
|
15
|
+
},
|
|
16
|
+
stub: {
|
|
17
|
+
type: "boolean",
|
|
18
|
+
default: false
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
const { config = {} } = await loadConfig({
|
|
23
|
+
name: "robuild",
|
|
24
|
+
configFile: "build.config",
|
|
25
|
+
cwd: args.values.dir
|
|
26
|
+
});
|
|
27
|
+
const rawEntries = args.positionals.length > 0 ? args.positionals : config.entries || [];
|
|
28
|
+
const entries = rawEntries.map((entry) => {
|
|
29
|
+
if (typeof entry === "string") {
|
|
30
|
+
const [input, outDir] = entry.split(":");
|
|
31
|
+
return input.endsWith("/") ? {
|
|
32
|
+
type: "transform",
|
|
33
|
+
input,
|
|
34
|
+
outDir
|
|
35
|
+
} : {
|
|
36
|
+
type: "bundle",
|
|
37
|
+
input: input.split(","),
|
|
38
|
+
outDir
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
return entry;
|
|
42
|
+
});
|
|
43
|
+
if (args.values.stub) for (const entry of entries) entry.stub = true;
|
|
44
|
+
if (rawEntries.length === 0) {
|
|
45
|
+
consola.error("No build entries specified.");
|
|
46
|
+
process.exit(1);
|
|
47
|
+
}
|
|
48
|
+
await build({
|
|
49
|
+
cwd: args.values.dir,
|
|
50
|
+
...config,
|
|
51
|
+
entries
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
//#endregion
|
package/dist/config.mjs
ADDED
package/dist/index.d.mts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { BuildConfig, BuildEntry, BundleEntry, TransformEntry } from "./_chunks/types-1AA9vjTS.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/build.d.ts
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Build dist/ from src/
|
|
7
|
+
*/
|
|
8
|
+
declare function build(config: BuildConfig): Promise<void>;
|
|
9
|
+
//#endregion
|
|
10
|
+
export { BuildConfig, BuildEntry, BundleEntry, TransformEntry, build };
|
package/dist/index.mjs
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "robuild",
|
|
3
|
+
"type": "module",
|
|
4
|
+
"version": "0.0.2",
|
|
5
|
+
"packageManager": "pnpm@10.11.1",
|
|
6
|
+
"description": "Zero-config ESM/TS package builder. Powered by Rolldown and Oxc",
|
|
7
|
+
"license": "MIT",
|
|
8
|
+
"repository": "Sunny-117/robuild",
|
|
9
|
+
"sideEffects": false,
|
|
10
|
+
"exports": {
|
|
11
|
+
".": "./dist/index.mjs",
|
|
12
|
+
"./config": "./dist/config.mjs"
|
|
13
|
+
},
|
|
14
|
+
"types": "./dist/index.d.mts",
|
|
15
|
+
"bin": "./dist/cli.mjs",
|
|
16
|
+
"files": [
|
|
17
|
+
"dist"
|
|
18
|
+
],
|
|
19
|
+
"scripts": {
|
|
20
|
+
"build": "pnpm robuild",
|
|
21
|
+
"dev": "pnpm vitest",
|
|
22
|
+
"lint": "eslint .",
|
|
23
|
+
"lint:fix": "automd && eslint . --fix",
|
|
24
|
+
"robuild": "esno src/cli.ts",
|
|
25
|
+
"prepack": "pnpm build",
|
|
26
|
+
"release": "pnpm test && changelogen --release && npm publish && git push --follow-tags",
|
|
27
|
+
"test": "pnpm lint && pnpm test:types",
|
|
28
|
+
"test:types": "tsc --noEmit --skipLibCheck"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"c12": "^3.0.4",
|
|
32
|
+
"consola": "^3.4.2",
|
|
33
|
+
"defu": "^6.1.4",
|
|
34
|
+
"exsolve": "^1.0.5",
|
|
35
|
+
"magic-string": "^0.30.17",
|
|
36
|
+
"oxc-minify": "^0.72.3",
|
|
37
|
+
"oxc-parser": "^0.72.3",
|
|
38
|
+
"oxc-transform": "^0.72.3",
|
|
39
|
+
"pretty-bytes": "^7.0.0",
|
|
40
|
+
"rolldown": "1.0.0-beta.12",
|
|
41
|
+
"rolldown-plugin-dts": "^0.13.8",
|
|
42
|
+
"tinyglobby": "^0.2.14"
|
|
43
|
+
},
|
|
44
|
+
"devDependencies": {
|
|
45
|
+
"@antfu/eslint-config": "^4.17.0",
|
|
46
|
+
"@types/node": "^22.15.30",
|
|
47
|
+
"@vitest/coverage-v8": "^3.2.2",
|
|
48
|
+
"automd": "^0.4.0",
|
|
49
|
+
"changelogen": "^0.6.1",
|
|
50
|
+
"eslint": "^9.28.0",
|
|
51
|
+
"esno": "^4.8.0",
|
|
52
|
+
"prettier": "^3.5.3",
|
|
53
|
+
"typescript": "^5.8.3",
|
|
54
|
+
"vitest": "^3.2.2"
|
|
55
|
+
}
|
|
56
|
+
}
|