diff --git a/lib/__tests__/build-scss.test.js b/lib/__tests__/build-scss.test.js index e178c6843c..150913013d 100644 --- a/lib/__tests__/build-scss.test.js +++ b/lib/__tests__/build-scss.test.js @@ -114,7 +114,7 @@ describe('buildScssCommand', () => { }); }); - it('should compile core and theme stylesheets', () => { + it('should compile core and theme stylesheets', async () => { const args = [ '--corePath=styles/core.scss', '--themesPath=styles/themes', @@ -122,7 +122,7 @@ describe('buildScssCommand', () => { '--defaultThemeVariants=light', ]; - buildScssCommand(args); + await buildScssCommand(args); expect(sass.compile).toHaveBeenCalledWith( expect.stringContaining('core.scss'), @@ -135,8 +135,8 @@ describe('buildScssCommand', () => { ); }); - it('should use default arguments when none provided', () => { - buildScssCommand([]); + it('should use default arguments when none provided', async () => { + await buildScssCommand([]); expect(sass.compile).toHaveBeenCalledWith( expect.stringContaining('core.scss'), @@ -144,8 +144,8 @@ describe('buildScssCommand', () => { ); }); - it('should exclude core properly', () => { - buildScssCommand(['--excludeCore']); + it('should exclude core properly', async () => { + await buildScssCommand(['--excludeCore']); expect(sass.compile).not.toHaveBeenCalledWith( expect.stringContaining('core.scss'), diff --git a/lib/build-scss.js b/lib/build-scss.js index b56c138e13..5a8bb10c8a 100755 --- a/lib/build-scss.js +++ b/lib/build-scss.js @@ -151,7 +151,13 @@ const compileAndWriteStyleSheets = ({ * * @param {Array} commandArgs - Command line arguments for building SCSS stylesheets. */ -function buildScssCommand(commandArgs) { +async function buildScssCommand(commandArgs) { + process.on('SIGINT', () => { + // eslint-disable-next-line no-console + console.log(chalk.yellow('\nBuild interrupted. Partial output may exist in the output directory.')); + process.exit(130); + }); + const defaultArgs = { corePath: path.resolve(process.cwd(), 'styles/scss/core/core.scss'), excludeCore: false, @@ -168,6 +174,9 @@ function buildScssCommand(commandArgs) { defaultThemeVariants, } = minimist(commandArgs, { default: defaultArgs, boolean: ['excludeCore'] }); + // eslint-disable-next-line no-console + console.log(chalk.grey('Press Ctrl+C to interrupt the build (takes effect between compilations).\n')); + // Core CSS if (!excludeCore) { compileAndWriteStyleSheets({ @@ -175,20 +184,25 @@ function buildScssCommand(commandArgs) { stylesPath: corePath, outDir, }); + // Yield to the event loop so pending SIGINT can be processed + await new Promise(resolve => setTimeout(resolve, 0)); } - // Theme Variants CSS - fs.readdirSync(themesPath, { withFileTypes: true }) - .filter((item) => item.isDirectory()) - .forEach((themeDir) => { - compileAndWriteStyleSheets({ - name: themeDir.name, - stylesPath: `${themesPath}/${themeDir.name}/index.css`, - outDir, - isThemeVariant: true, - isDefaultThemeVariant: defaultThemeVariants.includes(themeDir.name), - }); + // Theme variants CSS (sequential so SIGINT can be handled between compilations) + const themeDirs = fs.readdirSync(themesPath, { withFileTypes: true }) + .filter((item) => item.isDirectory()); + + for (const themeDir of themeDirs) { + compileAndWriteStyleSheets({ + name: themeDir.name, + stylesPath: `${themesPath}/${themeDir.name}/index.css`, + outDir, + isThemeVariant: true, + isDefaultThemeVariant: defaultThemeVariants.includes(themeDir.name), }); + // Yield to the event loop so pending SIGINT can be processed + await new Promise(resolve => setTimeout(resolve, 0)); + } } module.exports = buildScssCommand;