jiek 2.2.1 → 2.2.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/dist/cli-only-build.cjs +239 -127
- package/dist/cli-only-build.js +249 -137
- package/dist/rollup/index.cjs +19 -3
- package/dist/rollup/index.js +19 -3
- package/package.json +9 -5
- package/src/commands/build/analyzer.ts +122 -0
- package/src/commands/build/client/analyzer.tsx +121 -0
- package/src/commands/build/client/index.ts +28 -0
- package/src/commands/build.ts +25 -153
- package/src/commands/utils/optionParser.ts +4 -0
- package/src/rollup/index.ts +18 -2
- package/src/server.ts +9 -1
- package/src/utils/checkDependency.ts +22 -0
- package/src/utils/ts.ts +3 -3
@@ -0,0 +1,122 @@
|
|
1
|
+
import type { Command } from 'commander'
|
2
|
+
|
3
|
+
import { CLIENT_CUSTOM_RENDER_SCRIPT } from '#~/commands/build/client/index.ts'
|
4
|
+
import { parseBoolean } from '#~/commands/utils/optionParser.ts'
|
5
|
+
import type { Module } from '#~/rollup/bundle-analyzer.ts'
|
6
|
+
import type { createServer } from '#~/server.ts'
|
7
|
+
import { checkDependency } from '#~/utils/checkDependency.ts'
|
8
|
+
import { existsSync, mkdirSync, statSync, writeFileSync } from 'node:fs'
|
9
|
+
import path from 'node:path'
|
10
|
+
|
11
|
+
export interface AnalyzerBuildOptions {
|
12
|
+
ana?: boolean
|
13
|
+
/**
|
14
|
+
* @default '.jk-analyses'
|
15
|
+
*/
|
16
|
+
'ana.dir': string
|
17
|
+
/**
|
18
|
+
* @default 'server'
|
19
|
+
*/
|
20
|
+
'ana.mode': string
|
21
|
+
'ana.open'?: boolean
|
22
|
+
/**
|
23
|
+
* @default 'parsed'
|
24
|
+
*/
|
25
|
+
'ana.size': string
|
26
|
+
}
|
27
|
+
|
28
|
+
export const registerAnalyzerCommandOptions = (command: Command) =>
|
29
|
+
command
|
30
|
+
.option('--ana', 'Enable the bundle analyzer.', parseBoolean)
|
31
|
+
.option('--ana.dir <DIR>', 'The directory of the bundle analyzer.', '.jk-analyses')
|
32
|
+
.option(
|
33
|
+
'--ana.mode <MODE>',
|
34
|
+
'The mode of the bundle analyzer, support "static", "json" and "server".',
|
35
|
+
'server'
|
36
|
+
)
|
37
|
+
.option('--ana.open', 'Open the bundle analyzer in the browser.', parseBoolean)
|
38
|
+
.option(
|
39
|
+
'--ana.size <SIZE>',
|
40
|
+
'The default size of the bundle analyzer, support "stat", "parsed" and "gzip".',
|
41
|
+
'parsed'
|
42
|
+
)
|
43
|
+
|
44
|
+
export const useAnalyzer = async (options: AnalyzerBuildOptions, server?: ReturnType<typeof createServer>) => {
|
45
|
+
const modules: Module[] = []
|
46
|
+
let bundleAnalyzerModule: typeof import('vite-bundle-analyzer') | undefined
|
47
|
+
const analyzer = options.ana
|
48
|
+
? {
|
49
|
+
dir: options['ana.dir'],
|
50
|
+
mode: options['ana.mode'],
|
51
|
+
open: options['ana.open'],
|
52
|
+
size: options['ana.size']
|
53
|
+
}
|
54
|
+
: undefined
|
55
|
+
if (
|
56
|
+
options.ana
|
57
|
+
&& ![
|
58
|
+
'stat',
|
59
|
+
'parsed',
|
60
|
+
'gzip'
|
61
|
+
].includes(analyzer?.size ?? '')
|
62
|
+
) {
|
63
|
+
throw new Error('The value of `ana.size` must be "stat", "parsed" or "gzip"')
|
64
|
+
}
|
65
|
+
|
66
|
+
if (analyzer) {
|
67
|
+
await checkDependency('vite-bundle-analyzer')
|
68
|
+
bundleAnalyzerModule = await import('vite-bundle-analyzer')
|
69
|
+
}
|
70
|
+
|
71
|
+
const refreshAnalyzer = async (cwd: string, applyModules: typeof modules) => {
|
72
|
+
if (!(analyzer && server && bundleAnalyzerModule)) return
|
73
|
+
|
74
|
+
if (analyzer.mode === 'json') {
|
75
|
+
const anaDir = path.resolve(cwd, analyzer.dir)
|
76
|
+
if (!existsSync(anaDir)) {
|
77
|
+
mkdirSync(anaDir, { recursive: true })
|
78
|
+
}
|
79
|
+
const gitIgnorePath = path.resolve(anaDir, '.gitignore')
|
80
|
+
if (!existsSync(gitIgnorePath)) {
|
81
|
+
writeFileSync(gitIgnorePath, '*\n!.gitignore\n')
|
82
|
+
}
|
83
|
+
const npmIgnorePath = path.resolve(anaDir, '.npmignore')
|
84
|
+
if (!existsSync(npmIgnorePath)) {
|
85
|
+
writeFileSync(npmIgnorePath, '*\n')
|
86
|
+
}
|
87
|
+
if (!statSync(anaDir).isDirectory()) {
|
88
|
+
throw new Error(`The directory '${anaDir}' is not a directory.`)
|
89
|
+
}
|
90
|
+
}
|
91
|
+
|
92
|
+
const { renderView, injectHTMLTag } = bundleAnalyzerModule
|
93
|
+
applyModules.forEach(m => {
|
94
|
+
const index = modules.findIndex(({ filename }) => filename === m.filename)
|
95
|
+
if (index === -1) {
|
96
|
+
modules.push(m)
|
97
|
+
} else {
|
98
|
+
modules[index] = m
|
99
|
+
}
|
100
|
+
})
|
101
|
+
let html = await renderView(modules, {
|
102
|
+
title: `Jiek Analyzer`,
|
103
|
+
mode: analyzer.size as 'stat' | 'parsed' | 'gzip'
|
104
|
+
})
|
105
|
+
html = injectHTMLTag({
|
106
|
+
html,
|
107
|
+
injectTo: 'body',
|
108
|
+
descriptors: [
|
109
|
+
{ kind: 'script', text: CLIENT_CUSTOM_RENDER_SCRIPT }
|
110
|
+
]
|
111
|
+
})
|
112
|
+
void server.renderTo('/ana', html)
|
113
|
+
}
|
114
|
+
|
115
|
+
return {
|
116
|
+
modules,
|
117
|
+
refreshAnalyzer,
|
118
|
+
ANALYZER_ENV: {
|
119
|
+
JIEK_ANALYZER: analyzer ? JSON.stringify(analyzer) : undefined
|
120
|
+
}
|
121
|
+
}
|
122
|
+
}
|
@@ -0,0 +1,121 @@
|
|
1
|
+
import type { Module } from '#~/rollup/bundle-analyzer.ts'
|
2
|
+
|
3
|
+
interface Node {
|
4
|
+
id: string
|
5
|
+
filename: string
|
6
|
+
parent?: Node
|
7
|
+
}
|
8
|
+
|
9
|
+
declare global {
|
10
|
+
// @ts-ignore
|
11
|
+
// eslint-disable-next-line no-var,vars-on-top
|
12
|
+
var React: typeof import('react')
|
13
|
+
// eslint-disable-next-line no-var,vars-on-top
|
14
|
+
var analyzeModule: Module[]
|
15
|
+
interface WindowEventMap {
|
16
|
+
'graph:click': CustomEvent<
|
17
|
+
| undefined
|
18
|
+
| { node: Node }
|
19
|
+
>
|
20
|
+
'send:filter': CustomEvent<{
|
21
|
+
analyzeModule: Module[]
|
22
|
+
}>
|
23
|
+
}
|
24
|
+
}
|
25
|
+
|
26
|
+
export function Main() {
|
27
|
+
const { useState, useMemo, useEffect, useCallback } = React
|
28
|
+
const [path, setPath] = useState(() => location.pathname.replace(/^\/ana\/?/, ''))
|
29
|
+
const [pkgName, entry] = useMemo(() => {
|
30
|
+
const pkgName = /^(@[^/]+\/[^/]+|[^/]+)\/?/.exec(path)?.[1]
|
31
|
+
return [
|
32
|
+
pkgName,
|
33
|
+
(pkgName != null) ? path.replace(`${pkgName}/`, '') : undefined
|
34
|
+
]
|
35
|
+
}, [path])
|
36
|
+
const push = useCallback((newPath: string) => {
|
37
|
+
setPath(newPath)
|
38
|
+
document.title = `${document.title.replace(/ - \/.*/, '')} - \/${newPath}`
|
39
|
+
history.pushState(null, '', `/ana/${newPath}`)
|
40
|
+
}, [])
|
41
|
+
const filterModules = useCallback((startWith: string) => {
|
42
|
+
const modules = analyzeModule.filter(m => m.filename.startsWith(startWith))
|
43
|
+
dispatchEvent(new CustomEvent('send:filter', { detail: { analyzeModule: modules } }))
|
44
|
+
}, [])
|
45
|
+
useEffect(() => {
|
46
|
+
if (path !== '') {
|
47
|
+
document.title = `${document.title.replace(/ - \/.*/, '')} - \/${path}`
|
48
|
+
} else {
|
49
|
+
document.title = document.title.replace(/ - \/.*/, '')
|
50
|
+
}
|
51
|
+
filterModules(path)
|
52
|
+
}, [path, filterModules])
|
53
|
+
useEffect(() => {
|
54
|
+
const offGraphClick = listen('graph:click', ({ detail }) => {
|
55
|
+
if (!detail) return
|
56
|
+
|
57
|
+
let root = detail.node
|
58
|
+
while (root.parent) {
|
59
|
+
root = root.parent
|
60
|
+
}
|
61
|
+
if (root.filename === path) return
|
62
|
+
push(root.filename)
|
63
|
+
})
|
64
|
+
return () => {
|
65
|
+
offGraphClick()
|
66
|
+
}
|
67
|
+
}, [push])
|
68
|
+
function listen<T extends keyof WindowEventMap>(type: T, listener: (this: Window, ev: WindowEventMap[T]) => any) {
|
69
|
+
window.addEventListener(type, listener)
|
70
|
+
return () => {
|
71
|
+
window.removeEventListener(type, listener)
|
72
|
+
}
|
73
|
+
}
|
74
|
+
return (
|
75
|
+
<div
|
76
|
+
style={{
|
77
|
+
padding: '12px 55px'
|
78
|
+
}}
|
79
|
+
>
|
80
|
+
/
|
81
|
+
<select
|
82
|
+
style={{
|
83
|
+
appearance: 'none',
|
84
|
+
border: 'none',
|
85
|
+
background: 'none'
|
86
|
+
}}
|
87
|
+
value={pkgName}
|
88
|
+
onChange={e => push(e.target.value)}
|
89
|
+
>
|
90
|
+
<option value=''>All</option>
|
91
|
+
{analyzeModule
|
92
|
+
.map(m => /^(@[^/]+\/[^/]+|[^/]+)\/?/.exec(m.filename)?.[1])
|
93
|
+
.filter((v, i, a) => a.indexOf(v) === i)
|
94
|
+
.map(v => (
|
95
|
+
<option key={v} value={v}>{v}</option>
|
96
|
+
))}
|
97
|
+
</select>
|
98
|
+
{pkgName != null && <>
|
99
|
+
/
|
100
|
+
<select
|
101
|
+
style={{
|
102
|
+
appearance: 'none',
|
103
|
+
border: 'none',
|
104
|
+
background: 'none'
|
105
|
+
}}
|
106
|
+
value={entry}
|
107
|
+
onChange={e => push(`${pkgName}/${e.target.value}`)}
|
108
|
+
>
|
109
|
+
<option value=''>All</option>
|
110
|
+
{analyzeModule
|
111
|
+
.filter(m => m.filename.startsWith(`${pkgName}/`))
|
112
|
+
.map(m => m.filename.replace(`${pkgName}/`, ''))
|
113
|
+
.filter((v, i, a) => a.indexOf(v) === i)
|
114
|
+
.map(v => (
|
115
|
+
<option key={v} value={v}>{v}</option>
|
116
|
+
))}
|
117
|
+
</select>
|
118
|
+
</>}
|
119
|
+
</div>
|
120
|
+
)
|
121
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
import { Main } from './analyzer'
|
2
|
+
|
3
|
+
declare global {
|
4
|
+
// eslint-disable-next-line no-var,vars-on-top
|
5
|
+
var CUSTOM_SIDE_BAR: boolean
|
6
|
+
// eslint-disable-next-line no-var,vars-on-top
|
7
|
+
var __REPLACE_INJECT__: string
|
8
|
+
}
|
9
|
+
|
10
|
+
function render() {
|
11
|
+
CUSTOM_SIDE_BAR = true
|
12
|
+
window.addEventListener('client:ready', () =>
|
13
|
+
setTimeout(() => {
|
14
|
+
window.dispatchEvent(
|
15
|
+
new CustomEvent('send:ui', {
|
16
|
+
detail: { type: 'Main', Component: __REPLACE_INJECT__ }
|
17
|
+
})
|
18
|
+
)
|
19
|
+
}, 0))
|
20
|
+
}
|
21
|
+
|
22
|
+
export const CLIENT_CUSTOM_RENDER_SCRIPT = [
|
23
|
+
Main.toString(),
|
24
|
+
render
|
25
|
+
.toString()
|
26
|
+
.replace('__REPLACE_INJECT__', Main.name),
|
27
|
+
`(${render.name})()`
|
28
|
+
].join('\n')
|
package/src/commands/build.ts
CHANGED
@@ -1,24 +1,24 @@
|
|
1
|
-
import { existsSync, mkdirSync,
|
1
|
+
import { existsSync, mkdirSync, writeFileSync } from 'node:fs'
|
2
2
|
import { createRequire } from 'node:module'
|
3
3
|
import path from 'node:path'
|
4
4
|
import process from 'node:process'
|
5
5
|
|
6
|
-
import { confirm } from '@inquirer/prompts'
|
7
6
|
import { MultiBar, Presets } from 'cli-progress'
|
8
7
|
import { program } from 'commander'
|
9
8
|
import { execaCommand } from 'execa'
|
10
|
-
import type { renderView } from 'vite-bundle-analyzer'
|
11
9
|
|
12
10
|
import type { RollupBuildEvent } from '#~/bridge.ts'
|
11
|
+
import type { AnalyzerBuildOptions } from '#~/commands/build/analyzer.ts'
|
12
|
+
import { registerAnalyzerCommandOptions, useAnalyzer } from '#~/commands/build/analyzer.ts'
|
13
13
|
import { entriesDescription, filterDescription, outdirDescription } from '#~/commands/descriptions.ts'
|
14
14
|
import { IS_WORKSPACE } from '#~/commands/meta.ts'
|
15
|
+
import { parseBoolean } from '#~/commands/utils/optionParser.ts'
|
15
16
|
import type { TemplateOptions } from '#~/rollup/base.ts'
|
16
17
|
import { BUILDER_TYPES, BUILDER_TYPE_PACKAGE_NAME_MAP } from '#~/rollup/base.ts'
|
17
|
-
import type { Module } from '#~/rollup/bundle-analyzer.ts'
|
18
18
|
import { createServer } from '#~/server.ts'
|
19
|
+
import { checkDependency } from '#~/utils/checkDependency.ts'
|
19
20
|
import type { ProjectsGraph } from '#~/utils/filterSupport.ts'
|
20
21
|
import { filterPackagesGraph, getSelectedProjectsGraph } from '#~/utils/filterSupport.ts'
|
21
|
-
import { getWD } from '#~/utils/getWD.ts'
|
22
22
|
import { loadConfig } from '#~/utils/loadConfig.ts'
|
23
23
|
import { tsRegisterName } from '#~/utils/tsRegister.ts'
|
24
24
|
|
@@ -49,21 +49,7 @@ If you want to through the options to the \`rollup\` command, you can pass the o
|
|
49
49
|
${isDefault ? 'This command is the default command.' : ''}
|
50
50
|
`.trim()
|
51
51
|
|
52
|
-
interface BuildOptions {
|
53
|
-
ana?: boolean
|
54
|
-
/**
|
55
|
-
* @default '.jk-analyses'
|
56
|
-
*/
|
57
|
-
'ana.dir': string
|
58
|
-
/**
|
59
|
-
* @default 'server'
|
60
|
-
*/
|
61
|
-
'ana.mode': string
|
62
|
-
'ana.open'?: boolean
|
63
|
-
/**
|
64
|
-
* @default 'parsed'
|
65
|
-
*/
|
66
|
-
'ana.size': string
|
52
|
+
interface BuildOptions extends AnalyzerBuildOptions {
|
67
53
|
/**
|
68
54
|
* Auto-detect the builder from the installed dependencies.
|
69
55
|
* If the builder is not installed, it will prompt the user to install it.
|
@@ -120,22 +106,6 @@ interface BuildOptions {
|
|
120
106
|
dtsconfig?: string
|
121
107
|
}
|
122
108
|
|
123
|
-
async function checkDependency(dependency: string) {
|
124
|
-
try {
|
125
|
-
require.resolve(dependency)
|
126
|
-
} catch {
|
127
|
-
console.error(`The package '${dependency}' is not installed, please install it first.`)
|
128
|
-
const { notWorkspace } = getWD()
|
129
|
-
const command = `pnpm install -${notWorkspace ? '' : 'w'}D ${dependency}`
|
130
|
-
if (await confirm({ message: 'Do you want to install it now?' })) {
|
131
|
-
await execaCommand(command)
|
132
|
-
} else {
|
133
|
-
console.warn(`You can run the command '${command}' to install it manually.`)
|
134
|
-
process.exit(1)
|
135
|
-
}
|
136
|
-
}
|
137
|
-
}
|
138
|
-
|
139
109
|
let DEFAULT_BUILDER_TYPE: typeof BUILDER_TYPES[number]
|
140
110
|
Object.entries(BUILDER_TYPE_PACKAGE_NAME_MAP).forEach(([type, packageName]) => {
|
141
111
|
try {
|
@@ -147,11 +117,6 @@ if (!DEFAULT_BUILDER_TYPE!) {
|
|
147
117
|
DEFAULT_BUILDER_TYPE = 'esbuild'
|
148
118
|
}
|
149
119
|
|
150
|
-
function parseBoolean(v?: unknown) {
|
151
|
-
if (v === undefined) return true
|
152
|
-
return Boolean(v)
|
153
|
-
}
|
154
|
-
|
155
120
|
const buildFilterDescription = `
|
156
121
|
${filterDescription}
|
157
122
|
If you pass the --filter option, it will merge into the filters of the command.
|
@@ -217,16 +182,7 @@ command = command
|
|
217
182
|
.option('-w, --watch', 'Watch the file changes.', parseBoolean)
|
218
183
|
.option('-p, --port <PORT>', 'The port of the server.', Number.parseInt, 8888)
|
219
184
|
|
220
|
-
command = command
|
221
|
-
.option('--ana', 'Enable the bundle analyzer.', parseBoolean)
|
222
|
-
.option('--ana.dir <DIR>', 'The directory of the bundle analyzer.', '.jk-analyses')
|
223
|
-
.option('--ana.mode <MODE>', 'The mode of the bundle analyzer, support "static", "json" and "server".', 'server')
|
224
|
-
.option('--ana.open', 'Open the bundle analyzer in the browser.', parseBoolean)
|
225
|
-
.option(
|
226
|
-
'--ana.size <SIZE>',
|
227
|
-
'The default size of the bundle analyzer, support "stat", "parsed" and "gzip".',
|
228
|
-
'parsed'
|
229
|
-
)
|
185
|
+
command = registerAnalyzerCommandOptions(command)
|
230
186
|
|
231
187
|
command = command
|
232
188
|
.option('-s, --silent', "Don't display logs.", parseBoolean)
|
@@ -282,48 +238,17 @@ command
|
|
282
238
|
[] as string[]
|
283
239
|
)
|
284
240
|
|
285
|
-
const
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
? {
|
291
|
-
dir: options['ana.dir'],
|
292
|
-
mode: options['ana.mode'],
|
293
|
-
open: options['ana.open'],
|
294
|
-
size: options['ana.size']
|
295
|
-
}
|
241
|
+
const shouldCreateServer = [
|
242
|
+
options.ana === true && options['ana.mode'] === 'server'
|
243
|
+
].some(Boolean)
|
244
|
+
const server = shouldCreateServer
|
245
|
+
? createServer(options.port, 'localhost')
|
296
246
|
: undefined
|
297
|
-
if (
|
298
|
-
options.ana
|
299
|
-
&& ![
|
300
|
-
'stat',
|
301
|
-
'parsed',
|
302
|
-
'gzip'
|
303
|
-
].includes(analyzer?.size ?? '')
|
304
|
-
) {
|
305
|
-
throw new Error('The value of `ana.size` must be "stat", "parsed" or "gzip"')
|
306
|
-
}
|
307
|
-
const server = analyzer && createServer(options.port, 'localhost')
|
308
247
|
|
309
|
-
|
310
|
-
|
311
|
-
|
312
|
-
|
313
|
-
}
|
314
|
-
const anaPaths = new Set<string>()
|
315
|
-
const refreshAnalyzer = async (subPath = '', renderModules = modules) => {
|
316
|
-
if (!(analyzer && server && render)) return
|
317
|
-
const p = `/ana${subPath}`
|
318
|
-
anaPaths.add(p)
|
319
|
-
void server.renderTo(
|
320
|
-
p,
|
321
|
-
await render(renderModules, {
|
322
|
-
title: `Jiek Analyzer - ${subPath}`,
|
323
|
-
mode: analyzer.size as 'stat' | 'parsed' | 'gzip'
|
324
|
-
})
|
325
|
-
)
|
326
|
-
}
|
248
|
+
const {
|
249
|
+
ANALYZER_ENV,
|
250
|
+
refreshAnalyzer
|
251
|
+
} = await useAnalyzer(options, server)
|
327
252
|
|
328
253
|
const { build } = loadConfig()
|
329
254
|
silent = silent ?? build?.silent ?? false
|
@@ -343,7 +268,7 @@ command
|
|
343
268
|
entries = undefined
|
344
269
|
}
|
345
270
|
const env = {
|
346
|
-
|
271
|
+
...ANALYZER_ENV,
|
347
272
|
JIEK_BUILDER: type,
|
348
273
|
JIEK_OUT_DIR: outdir,
|
349
274
|
JIEK_CLEAN: String(!noClean),
|
@@ -388,27 +313,10 @@ command
|
|
388
313
|
.replace(/dist\/rollup.js$/, 'dist/bin/rollup')
|
389
314
|
let i = 0
|
390
315
|
await Promise.all(
|
391
|
-
Object.entries(value).map(async ([
|
316
|
+
Object.entries(value).map(async ([pkgCWD, manifest]) => {
|
392
317
|
if (manifest.name == null) {
|
393
318
|
throw new Error('package.json must have a name field')
|
394
319
|
}
|
395
|
-
if (analyzer) {
|
396
|
-
const anaDir = path.resolve(dir, analyzer.dir)
|
397
|
-
if (!existsSync(anaDir)) {
|
398
|
-
mkdirSync(anaDir, { recursive: true })
|
399
|
-
}
|
400
|
-
const gitIgnorePath = path.resolve(anaDir, '.gitignore')
|
401
|
-
if (!existsSync(gitIgnorePath)) {
|
402
|
-
writeFileSync(gitIgnorePath, '*\n!.gitignore\n')
|
403
|
-
}
|
404
|
-
const npmIgnorePath = path.resolve(anaDir, '.npmignore')
|
405
|
-
if (!existsSync(npmIgnorePath)) {
|
406
|
-
writeFileSync(npmIgnorePath, '*\n')
|
407
|
-
}
|
408
|
-
if (!statSync(anaDir).isDirectory()) {
|
409
|
-
throw new Error(`The directory '${anaDir}' is not a directory.`)
|
410
|
-
}
|
411
|
-
}
|
412
320
|
|
413
321
|
// TODO support auto build child packages in workspaces
|
414
322
|
const escapeManifestName = manifest.name.replace(/^@/g, '').replace(/\//g, '+')
|
@@ -426,7 +334,7 @@ command
|
|
426
334
|
command.push(...passThroughOptions)
|
427
335
|
const child = execaCommand(command.join(' '), {
|
428
336
|
ipc: true,
|
429
|
-
cwd:
|
337
|
+
cwd: pkgCWD,
|
430
338
|
env: {
|
431
339
|
...env,
|
432
340
|
JIEK_NAME: manifest.name,
|
@@ -540,41 +448,18 @@ command
|
|
540
448
|
const {
|
541
449
|
data: {
|
542
450
|
type,
|
543
|
-
path,
|
544
451
|
modules: pkgModules
|
545
452
|
}
|
546
453
|
} = e
|
547
|
-
|
548
|
-
|
454
|
+
void refreshAnalyzer(
|
455
|
+
pkgCWD,
|
456
|
+
pkgModules.map(m => ({
|
549
457
|
...m,
|
458
|
+
type,
|
550
459
|
filename: `${manifest.name}/${m.filename}`,
|
551
460
|
label: `${manifest.name}/${m.label}`
|
552
|
-
}
|
553
|
-
const pushOrReplace = (arr: Module[]) => {
|
554
|
-
const index = arr.findIndex(({ filename }) => filename === newM.filename)
|
555
|
-
if (index === -1) {
|
556
|
-
arr.push(newM)
|
557
|
-
} else {
|
558
|
-
arr[index] = newM
|
559
|
-
}
|
560
|
-
}
|
561
|
-
pushOrReplace(modules)
|
562
|
-
if (type === 'esm') {
|
563
|
-
pushOrReplace(esmModules)
|
564
|
-
}
|
565
|
-
if (type === 'cjs') {
|
566
|
-
pushOrReplace(cjsModules)
|
567
|
-
}
|
568
|
-
})
|
569
|
-
void refreshAnalyzer()
|
570
|
-
void refreshAnalyzer(
|
571
|
-
`/${type}`,
|
572
|
-
{
|
573
|
-
cjs: cjsModules,
|
574
|
-
esm: esmModules
|
575
|
-
}[type]
|
461
|
+
}))
|
576
462
|
)
|
577
|
-
void refreshAnalyzer(`/${type}/${manifest.name}/${path.slice(2)}`, pkgModules)
|
578
463
|
break
|
579
464
|
}
|
580
465
|
case 'debug': {
|
@@ -624,20 +509,7 @@ command
|
|
624
509
|
}
|
625
510
|
} finally {
|
626
511
|
multiBars.stop()
|
627
|
-
let message = 'The build is complete'
|
628
|
-
if (analyzer) {
|
629
|
-
message += ` and the analyzer is running at http://localhost:${options.port}/ana in ${analyzer.mode} mode.\n`
|
630
|
-
message += analyzer.open ? ' The browser will open automatically.\n' : ''
|
631
|
-
if (anaPaths.size > 0) {
|
632
|
-
message += `The analyzer has ${anaPaths.size} pages:\n${
|
633
|
-
Array
|
634
|
-
.from(anaPaths)
|
635
|
-
.map(p => `http://localhost:${options.port}${p}`)
|
636
|
-
.join('\n')
|
637
|
-
}`
|
638
|
-
}
|
639
|
-
}
|
640
512
|
// eslint-disable-next-line no-console
|
641
|
-
!silent && console.log(
|
513
|
+
!silent && console.log('Build complete')
|
642
514
|
}
|
643
515
|
})
|
package/src/rollup/index.ts
CHANGED
@@ -219,7 +219,7 @@ const withMinify = (
|
|
219
219
|
return minify === 'only-minify'
|
220
220
|
? [{
|
221
221
|
...output,
|
222
|
-
// TODO replace suffix when
|
222
|
+
// TODO replace suffix when publish to npm and the `build.output.minify` is 'only-minify'
|
223
223
|
// TODO resolve dts output file name
|
224
224
|
entryFileNames: chunkInfo =>
|
225
225
|
typeof output.entryFileNames === 'function'
|
@@ -359,7 +359,23 @@ const generateConfigs = (context: ConfigGenerateContext, options: TemplateOption
|
|
359
359
|
const rollupOptions: RollupOptions[] = []
|
360
360
|
|
361
361
|
const commonPlugins: Plugin[] = [
|
362
|
-
nodeResolve({
|
362
|
+
nodeResolve({
|
363
|
+
exportConditions,
|
364
|
+
extensions: [
|
365
|
+
'.js',
|
366
|
+
'.cjs',
|
367
|
+
'.mjs',
|
368
|
+
'.jsx',
|
369
|
+
'.cjsx',
|
370
|
+
'.mjsx',
|
371
|
+
'.ts',
|
372
|
+
'.cts',
|
373
|
+
'.mts',
|
374
|
+
'.tsx',
|
375
|
+
'.ctsx',
|
376
|
+
'.mtsx'
|
377
|
+
]
|
378
|
+
})
|
363
379
|
]
|
364
380
|
if (jsOutput && !WITHOUT_JS) {
|
365
381
|
const sourcemap = typeof options?.output?.sourcemap === 'object'
|
package/src/server.ts
CHANGED
@@ -5,7 +5,15 @@ export const createServer = (port: number, host: string) => {
|
|
5
5
|
app.listen(port, host)
|
6
6
|
const streams = new Map<string, string>()
|
7
7
|
app.use(async (ctx) => {
|
8
|
-
|
8
|
+
let stream = streams.get(ctx.path)
|
9
|
+
if (stream == null) {
|
10
|
+
const maybeKey = streams
|
11
|
+
.keys()
|
12
|
+
.find(p => ctx.path.startsWith(p))
|
13
|
+
stream = maybeKey != null
|
14
|
+
? streams.get(maybeKey)
|
15
|
+
: undefined
|
16
|
+
}
|
9
17
|
if (stream != null) {
|
10
18
|
ctx.body = stream
|
11
19
|
}
|
@@ -0,0 +1,22 @@
|
|
1
|
+
import process from 'node:process'
|
2
|
+
|
3
|
+
import { confirm } from '@inquirer/prompts'
|
4
|
+
import { execaCommand } from 'execa'
|
5
|
+
|
6
|
+
import { getWD } from '#~/utils/getWD.ts'
|
7
|
+
|
8
|
+
export async function checkDependency(dependency: string) {
|
9
|
+
try {
|
10
|
+
require.resolve(dependency)
|
11
|
+
} catch {
|
12
|
+
console.error(`The package '${dependency}' is not installed, please install it first.`)
|
13
|
+
const { notWorkspace } = getWD()
|
14
|
+
const command = `pnpm install -${notWorkspace ? '' : 'w'}D ${dependency}`
|
15
|
+
if (await confirm({ message: 'Do you want to install it now?' })) {
|
16
|
+
await execaCommand(command)
|
17
|
+
} else {
|
18
|
+
console.warn(`You can run the command '${command}' to install it manually.`)
|
19
|
+
process.exit(1)
|
20
|
+
}
|
21
|
+
}
|
22
|
+
}
|
package/src/utils/ts.ts
CHANGED
@@ -4,7 +4,7 @@ import { dirname, resolve } from 'node:path'
|
|
4
4
|
import { parse } from 'jsonc-parser'
|
5
5
|
import { isMatch } from 'micromatch'
|
6
6
|
|
7
|
-
|
7
|
+
interface TSConfig {
|
8
8
|
extends?: string | string[]
|
9
9
|
compilerOptions?: Record<string, unknown>
|
10
10
|
references?: { path: string }[]
|
@@ -16,7 +16,7 @@ type TSConfig = {
|
|
16
16
|
const getTSConfig = (p: string): TSConfig =>
|
17
17
|
!fs.existsSync(p) || !fs.statSync(p).isFile()
|
18
18
|
? {}
|
19
|
-
: parse(fs.readFileSync(p, 'utf-8'), [], { allowTrailingComma: true, allowEmptyContent: true })
|
19
|
+
: parse(fs.readFileSync(p, 'utf-8'), [], { allowTrailingComma: true, allowEmptyContent: true }) as TSConfig
|
20
20
|
|
21
21
|
const getExtendTSConfig = (tsconfigPath: string): TSConfig => {
|
22
22
|
tsconfigPath = resolve(tsconfigPath)
|
@@ -25,7 +25,7 @@ const getExtendTSConfig = (tsconfigPath: string): TSConfig => {
|
|
25
25
|
const resolvePaths = (paths: string[] | undefined) => paths?.map(p => resolve(tsconfigPathDirname, p)) ?? []
|
26
26
|
|
27
27
|
const extendsPaths = resolvePaths(
|
28
|
-
exts ? Array.isArray(exts) ? exts : [exts] : []
|
28
|
+
exts !== undefined ? Array.isArray(exts) ? exts : [exts] : []
|
29
29
|
)
|
30
30
|
if (extendsPaths.length === 0) return tsconfig
|
31
31
|
return extendsPaths
|