Nodejs exits after awaiting async code without error

Tags: , ,



I’m making a build script for my angular app in node. Please have a look at the snippet:

const fs = require('fs-extra');

const dev = process.argv[2] === 'dev';
const folder = process.argv[3];

if (folder && fs.existsSync(`./projects/${folder}`)) {
    
    const execSync = require('child_process').execSync;
    // ng build --prod --output-hashing=none OR ng build --source-map --output-hashing=none
    
    let command;
    if (dev) {
        command = 'ng build --source-map --output-hashing=none ' + folder;
    } else {
        command = 'ng build --prod --output-hashing=none ' + folder;
    }

    // execSync(command, {stdio:[0, 1, 2]});

    (async function build()
        {
            
            const files = [
            ];
            const { promisify } = require('util')

            const getFiles = async () => {
                try {
                    const readdir = promisify(fs.readdir);
                    await readdir(`./dist/${folder}`, {withFileTypes:true}, (err, elements) => {
                        //handling error
                        if (err) {
                            return console.error('Unable to scan directory: ' + err);
                        } else {
                            elements.forEach(async element => {
                                if( !element.isDirectory() && /.*-es2015.js$/.test(element.name) ) {
                                    files.push(`./dist/${folder}/${element.name}`);
                                    console.log(`Pushing file: ./dist/${folder}/${element.name}`);
                                }
                            });
                        }
                    });
                } catch (err) {
                    console.error(err);
                }
            }
            
            await getFiles();

            // We need a random number for voiding the cache with every new build
            const random = [...Array(10)].map(()=>(c = (r = Math.random()).toString(36)[2]) && r>.5 ? c.toUpperCase():c ).join('');

            // create directory if doesnt exists (not needed anymore): await fs.ensureDir(`../js/${folder}/dist`)
            if (!dev && files.length) {
                const concat = require('concat');
                await concat(files, `./dist/${folder}/concatenated.${random}.js`);
            }
            console.log('Build complete');
        }
    )();
    
} else if (folder && !fs.existsSync(`projects/${folder}`)) {
    console.log('Specified destination folder does not exists as a project');
}
else {
    console.log('Please specify a destination folder such as app-name');
}

Well, the mysterious is that just after await getFiles() call, the execution halts, no error neither message anywhere is shown. I’m getting crazy investigating this.

Can anybody spot the issue? Thanks

Answer

The main issue in your code is that you are not promisfying the readdir correctly.

Try this:

(async () => {
    try {
        const readdir = require('util').promisify(require('fs').readdir);
        const elements = await readdir(`./dist/${folder}`, { withFileTypes: true });
        await Promise.all(
            elements.map(async (element) => {
                if (!element.isDirectory() && /.*-es2015.js$/.test(element.name)) {
                    files.push(`./dist/${folder}/${element.name}`);
                    console.log(`Pushing file: ./dist/${folder}/${element.name}`);
                }
            })
        );
    } catch (error) {
        console.error('Unable to scan directory: ' + err);
    }
})();

You can of course keep your forEach while omitting the async instead of the map + async + Promise.all. The difference is is that the one I suggest is faster since it utilizes concurrency while forEach would work sequentially! But either one would work!



Source: stackoverflow