@liuli-util/cli 3.9.0 → 3.11.0
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/CHANGELOG.md +41 -0
- package/README.md +3 -3
- package/_gitignore +33 -0
- package/dist/PathUtil.d.ts +7 -0
- package/dist/PathUtil.d.ts.map +1 -0
- package/dist/bin.d.ts +1 -1
- package/dist/bin.js +116 -1
- package/dist/bin.js.map +7 -1
- package/dist/commands/esbuild/ESBuildProgram.d.ts +71 -0
- package/dist/commands/esbuild/ESBuildProgram.d.ts.map +1 -0
- package/dist/commands/esbuild/index.d.ts +3 -0
- package/dist/commands/esbuild/index.d.ts.map +1 -0
- package/dist/commands/esbuild/util/debounce.d.ts +15 -0
- package/dist/commands/esbuild/util/debounce.d.ts.map +1 -0
- package/dist/commands/esbuild/util/esbuildPlugins.d.ts +16 -0
- package/dist/commands/esbuild/util/esbuildPlugins.d.ts.map +1 -0
- package/dist/commands/generate/GenerateProgram.d.ts +18 -0
- package/dist/commands/generate/GenerateProgram.d.ts.map +1 -0
- package/dist/commands/generate/index.d.ts +3 -0
- package/dist/commands/generate/index.d.ts.map +1 -0
- package/dist/commands/sync/SyncProgram.d.ts +15 -0
- package/dist/commands/sync/SyncProgram.d.ts.map +1 -0
- package/dist/commands/sync/index.d.ts +3 -0
- package/dist/commands/sync/index.d.ts.map +1 -0
- package/dist/commands/sync/when.d.ts +21 -0
- package/dist/commands/sync/when.d.ts.map +1 -0
- package/dist/index.d.ts +3 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.esm.js +5 -1
- package/dist/index.esm.js.map +7 -1
- package/dist/index.js +5 -1
- package/dist/index.js.map +7 -1
- package/dist/utils/AsyncArray.d.ts +21 -0
- package/dist/utils/AsyncArray.d.ts.map +1 -0
- package/dist/utils/appendScript.d.ts +7 -0
- package/dist/utils/appendScript.d.ts.map +1 -0
- package/dist/utils/arrayToMap.d.ts +3 -0
- package/dist/utils/arrayToMap.d.ts.map +1 -0
- package/dist/utils/findParent.d.ts +8 -0
- package/dist/utils/findParent.d.ts.map +1 -0
- package/dist/utils/index.d.ts +5 -0
- package/dist/utils/index.d.ts.map +1 -0
- package/package.json +34 -22
- package/src/@types/global.d.ts +8 -0
- package/src/PathUtil.ts +8 -0
- package/src/bin.ts +5 -5
- package/src/commands/esbuild/ESBuildProgram.ts +288 -0
- package/src/commands/esbuild/__tests__/ESBuildProgram.test.ts +125 -0
- package/src/commands/esbuild/__tests__/spinnies.test.ts +11 -0
- package/src/commands/esbuild/index.ts +32 -0
- package/src/commands/esbuild/util/debounce.ts +29 -0
- package/src/commands/esbuild/util/esbuildPlugins.ts +82 -0
- package/src/commands/generate/GenerateProgram.ts +115 -0
- package/src/commands/generate/__tests__/GenerateProgram.test.ts +51 -0
- package/src/commands/generate/index.ts +26 -0
- package/src/commands/sync/SyncProgram.ts +247 -0
- package/src/commands/sync/__tests__/SyncProgram.test.ts +50 -0
- package/src/commands/sync/__tests__/when.test.ts +46 -0
- package/src/commands/sync/index.ts +15 -0
- package/src/commands/sync/when.ts +67 -0
- package/src/index.ts +3 -1
- package/src/utils/AsyncArray.ts +144 -0
- package/src/utils/__tests__/appendScript.test.ts +15 -0
- package/src/utils/__tests__/arrayToMap.test.ts +37 -0
- package/src/utils/__tests__/findParent.test.ts +15 -0
- package/src/utils/appendScript.ts +17 -0
- package/src/utils/arrayToMap.ts +27 -0
- package/src/utils/findParent.ts +36 -0
- package/src/utils/index.ts +4 -0
- package/templates/cli/CHANGELOG.md +1 -0
- package/templates/cli/README.md +1 -0
- package/templates/cli/package.json +44 -0
- package/templates/cli/src/bin.ts +13 -0
- package/templates/cli/src/index.ts +1 -0
- package/templates/cli/tsconfig.json +28 -0
- package/templates/lib/CHANGELOG.md +1 -0
- package/templates/lib/README.md +1 -0
- package/templates/lib/package.json +32 -0
- package/templates/lib/src/__tests__/hello.test.ts +5 -0
- package/templates/lib/src/index.ts +3 -0
- package/templates/lib/tsconfig.json +28 -0
- package/tsconfig.json +34 -28
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"findParent.d.ts","sourceRoot":"","sources":["../../src/utils/findParent.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,wBAAgB,UAAU,CACxB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,GAClC,MAAM,GAAG,IAAI,CAAA;AAChB,wBAAgB,UAAU,CACxB,GAAG,EAAE,MAAM,EACX,SAAS,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAC3C,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/utils/index.ts"],"names":[],"mappings":"AAAA,cAAc,cAAc,CAAA;AAC5B,cAAc,gBAAgB,CAAA;AAC9B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@liuli-util/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.11.0",
|
|
4
4
|
"description": "一个针对于库和 CLI 应用程序打包的零配置 CLI",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.esm.js",
|
|
@@ -8,43 +8,55 @@
|
|
|
8
8
|
"license": "MIT",
|
|
9
9
|
"scripts": {
|
|
10
10
|
"setup": "yarn build",
|
|
11
|
-
"start": "ts-node src/bin.ts",
|
|
12
11
|
"build": "rimraf dist && yarn start build cli",
|
|
13
|
-
"dev": "yarn start build cli -w"
|
|
12
|
+
"dev": "yarn start build cli -w",
|
|
13
|
+
"start": "esno src/bin.ts"
|
|
14
14
|
},
|
|
15
|
+
"workspaces": [
|
|
16
|
+
"templates/*"
|
|
17
|
+
],
|
|
15
18
|
"bin": {
|
|
16
19
|
"liuli-cli": "dist/bin.js"
|
|
17
20
|
},
|
|
18
21
|
"jest": {
|
|
19
|
-
"preset": "ts-jest"
|
|
22
|
+
"preset": "ts-jest",
|
|
23
|
+
"moduleNameMapper": {
|
|
24
|
+
"lodash-es": "lodash"
|
|
25
|
+
}
|
|
20
26
|
},
|
|
21
27
|
"publishConfig": {
|
|
22
28
|
"access": "public",
|
|
23
29
|
"registry": "https://registry.npmjs.org/"
|
|
24
30
|
},
|
|
25
31
|
"dependencies": {
|
|
26
|
-
"@liuli-util/
|
|
27
|
-
"@liuli-util/
|
|
28
|
-
"@liuli-util/
|
|
29
|
-
"
|
|
30
|
-
"
|
|
32
|
+
"@liuli-util/commitlint-standard-config": "^0.1.6",
|
|
33
|
+
"@liuli-util/eslint-config-react-ts": "^0.1.0",
|
|
34
|
+
"@liuli-util/eslint-config-ts": "^0.2.0",
|
|
35
|
+
"@liuli-util/prettier-standard-config": "^0.1.0",
|
|
36
|
+
"chokidar": "^3.5.2",
|
|
37
|
+
"commander": "^8.2.0",
|
|
38
|
+
"enquirer": "^2.3.6",
|
|
39
|
+
"esbuild": "^0.13.2",
|
|
31
40
|
"fs-extra": "^10.0.0",
|
|
32
|
-
"
|
|
33
|
-
"
|
|
41
|
+
"glob": "^7.2.0",
|
|
42
|
+
"glob-promise": "^4.2.0",
|
|
43
|
+
"lodash-es": "^4.17.21",
|
|
44
|
+
"spinnies": "^0.5.1",
|
|
45
|
+
"ts-morph": "^12.0.0"
|
|
34
46
|
},
|
|
35
47
|
"devDependencies": {
|
|
36
|
-
"@types/fs-extra": "^9.0.
|
|
37
|
-
"@types/
|
|
38
|
-
"@types/jest": "^
|
|
39
|
-
"@types/lodash": "^4.
|
|
40
|
-
"@types/node": "^
|
|
41
|
-
"
|
|
42
|
-
"jest": "^
|
|
48
|
+
"@types/fs-extra": "^9.0.13",
|
|
49
|
+
"@types/glob": "^7",
|
|
50
|
+
"@types/jest": "^27.0.2",
|
|
51
|
+
"@types/lodash-es": "^4.17.5",
|
|
52
|
+
"@types/node": "^16.9.6",
|
|
53
|
+
"esno": "^0.9.1",
|
|
54
|
+
"jest": "^27.2.1",
|
|
55
|
+
"lodash": "^4.17.21",
|
|
43
56
|
"rimraf": "^3.0.2",
|
|
44
|
-
"ts-jest": "^
|
|
45
|
-
"
|
|
46
|
-
"
|
|
47
|
-
"typescript": "^4.3.4"
|
|
57
|
+
"ts-jest": "^27.0.5",
|
|
58
|
+
"type-fest": "^2.3.4",
|
|
59
|
+
"typescript": "^4.4.3"
|
|
48
60
|
},
|
|
49
61
|
"repository": {
|
|
50
62
|
"type": "git",
|
package/src/PathUtil.ts
ADDED
package/src/bin.ts
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { Command } from 'commander'
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
2
|
+
import { esbuildCommand } from './commands/esbuild'
|
|
3
|
+
import { generateCommand } from './commands/generate'
|
|
4
|
+
import { syncCommand } from './commands/sync'
|
|
5
5
|
|
|
6
6
|
const main = new Command()
|
|
7
7
|
main
|
|
8
|
-
.addCommand(
|
|
9
|
-
.addCommand(
|
|
8
|
+
.addCommand(esbuildCommand)
|
|
9
|
+
.addCommand(generateCommand)
|
|
10
10
|
.addCommand(syncCommand)
|
|
11
11
|
.parse()
|
|
@@ -0,0 +1,288 @@
|
|
|
1
|
+
import { build, BuildOptions, Platform, Plugin } from 'esbuild'
|
|
2
|
+
import { pathExists, readJson } from 'fs-extra'
|
|
3
|
+
import * as path from 'path'
|
|
4
|
+
import { PackageJson } from 'type-fest'
|
|
5
|
+
import { Project } from 'ts-morph'
|
|
6
|
+
import { promise } from 'glob-promise'
|
|
7
|
+
import { IOptions } from 'glob'
|
|
8
|
+
import { nativeNodeModules, nodeExternals } from './util/esbuildPlugins'
|
|
9
|
+
import { watch } from 'chokidar'
|
|
10
|
+
import Spinnies from 'spinnies'
|
|
11
|
+
import { debounce } from './util/debounce'
|
|
12
|
+
|
|
13
|
+
interface ESBuildProgramOptions {
|
|
14
|
+
base: string
|
|
15
|
+
isWatch: boolean
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface Task {
|
|
19
|
+
title: string
|
|
20
|
+
task(): Promise<any>
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class ESBuildProgram {
|
|
24
|
+
constructor(private readonly options: ESBuildProgramOptions) {}
|
|
25
|
+
|
|
26
|
+
static readonly globalExternal = ['esbuild', 'pnpapi', 'ts-morph']
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* 获取所有依赖
|
|
30
|
+
*/
|
|
31
|
+
static async getDeps(base: string): Promise<string[]> {
|
|
32
|
+
const json = (await readJson(
|
|
33
|
+
path.resolve(base, 'package.json'),
|
|
34
|
+
)) as PackageJson
|
|
35
|
+
return Object.keys({
|
|
36
|
+
...json.dependencies,
|
|
37
|
+
...json.devDependencies,
|
|
38
|
+
...json.peerDependencies,
|
|
39
|
+
})
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* 获取所在模块的类型
|
|
44
|
+
*/
|
|
45
|
+
static async getPlatform(base: string): Promise<Platform> {
|
|
46
|
+
const tsconfigPath = path.resolve(base, 'tsconfig.json')
|
|
47
|
+
if (await pathExists(tsconfigPath)) {
|
|
48
|
+
const tsconfigJson = await readJson(tsconfigPath)
|
|
49
|
+
if (
|
|
50
|
+
(tsconfigJson.compilerOptions.lib as string[]).some(
|
|
51
|
+
(lib) => lib.toLowerCase() === 'dom',
|
|
52
|
+
)
|
|
53
|
+
) {
|
|
54
|
+
return 'browser'
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
const pkgPath = path.resolve(base, 'package.json')
|
|
58
|
+
if (await pathExists(pkgPath)) {
|
|
59
|
+
const pkgJson = (await readJson(pkgPath)) as PackageJson
|
|
60
|
+
if (Object.keys(pkgJson.devDependencies ?? {}).includes('@types/node')) {
|
|
61
|
+
return 'node'
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
return 'neutral'
|
|
65
|
+
}
|
|
66
|
+
static getWatchOptions(base: string): {
|
|
67
|
+
pattern: string
|
|
68
|
+
options: IOptions
|
|
69
|
+
} {
|
|
70
|
+
const pattern = 'src/**/*.ts'
|
|
71
|
+
const options: Pick<IOptions, 'cwd' | 'ignore'> = {
|
|
72
|
+
cwd: base,
|
|
73
|
+
ignore: '**/__tests__/**/*',
|
|
74
|
+
}
|
|
75
|
+
return { pattern, options }
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* 生成类型定义
|
|
79
|
+
*/
|
|
80
|
+
async genDTS(): Promise<void> {
|
|
81
|
+
const base = this.options.base
|
|
82
|
+
const { pattern, options } = ESBuildProgram.getWatchOptions(
|
|
83
|
+
this.options.base,
|
|
84
|
+
)
|
|
85
|
+
const project = new Project({
|
|
86
|
+
tsConfigFilePath: path.resolve(base, 'tsconfig.json'),
|
|
87
|
+
skipAddingFilesFromTsConfig: true,
|
|
88
|
+
compilerOptions: {
|
|
89
|
+
emitDeclarationOnly: true,
|
|
90
|
+
noEmit: false,
|
|
91
|
+
incremental: this.options.isWatch,
|
|
92
|
+
},
|
|
93
|
+
})
|
|
94
|
+
const fileList = (await promise(pattern, options)).map((filePath) =>
|
|
95
|
+
path.resolve(base, filePath),
|
|
96
|
+
)
|
|
97
|
+
project.addSourceFilesAtPaths(fileList)
|
|
98
|
+
await project.emit({
|
|
99
|
+
emitOnlyDtsFiles: true,
|
|
100
|
+
})
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* 获取构建 cjs 的选项
|
|
105
|
+
* @param deps
|
|
106
|
+
* @param platform
|
|
107
|
+
* @param plugins
|
|
108
|
+
*/
|
|
109
|
+
getBuildCjsOption({
|
|
110
|
+
deps,
|
|
111
|
+
platform,
|
|
112
|
+
}: {
|
|
113
|
+
deps: string[]
|
|
114
|
+
platform: Platform
|
|
115
|
+
}): BuildOptions {
|
|
116
|
+
return {
|
|
117
|
+
outfile: './dist/index.js',
|
|
118
|
+
format: 'cjs',
|
|
119
|
+
sourcemap: true,
|
|
120
|
+
entryPoints: ['./src/index.ts'],
|
|
121
|
+
bundle: true,
|
|
122
|
+
external: [...ESBuildProgram.globalExternal, ...deps],
|
|
123
|
+
platform: platform,
|
|
124
|
+
minify: !this.options.isWatch,
|
|
125
|
+
incremental: this.options.isWatch,
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* 获取构建 esm 的选项
|
|
131
|
+
* @param deps
|
|
132
|
+
* @param platform
|
|
133
|
+
* @param plugins
|
|
134
|
+
*/
|
|
135
|
+
getBuildESMOption({
|
|
136
|
+
deps,
|
|
137
|
+
platform,
|
|
138
|
+
}: {
|
|
139
|
+
deps: string[]
|
|
140
|
+
platform: Platform
|
|
141
|
+
}): BuildOptions {
|
|
142
|
+
return {
|
|
143
|
+
outfile: './dist/index.esm.js',
|
|
144
|
+
format: 'esm',
|
|
145
|
+
sourcemap: true,
|
|
146
|
+
entryPoints: ['./src/index.ts'],
|
|
147
|
+
bundle: true,
|
|
148
|
+
external: [...ESBuildProgram.globalExternal, ...deps],
|
|
149
|
+
platform: platform,
|
|
150
|
+
minify: !this.options.isWatch,
|
|
151
|
+
incremental: this.options.isWatch,
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
/**
|
|
156
|
+
* 获取构建 cli 的选项
|
|
157
|
+
* @param deps
|
|
158
|
+
* @param platform
|
|
159
|
+
* @param plugins
|
|
160
|
+
*/
|
|
161
|
+
getBuildCliOption({
|
|
162
|
+
deps,
|
|
163
|
+
platform,
|
|
164
|
+
}: {
|
|
165
|
+
deps: string[]
|
|
166
|
+
platform: Platform
|
|
167
|
+
}): BuildOptions {
|
|
168
|
+
const plugins = ESBuildProgram.getPlugins(platform)
|
|
169
|
+
return {
|
|
170
|
+
entryPoints: ['./src/bin.ts'],
|
|
171
|
+
outfile: './dist/bin.js',
|
|
172
|
+
format: 'cjs',
|
|
173
|
+
sourcemap: true,
|
|
174
|
+
platform: platform,
|
|
175
|
+
bundle: true,
|
|
176
|
+
banner: {
|
|
177
|
+
js: '#!/usr/bin/env node',
|
|
178
|
+
},
|
|
179
|
+
external: [
|
|
180
|
+
...ESBuildProgram.globalExternal,
|
|
181
|
+
...(this.options.isWatch ? deps : []),
|
|
182
|
+
],
|
|
183
|
+
plugins,
|
|
184
|
+
minify: !this.options.isWatch,
|
|
185
|
+
incremental: this.options.isWatch,
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
static getPlugins(platform: string): Plugin[] {
|
|
190
|
+
const plugins: Plugin[] = []
|
|
191
|
+
if (platform === 'node') {
|
|
192
|
+
plugins.push(nodeExternals(), nativeNodeModules())
|
|
193
|
+
}
|
|
194
|
+
return plugins
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
async buildLib(): Promise<void> {
|
|
198
|
+
await this.build(this.getBuildLibTask.bind(this))
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
async buildCli(): Promise<void> {
|
|
202
|
+
await this.build(this.getBuildCliTask.bind(this))
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
getBuildLibTask(deps: string[], platform: Platform): Task[] {
|
|
206
|
+
return [
|
|
207
|
+
{
|
|
208
|
+
title: '构建 esm',
|
|
209
|
+
task: () =>
|
|
210
|
+
build(
|
|
211
|
+
this.getBuildESMOption({
|
|
212
|
+
deps: deps,
|
|
213
|
+
platform: platform,
|
|
214
|
+
}),
|
|
215
|
+
),
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
title: '构建 cjs',
|
|
219
|
+
task: () =>
|
|
220
|
+
build(
|
|
221
|
+
this.getBuildCjsOption({
|
|
222
|
+
deps: deps,
|
|
223
|
+
platform: platform,
|
|
224
|
+
}),
|
|
225
|
+
),
|
|
226
|
+
},
|
|
227
|
+
{
|
|
228
|
+
title: '生成类型定义',
|
|
229
|
+
task: () => this.genDTS(),
|
|
230
|
+
},
|
|
231
|
+
]
|
|
232
|
+
}
|
|
233
|
+
getBuildCliTask(deps: string[], platform: Platform): Task[] {
|
|
234
|
+
return [
|
|
235
|
+
{
|
|
236
|
+
title: '构建 cli',
|
|
237
|
+
task: () =>
|
|
238
|
+
build(
|
|
239
|
+
this.getBuildCliOption({
|
|
240
|
+
deps: deps,
|
|
241
|
+
platform: platform,
|
|
242
|
+
}),
|
|
243
|
+
),
|
|
244
|
+
},
|
|
245
|
+
...this.getBuildLibTask(deps, platform),
|
|
246
|
+
]
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
static async execTask(spinnies: Spinnies, task: Task): Promise<void> {
|
|
250
|
+
const start = Date.now()
|
|
251
|
+
spinnies.add(task.title, { text: task.title })
|
|
252
|
+
try {
|
|
253
|
+
await task.task()
|
|
254
|
+
spinnies.succeed(task.title, {
|
|
255
|
+
text: `${task.title}: ${Date.now() - start}ms`,
|
|
256
|
+
})
|
|
257
|
+
} catch (e) {
|
|
258
|
+
spinnies.fail(task.title, { text: task.title })
|
|
259
|
+
}
|
|
260
|
+
}
|
|
261
|
+
async build(
|
|
262
|
+
genTasks: (deps: string[], platform: Platform) => Task[],
|
|
263
|
+
): Promise<void> {
|
|
264
|
+
const run = async () => {
|
|
265
|
+
const start = Date.now()
|
|
266
|
+
const deps = await ESBuildProgram.getDeps(this.options.base)
|
|
267
|
+
const platform = await ESBuildProgram.getPlatform(this.options.base)
|
|
268
|
+
const tasks = genTasks(deps, platform)
|
|
269
|
+
const spinnies = new Spinnies()
|
|
270
|
+
await Promise.all(
|
|
271
|
+
tasks.map(async (task) => ESBuildProgram.execTask(spinnies, task)),
|
|
272
|
+
)
|
|
273
|
+
console.log(`构建完成: ${Date.now() - start}ms`)
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
if (!this.options.isWatch) {
|
|
277
|
+
await run()
|
|
278
|
+
return
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
const { pattern, options } = ESBuildProgram.getWatchOptions(
|
|
282
|
+
this.options.base,
|
|
283
|
+
)
|
|
284
|
+
await new Promise((resolve, reject) => {
|
|
285
|
+
watch(pattern, options).on('error', reject).on('all', debounce(run, 10))
|
|
286
|
+
})
|
|
287
|
+
}
|
|
288
|
+
}
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { ESBuildProgram } from '../ESBuildProgram'
|
|
2
|
+
import * as path from 'path'
|
|
3
|
+
import { mkdirp, pathExists, remove, writeJson } from 'fs-extra'
|
|
4
|
+
import { PackageJson } from 'type-fest'
|
|
5
|
+
import { build, Platform, Plugin } from 'esbuild'
|
|
6
|
+
import { nativeNodeModules, nodeExternals } from '../util/esbuildPlugins'
|
|
7
|
+
|
|
8
|
+
describe('测试 ESBuildProgram', () => {
|
|
9
|
+
describe('测试 getPlatform', () => {
|
|
10
|
+
const base: string = path.resolve(__dirname, '.temp/getPlatform')
|
|
11
|
+
beforeEach(async () => {
|
|
12
|
+
await remove(base)
|
|
13
|
+
await mkdirp(base)
|
|
14
|
+
})
|
|
15
|
+
it('测试 node 类型', async () => {
|
|
16
|
+
await writeJson(path.resolve(base, 'package.json'), {
|
|
17
|
+
devDependencies: {
|
|
18
|
+
'@types/node': '16',
|
|
19
|
+
},
|
|
20
|
+
} as PackageJson)
|
|
21
|
+
expect(await ESBuildProgram.getPlatform(base)).toBe('node' as Platform)
|
|
22
|
+
})
|
|
23
|
+
it('测试浏览器类型', async () => {
|
|
24
|
+
await writeJson(path.resolve(base, 'tsconfig.json'), {
|
|
25
|
+
compilerOptions: {
|
|
26
|
+
lib: ['DOM'],
|
|
27
|
+
},
|
|
28
|
+
})
|
|
29
|
+
expect(await ESBuildProgram.getPlatform(base)).toBe('browser' as Platform)
|
|
30
|
+
})
|
|
31
|
+
it('测试通用类型', async () => {
|
|
32
|
+
expect(await ESBuildProgram.getPlatform(base)).toBe('neutral' as Platform)
|
|
33
|
+
})
|
|
34
|
+
})
|
|
35
|
+
describe('测试 getDeps', () => {
|
|
36
|
+
const base: string = path.resolve(__dirname, '.temp/getDeps')
|
|
37
|
+
beforeEach(async () => {
|
|
38
|
+
await remove(base)
|
|
39
|
+
await mkdirp(base)
|
|
40
|
+
})
|
|
41
|
+
it('基本示例', async () => {
|
|
42
|
+
await writeJson(path.resolve(base, 'package.json'), {
|
|
43
|
+
devDependencies: {
|
|
44
|
+
'@types/node': '16',
|
|
45
|
+
},
|
|
46
|
+
dependencies: {
|
|
47
|
+
ora: '^6',
|
|
48
|
+
},
|
|
49
|
+
peerDependencies: {
|
|
50
|
+
typescript: '^4',
|
|
51
|
+
},
|
|
52
|
+
} as PackageJson)
|
|
53
|
+
const res = (await ESBuildProgram.getDeps(base)).sort()
|
|
54
|
+
console.log(res)
|
|
55
|
+
expect(res).toEqual(['@types/node', 'ora', 'typescript'].sort())
|
|
56
|
+
})
|
|
57
|
+
})
|
|
58
|
+
describe('测试构建相关', () => {
|
|
59
|
+
const base: string = path.resolve()
|
|
60
|
+
const program = new ESBuildProgram({
|
|
61
|
+
base,
|
|
62
|
+
isWatch: false,
|
|
63
|
+
})
|
|
64
|
+
let deps: string[]
|
|
65
|
+
let platform: Platform
|
|
66
|
+
let plugins: Plugin[]
|
|
67
|
+
beforeEach(async () => {
|
|
68
|
+
await remove(path.resolve(base, 'dist'))
|
|
69
|
+
deps = await ESBuildProgram.getDeps(base)
|
|
70
|
+
platform = await ESBuildProgram.getPlatform(base)
|
|
71
|
+
plugins = ESBuildProgram.getPlugins(platform)
|
|
72
|
+
})
|
|
73
|
+
it('测试 genDTS', async () => {
|
|
74
|
+
await program.genDTS()
|
|
75
|
+
expect(
|
|
76
|
+
await pathExists(path.resolve(base, 'dist/index.d.ts')),
|
|
77
|
+
).toBeTruthy()
|
|
78
|
+
})
|
|
79
|
+
it('测试 getBuildCjsOption', async () => {
|
|
80
|
+
await build(
|
|
81
|
+
program.getBuildCjsOption({
|
|
82
|
+
deps: deps,
|
|
83
|
+
platform: platform,
|
|
84
|
+
}),
|
|
85
|
+
)
|
|
86
|
+
expect(await pathExists(path.resolve(base, 'dist/index.js'))).toBeTruthy()
|
|
87
|
+
})
|
|
88
|
+
it('测试 getBuildESMOption', async () => {
|
|
89
|
+
const option = program.getBuildESMOption({
|
|
90
|
+
deps: deps,
|
|
91
|
+
platform: platform,
|
|
92
|
+
})
|
|
93
|
+
console.log('option: ', deps, option)
|
|
94
|
+
await build(option)
|
|
95
|
+
expect(
|
|
96
|
+
await pathExists(path.resolve(base, 'dist/index.esm.js')),
|
|
97
|
+
).toBeTruthy()
|
|
98
|
+
})
|
|
99
|
+
it('测试 getBuildCliOption', async () => {
|
|
100
|
+
await build(
|
|
101
|
+
program.getBuildCliOption({
|
|
102
|
+
deps: deps,
|
|
103
|
+
platform: platform,
|
|
104
|
+
}),
|
|
105
|
+
)
|
|
106
|
+
expect(await pathExists(path.resolve(base, 'dist/bin.js'))).toBeTruthy()
|
|
107
|
+
})
|
|
108
|
+
})
|
|
109
|
+
})
|
|
110
|
+
it('测试 esbuild', async () => {
|
|
111
|
+
await build({
|
|
112
|
+
outfile: './dist/bin.js',
|
|
113
|
+
format: 'cjs',
|
|
114
|
+
sourcemap: true,
|
|
115
|
+
entryPoints: ['./src/bin.ts'],
|
|
116
|
+
bundle: true,
|
|
117
|
+
external: [
|
|
118
|
+
...ESBuildProgram.globalExternal,
|
|
119
|
+
// ...(await ESBuildProgram.getDeps(path.resolve())),
|
|
120
|
+
],
|
|
121
|
+
platform: 'node',
|
|
122
|
+
plugins: [nativeNodeModules(), nodeExternals()],
|
|
123
|
+
treeShaking: true,
|
|
124
|
+
})
|
|
125
|
+
})
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import Spinnies from 'spinnies'
|
|
2
|
+
|
|
3
|
+
it('测试 spinnies', async () => {
|
|
4
|
+
const wait = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms))
|
|
5
|
+
const spinnies = new Spinnies()
|
|
6
|
+
spinnies.add('a', { text: '开始任务 a' })
|
|
7
|
+
spinnies.add('b', { text: '开始任务 b' })
|
|
8
|
+
await wait(3000)
|
|
9
|
+
spinnies.succeed('a', { text: '成功运行任务 a' })
|
|
10
|
+
spinnies.fail('b', { text: '成功运行任务 b' })
|
|
11
|
+
})
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { Command } from 'commander'
|
|
2
|
+
import { ESBuildProgram } from './ESBuildProgram'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
|
|
5
|
+
export const esbuildCommand = new Command('build')
|
|
6
|
+
.addCommand(
|
|
7
|
+
new Command('lib')
|
|
8
|
+
.description('使用 esbulid 将 ts lib 打包到 dist 目录,格式为 esm/cjs')
|
|
9
|
+
.option('-w --watch', '监视模式')
|
|
10
|
+
.action(async (option: { watch?: boolean }) => {
|
|
11
|
+
const buildProgram = new ESBuildProgram({
|
|
12
|
+
base: path.resolve(),
|
|
13
|
+
isWatch: !!option.watch,
|
|
14
|
+
})
|
|
15
|
+
await buildProgram.buildLib()
|
|
16
|
+
})
|
|
17
|
+
.alias('pkg'),
|
|
18
|
+
)
|
|
19
|
+
.addCommand(
|
|
20
|
+
new Command('cli')
|
|
21
|
+
.description(
|
|
22
|
+
'使用 esbulid 将 ts cli 打包到 dist 目录,格式为 cjs,并且捆绑依赖',
|
|
23
|
+
)
|
|
24
|
+
.option('-w, --watch', '监视模式')
|
|
25
|
+
.action(async (option: { watch?: boolean }) => {
|
|
26
|
+
const buildProgram = new ESBuildProgram({
|
|
27
|
+
base: path.resolve(),
|
|
28
|
+
isWatch: !!option.watch,
|
|
29
|
+
})
|
|
30
|
+
await buildProgram.buildCli()
|
|
31
|
+
}),
|
|
32
|
+
)
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 函数去抖
|
|
3
|
+
* 去抖 (debounce) 去抖就是对于一定时间段的连续的函数调用,只让其执行一次
|
|
4
|
+
* 注: 包装后的函数如果两次操作间隔小于 delay 则不会被执行, 如果一直在操作就会一直不执行, 直到操作停止的时间大于 delay 最小间隔时间才会执行一次, 不管任何时间调用都需要停止操作等待最小延迟时间
|
|
5
|
+
* 应用场景主要在那些连续的操作, 例如页面滚动监听, 包装后的函数只会执行最后一次
|
|
6
|
+
* 注: 该函数第一次调用一定不会执行,第一次一定拿不到缓存值,后面的连续调用都会拿到上一次的缓存值。如果需要在第一次调用获取到的缓存值,则需要传入第三个参数 {@param init},默认为 {@code undefined} 的可选参数
|
|
7
|
+
* 注: 返回函数结果的高阶函数需要使用 {@see Proxy} 实现,以避免原函数原型链上的信息丢失
|
|
8
|
+
*
|
|
9
|
+
* @param fn 真正需要执行的操作
|
|
10
|
+
* @param delay 最小延迟时间,单位为 ms
|
|
11
|
+
* @param init 初始的缓存值,不填默认为 {@see undefined}
|
|
12
|
+
* @return 包装后有去抖功能的函数。该函数是异步的,与需要包装的函数 {@param fn} 是否异步没有太大关联
|
|
13
|
+
*/
|
|
14
|
+
export function debounce<
|
|
15
|
+
T extends (...args: any[]) => any,
|
|
16
|
+
R extends (...args: Parameters<T>) => Promise<ReturnType<T>>,
|
|
17
|
+
>(fn: T, delay: number, init: any = null): R {
|
|
18
|
+
let flag: number
|
|
19
|
+
let result = init
|
|
20
|
+
return async function (...args) {
|
|
21
|
+
return new Promise((resolve) => {
|
|
22
|
+
if (flag) {
|
|
23
|
+
clearTimeout(flag as any)
|
|
24
|
+
}
|
|
25
|
+
flag = setTimeout(() => resolve((result = fn(...args))), delay) as any
|
|
26
|
+
setTimeout(() => resolve(result), delay)
|
|
27
|
+
})
|
|
28
|
+
} as R
|
|
29
|
+
}
|