Skip to content

Commit

Permalink
fix: build promise resolves before types are emitted (#597)
Browse files Browse the repository at this point in the history
Co-authored-by: hanyue.ph <hanyue.ph@cainiao.com>
Co-authored-by: EGOIST <0x142857@gmail.com>
  • Loading branch information
3 people committed Apr 1, 2022
1 parent 93bf6e8 commit d30f813
Show file tree
Hide file tree
Showing 2 changed files with 155 additions and 144 deletions.
298 changes: 154 additions & 144 deletions src/index.ts
Expand Up @@ -144,165 +144,175 @@ export async function build(_options: Options) {
logger.info('CLI', 'Running in watch mode')
}

if (options.dts) {
const worker = new Worker(path.join(__dirname, './rollup.js'))
worker.postMessage({
configName: item?.name,
options: {
...options, // functions cannot be cloned
banner: undefined,
footer: undefined,
esbuildPlugins: undefined,
esbuildOptions: undefined,
plugins: undefined,
},
})
worker.on('message', (data) => {
if (data === 'error') {
process.exitCode = 1
} else if (data === 'success') {
process.exitCode = 0
}
})
const dtsTask = async () => {
if (options.dts) {
await new Promise<void>((resolve, reject) => {
const worker = new Worker(path.join(__dirname, './rollup.js'))
worker.postMessage({
configName: item?.name,
options: {
...options, // functions cannot be cloned
banner: undefined,
footer: undefined,
esbuildPlugins: undefined,
esbuildOptions: undefined,
plugins: undefined,
},
})
worker.on('message', (data) => {
if (data === 'error') {
process.exitCode = 1
reject()
} else if (data === 'success') {
process.exitCode = 0
resolve()
}
})
})
}
}

if (!options.dts?.only) {
let existingOnSuccess: ChildProcess | undefined
/** Files imported by the entry */
const buildDependencies: Set<string> = new Set()
const otherTasks = async () => {
if (!options.dts?.only) {
let existingOnSuccess: ChildProcess | undefined
/** Files imported by the entry */
const buildDependencies: Set<string> = new Set()

const killPreviousProcess = async () => {
if (existingOnSuccess) {
await killProcess({
pid: existingOnSuccess.pid,
})
existingOnSuccess = undefined
const killPreviousProcess = async () => {
if (existingOnSuccess) {
await killProcess({
pid: existingOnSuccess.pid,
})
existingOnSuccess = undefined
}
}
}

const debouncedBuildAll = debouncePromise(
() => {
return buildAll()
},
100,
handleError
)

const buildAll = async () => {
const killPromise = killPreviousProcess()
// Store previous build dependencies in case the build failed
// So we can restore it
const previousBuildDependencies = new Set(buildDependencies)
buildDependencies.clear()

if (options.clean) {
const extraPatterns = Array.isArray(options.clean)
? options.clean
: []
await removeFiles(
['**/*', '!**/*.d.ts', ...extraPatterns],
options.outDir
)
logger.info('CLI', 'Cleaning output folder')
}
const debouncedBuildAll = debouncePromise(
() => {
return buildAll()
},
100,
handleError
)

const css: Map<string, string> = new Map()
await Promise.all([
...options.format.map(async (format, index) => {
const pluginContainer = new PluginContainer([
shebang(),
...(options.plugins || []),
cjsSplitting(),
es5(),
sizeReporter(),
])
await pluginContainer.buildStarted()
await runEsbuild(options, {
pluginContainer,
format,
css: index === 0 || options.injectStyle ? css : undefined,
logger,
buildDependencies,
}).catch((error) => {
previousBuildDependencies.forEach((v) =>
buildDependencies.add(v)
)
throw error
const buildAll = async () => {
const killPromise = killPreviousProcess()
// Store previous build dependencies in case the build failed
// So we can restore it
const previousBuildDependencies = new Set(buildDependencies)
buildDependencies.clear()

if (options.clean) {
const extraPatterns = Array.isArray(options.clean)
? options.clean
: []
await removeFiles(
['**/*', '!**/*.d.ts', ...extraPatterns],
options.outDir
)
logger.info('CLI', 'Cleaning output folder')
}

const css: Map<string, string> = new Map()
await Promise.all([
...options.format.map(async (format, index) => {
const pluginContainer = new PluginContainer([
shebang(),
...(options.plugins || []),
cjsSplitting(),
es5(),
sizeReporter(),
])
await pluginContainer.buildStarted()
await runEsbuild(options, {
pluginContainer,
format,
css: index === 0 || options.injectStyle ? css : undefined,
logger,
buildDependencies,
}).catch((error) => {
previousBuildDependencies.forEach((v) =>
buildDependencies.add(v)
)
throw error
})
}),
])
await killPromise
if (options.onSuccess) {
const parts = parseArgsStringToArgv(options.onSuccess)
const exec = parts[0]
const args = parts.splice(1)
existingOnSuccess = execa(exec, args, {
stdio: 'inherit',
})
}),
])
await killPromise
if (options.onSuccess) {
const parts = parseArgsStringToArgv(options.onSuccess)
const exec = parts[0]
const args = parts.splice(1)
existingOnSuccess = execa(exec, args, {
stdio: 'inherit',
})
}
}
}

const startWatcher = async () => {
if (!options.watch) return

const { watch } = await import('chokidar')

const customIgnores = options.ignoreWatch
? Array.isArray(options.ignoreWatch)
? options.ignoreWatch
: [options.ignoreWatch]
: []

const ignored = [
'**/{.git,node_modules}/**',
options.outDir,
...customIgnores,
]

const watchPaths =
typeof options.watch === 'boolean'
? '.'
: Array.isArray(options.watch)
? options.watch.filter(
(path): path is string => typeof path === 'string'
)
: options.watch

logger.info(
'CLI',
`Watching for changes in ${
Array.isArray(watchPaths)
? watchPaths.map((v) => '"' + v + '"').join(' | ')
: '"' + watchPaths + '"'
}`
)
logger.info(
'CLI',
`Ignoring changes in ${ignored
.map((v) => '"' + v + '"')
.join(' | ')}`
)
const startWatcher = async () => {
if (!options.watch) return

const watcher = watch(watchPaths, {
ignoreInitial: true,
ignorePermissionErrors: true,
ignored,
})
watcher.on('all', (type, file) => {
file = slash(file)
if (!buildDependencies.has(file)) return
const { watch } = await import('chokidar')

logger.info('CLI', `Change detected: ${type} ${file}`)
debouncedBuildAll()
})
}
const customIgnores = options.ignoreWatch
? Array.isArray(options.ignoreWatch)
? options.ignoreWatch
: [options.ignoreWatch]
: []

logger.info('CLI', `Target: ${options.target}`)
const ignored = [
'**/{.git,node_modules}/**',
options.outDir,
...customIgnores,
]

const watchPaths =
typeof options.watch === 'boolean'
? '.'
: Array.isArray(options.watch)
? options.watch.filter(
(path): path is string => typeof path === 'string'
)
: options.watch

logger.info(
'CLI',
`Watching for changes in ${
Array.isArray(watchPaths)
? watchPaths.map((v) => '"' + v + '"').join(' | ')
: '"' + watchPaths + '"'
}`
)
logger.info(
'CLI',
`Ignoring changes in ${ignored
.map((v) => '"' + v + '"')
.join(' | ')}`
)

await buildAll()
const watcher = watch(watchPaths, {
ignoreInitial: true,
ignorePermissionErrors: true,
ignored,
})
watcher.on('all', (type, file) => {
file = slash(file)
if (!buildDependencies.has(file)) return

startWatcher()
logger.info('CLI', `Change detected: ${type} ${file}`)
debouncedBuildAll()
})
}

logger.info('CLI', `Target: ${options.target}`)

await buildAll()

startWatcher()
}
}

await Promise.all([dtsTask(), otherTasks()])
}
)
)
Expand Down
1 change: 1 addition & 0 deletions src/rollup.ts
Expand Up @@ -244,6 +244,7 @@ const startRollup = async (options: NormalizedOptions) => {
watchRollup(config)
} else {
await runRollup(config)
parentPort?.postMessage('success')
parentPort?.close()
}
}
Expand Down

1 comment on commit d30f813

@vercel
Copy link

@vercel vercel bot commented on d30f813 Apr 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.