UNPKG

@nx/js

Version:

The JS plugin for Nx contains executors and generators that provide the best experience for developing JavaScript and TypeScript projects.

200 lines (199 loc) • 7.88 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.compileSwc = compileSwc; exports.compileSwcWatch = compileSwcWatch; const devkit_1 = require("@nx/devkit"); const node_child_process_1 = require("node:child_process"); const node_fs_1 = require("node:fs"); const node_path_1 = require("node:path"); const async_iterable_1 = require("@nx/devkit/src/utils/async-iterable"); const print_diagnostics_1 = require("../typescript/print-diagnostics"); const run_type_check_1 = require("../typescript/run-type-check"); const path_1 = require("path"); function getSwcCmd({ swcCliOptions: { swcrcPath, destPath, stripLeadingPaths }, root, projectRoot, originalProjectRoot, sourceRoot, inline, }, watch = false) { const swcCLI = require.resolve('@swc/cli/bin/swc.js'); let inputDir; // TODO(v21): remove inline feature if (inline) { inputDir = originalProjectRoot.split('/')[0]; } else { if (sourceRoot) { inputDir = (0, path_1.relative)(projectRoot, sourceRoot); } else { // If sourceRoot is not provided, check if `src` exists and use that instead. // This is important for root projects to avoid compiling too many directories. inputDir = (0, node_fs_1.existsSync)((0, node_path_1.join)(root, projectRoot, 'src')) ? 'src' : '.'; } } let swcCmd = `node ${swcCLI} ${inputDir || '.'} -d ${destPath} --config-file=${swcrcPath} ${stripLeadingPaths ? '--strip-leading-paths' : ''}`; return watch ? swcCmd.concat(' --watch') : swcCmd; } function getTypeCheckOptions(normalizedOptions) { const { sourceRoot, projectRoot, watch, tsConfig, root, outputPath } = normalizedOptions; const inputDir = // If `--strip-leading-paths` SWC option is used, we need to transpile from `src` directory. !normalizedOptions.swcCliOptions.stripLeadingPaths ? projectRoot : sourceRoot ? sourceRoot : (0, node_fs_1.existsSync)((0, node_path_1.join)(root, projectRoot, 'src')) ? (0, node_path_1.join)(projectRoot, 'src') : projectRoot; const typeCheckOptions = { mode: 'emitDeclarationOnly', tsConfigPath: tsConfig, outDir: outputPath, workspaceRoot: root, rootDir: inputDir, }; if (watch) { typeCheckOptions.incremental = true; typeCheckOptions.cacheDir = devkit_1.cacheDir; } if (normalizedOptions.isTsSolutionSetup && normalizedOptions.skipTypeCheck) { typeCheckOptions.ignoreDiagnostics = true; } return typeCheckOptions; } async function compileSwc(context, normalizedOptions, postCompilationCallback) { devkit_1.logger.log(`Compiling with SWC for ${context.projectName}...`); if (normalizedOptions.clean) { (0, node_fs_1.rmSync)(normalizedOptions.outputPath, { recursive: true, force: true }); } try { const swcCmdLog = (0, node_child_process_1.execSync)(getSwcCmd(normalizedOptions), { encoding: 'utf8', cwd: normalizedOptions.swcCliOptions.swcCwd, windowsHide: false, stdio: 'pipe', }); devkit_1.logger.log(swcCmdLog.replace(/\n/, '')); } catch (error) { devkit_1.logger.error('SWC compilation failed'); if (error.stderr) { devkit_1.logger.error(error.stderr.toString()); } return { success: false }; } if (normalizedOptions.skipTypeCheck && !normalizedOptions.isTsSolutionSetup) { await postCompilationCallback(); return { success: true }; } const { errors, warnings } = await (0, run_type_check_1.runTypeCheck)(getTypeCheckOptions(normalizedOptions)); const hasErrors = errors.length > 0; const hasWarnings = warnings.length > 0; if (hasErrors || hasWarnings) { await (0, print_diagnostics_1.printDiagnostics)(errors, warnings); } await postCompilationCallback(); return { success: !hasErrors, outfile: normalizedOptions.mainOutputPath, }; } async function* compileSwcWatch(context, normalizedOptions, postCompilationCallback) { const getResult = (success) => ({ success, outfile: normalizedOptions.mainOutputPath, }); let typeCheckOptions; let initialPostCompile = true; if (normalizedOptions.clean) { (0, node_fs_1.rmSync)(normalizedOptions.outputPath, { recursive: true, force: true }); } return yield* (0, async_iterable_1.createAsyncIterable)(async ({ next, done }) => { let processOnExit; let stdoutOnData; let stderrOnData; let watcherOnExit; const swcWatcher = (0, node_child_process_1.exec)(getSwcCmd(normalizedOptions, true), { cwd: normalizedOptions.swcCliOptions.swcCwd, windowsHide: false, }); processOnExit = () => { swcWatcher.kill(); done(); process.off('SIGINT', processOnExit); process.off('SIGTERM', processOnExit); process.off('exit', processOnExit); }; stdoutOnData = async (data) => { process.stdout.write(data); if (!data.startsWith('Watching')) { const swcStatus = data.includes('Successfully'); if (initialPostCompile) { await postCompilationCallback(); initialPostCompile = false; } if (normalizedOptions.skipTypeCheck || normalizedOptions.isTsSolutionSetup) { next(getResult(swcStatus)); return; } if (!typeCheckOptions) { typeCheckOptions = getTypeCheckOptions(normalizedOptions); } const delayed = delay(5000); next(getResult(await Promise.race([ delayed .start() .then(() => ({ tscStatus: false, type: 'timeout' })), (0, run_type_check_1.runTypeCheck)(typeCheckOptions).then(({ errors, warnings }) => { const hasErrors = errors.length > 0; if (hasErrors) { (0, print_diagnostics_1.printDiagnostics)(errors, warnings); } return { tscStatus: !hasErrors, type: 'tsc', }; }), ]).then(({ type, tscStatus }) => { if (type === 'tsc') { delayed.cancel(); return tscStatus && swcStatus; } return swcStatus; }))); } }; stderrOnData = (err) => { process.stderr.write(err); if (err.includes('Debugger attached.')) { return; } next(getResult(false)); }; watcherOnExit = () => { done(); swcWatcher.off('exit', watcherOnExit); }; swcWatcher.stdout.on('data', stdoutOnData); swcWatcher.stderr.on('data', stderrOnData); process.on('SIGINT', processOnExit); process.on('SIGTERM', processOnExit); process.on('exit', processOnExit); swcWatcher.on('exit', watcherOnExit); }); } function delay(ms) { let timerId = undefined; return { start() { return new Promise((resolve) => { timerId = setTimeout(() => { resolve(); }, ms); }); }, cancel() { if (timerId) { clearTimeout(timerId); timerId = undefined; } }, }; }