From d30f813ee752979f6f9f6aa7698766ba146c3e48 Mon Sep 17 00:00:00 2001 From: null51_ Date: Fri, 1 Apr 2022 14:26:26 +0800 Subject: [PATCH] fix: build promise resolves before types are emitted (#597) Co-authored-by: hanyue.ph Co-authored-by: EGOIST <0x142857@gmail.com> --- src/index.ts | 298 ++++++++++++++++++++++++++------------------------ src/rollup.ts | 1 + 2 files changed, 155 insertions(+), 144 deletions(-) diff --git a/src/index.ts b/src/index.ts index 81cd7d05..b9d09e0b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -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((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 = new Set() + const otherTasks = async () => { + if (!options.dts?.only) { + let existingOnSuccess: ChildProcess | undefined + /** Files imported by the entry */ + const buildDependencies: Set = 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 = 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 = 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()]) } ) ) diff --git a/src/rollup.ts b/src/rollup.ts index e07ed961..f7128da0 100644 --- a/src/rollup.ts +++ b/src/rollup.ts @@ -244,6 +244,7 @@ const startRollup = async (options: NormalizedOptions) => { watchRollup(config) } else { await runRollup(config) + parentPort?.postMessage('success') parentPort?.close() } }