简体   繁体   中英

Dynamically export a module by reading all files in a directory in Node.js

So today i was trying read all default exports from some directory which has index.js . Try to wrap it inside one object and export it back again. Is there a better way to handle this?

 export default (() => require('fs')
            .readdirSync(__dirname)
            .filter(fileName => !!/.js$/ig.test(fileName))
            .map(fileName => fileName.split('.')[0])
            .reduce((defaultExportObj, nextFileName) => {
                try {
                    return {
                        ...defaultExportObj,
                        [nextFileName]: require(__dirname + `/${nextFileName}`),
                    };
                }catch(err) { throw err; }
            }, {}))();

I guess i'd do something like this - not sure if this is better - w/e better is ^^

webpack: require.context

function expDefault(path, mode = "sync"){

    const modules = {}
    const context = require.context(path, false, /\.js$/, mode)
    context.keys().forEach(file => {
        const name = fileName.replace(/^.+\/([^/]+)\.js$/, "$1")
        modules[name] = context(name).default
    })
    return modules
}
export default expDefault(__dirname)

This seems like mostly personal style preferences, but I'd just use a plain for/of loop and some if statements instead of 3 intermediate arrays.

const moduleList = {};
const files = require('fs').readdirSync(__dirname);
const jsExt = /.js$/i;

for (const filename of files) {
    if (jsExt.test(filename)) {
        const baseFilename = filename.slice(-3);
        moduleList[baseFilename] = require(__dirname + '/' + baseFilename),
    }
}

export default moduleList;

Comments:

  1. Creates regex object once rather than multiple times
  2. No need for g flag on the regex
  3. Use filename.slice(-3) to remove known file extension because .split('.')[0] doesn't get you the string after last . and windows allows multiple . in a filename. Also, no need to search for where the . is as you already know where it is since it's a known extension.
  4. Only one array created from readdirSync() rather than two additional intermediate arrays
  5. The array is only iterated once instead of four times.
  6. There's no point to try {...} catch(err) { throw err; } try {...} catch(err) { throw err; } unless you're going to put something else in the catch block.
  7. A mix of template literals and string addition in __dirname + `/${nextFileName}` doesn't make sense to me. Use one or the other.

If you have some reason to want all symbols private, you could modify it to this:

export default (function() {
    const moduleList = {};
    const files = require('fs').readdirSync(__dirname);
    const jsExt = /.js$/i;

    for (const filename of files) {
        if (jsExt.test(filename)) {
            const baseFilename = filename.slice(-3);
            moduleList[baseFilename] = require(__dirname + '/' + baseFilename),
        }
    }
    return moduleList;
})();    

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM