How to export everything from every file in a directory? - node.js

Usually, I create an index.js file that exports everything from every file in a specific directory. like this:
export * from "./file1"
export * from "./file2"
export * from "./file3"
This is a common pattern in all of my projects. The downside of this approach is that whenever I create a new file in a directory I have to change its corresponding index.js file and export the new file. Now I'm trying to automate it and write a script that exports everything in every file in a directory.
after some googling, I came up with this:
import fs from "fs";
export let exp = {};
fs.readdirSync("./").forEach(function (file) {
if (file.indexOf(".js") > -1 && file != "index.js") {
const imp = require(`./` + file);
exp = { ...exp, ...imp };
}
});
But it doesn't work, maybe because I used the require function and that doesn't work with ES modules.
Also, I can't write something like this because I'm not allowed to use export in a function block.
export let exp = {};
fs.readdirSync("./").forEach(function (file) {
if (file.indexOf(".ts") > -1 && file != "index.ts") {
export * from ("./"+file);
}
});
So I stock here. do you have any idea about this?

I suggest using a package like glob. The glob package allows you to get all files inside a directory including those hidden within a subfolder.
Example usage:
const glob = require("glob");
glob("**/*", function (err, files) {
// files is an array of filenames
// err is an error object or null
});

Related

How to create an import/export script using Node.JS?

I'm looking to import/export a list of files in a directory through an index.js file in the same directory.
For example, I have 2 files in a directory: admin.js and user.js and I am looking to require and exporting them in the in the index.js like so
module.exports = {
admin: require("./admin"),
users: require("./users"),
};
The script I have come up with looks like this but it is not working and giving me an error
fs.readdirSync(__dirname, (files) => {
files.forEach((file) => {
module.exports[file] = require(`./${file}`);
});
});
How can I improve this script to make it work?
Thank you!
[Update - 2022 December 18]
Found a solution based off of sequelize models/index.js, this will pretty much require and export your files and folders, feel free to use and modify
const fs = require('fs')
const path = require('path')
const basename = path.basename(__filename)
const controllers = {}
fs.readdirSync(__dirname)
.filter((folder) => {
return folder.indexOf('.') !== 0 && folder !== basename
})
.forEach((folder) => {
const controller = require(path.join(__dirname, folder))
controllers[controller.name] = controller
})
module.exports = controllers
fs.readdirSync() does NOT accept a callback. It directly returns the result:
const files = fs.readdirSync(__dirname);
for (let file of files) {
module.exports[file] = require(`./${file}`);
}
Note, the future of the Javascript language is using import and export with statically declared module names instead of require()and module.exports and this structure will generally not work with the newer way of doing things. So, if you expect to eventually move to the newer ESM modules, you may not want to bake in this type of architecture.
There is a dynamic import in ESM modules, but it's asynchronous (returns a promise that you have to wait for).
Also, note that this will attempt to reload your index.js file containing this code. That's might not be harmful, but may not be your intention.

extract 7zip files in Nodejs

I am trying to extract .7z files which is password protected.
In a particular folder path there are some .7z files format. First I have to extract all files in the same directory than I have to do another stuff with this files.
const path = require('path')
const fs = require('fs')
import { extractFull } from 'node-7z-forall';
const dirpath = path.join('C:/MyFolder/DATA')
fs.readdir(dirpath, function(err, files) {
const txtFiles = files.filter(el => path.extname(el) === '.7z')
console.log(txtFiles);
extractFull(txtFiles, 'C:/MyFolder/DATA', { p: 'admin123' } /* 7z options/switches */)
.progress(function (files) {
console.log('Some files are extracted: %s', files);
});
})
I am using node-7z-forall module but it is only working when I change the file format to .js to .mjs. in .mjs file format file extract smoothly .but in .js format it is not working.
error:
import { extractFull } from 'node-7z-forall';
^^^^^^
SyntaxError: Cannot use import statement outside a module
How to handle this error. Is it possible to work with in .js format instead of .mjs format?
I am new in nodejs. Please help!
the reason it errors, it that ".js" indicates a commonjs file which uses require() but a ".mjs" file indicates a module which uses the import syntax.
This is also where the error comes from because you try to use import in a non module.
You can prevent the error by simply importing the package using require():
const { extractFull } = require('node-7z-forall');

Can you pull in excludes/includes options in Typescript Compiler API?

I'm trying use the Typescript API to do some custom compilation (using plugins, etc.).
When compiling with the command line, typescript will automatically take into account not only the compilerOptions, but also the excludes key, as well as the types key (among other things).
The Typescript API documentation is almost non-existent, but I've tried manually doing a deep search and excluding these files from the total file list passed into the createProgram method. However, this has taken a toll on our build performance, and I think the Typescript compiler has a much more efficient solution.
Here's what I have in my compile.ts file.
import ts from 'typescript';
import keysTransformer from 'ts-transformer-keys/transformer';
import tsConfig from './tsconfig.json';
import fs from 'fs';
const deepFindTsFiles = (dir: string, fileList?: string[]) => {
dir = dir.endsWith('/') ? dir : dir + '/'
const files = fs.readdirSync(dir);
fileList = fileList || [];
files.forEach((file) => {
console.log('file', dir + file);
console.log(tsConfig.exclude.includes(dir + file));
if (fs.statSync(dir + file).isDirectory() && !tsConfig.exclude.includes(dir + file)) {
fileList = deepFindTsFiles(dir + file + '/', fileList);
}
else if (!tsConfig.exclude.includes(dir + file) && file.split('.')[1].includes('ts')) {
fileList!.push(dir + file);
}
});
return fileList;
};
const fileList = deepFindTsFiles(tsConfig.compilerOptions.rootDir);
// the compiler options parsed from tsconfig.json
const { options } = ts.parseJsonConfigFileContent(
tsConfig,
ts.sys,
__dirname
);
// createProgram doesn't seem to have an option for excludes/includes/types
const program = ts.createProgram(fileList, options);
const transformers = {
before: [keysTransformer(program)],
after: []
};
program.emit(undefined, undefined, undefined, false, transformers);
The code above properly compiles my source code and applies the proper plugins, however it's much slower than using the command line tools.
What's passed into the createProgram method is just the compilerOptions object in my tsconfig.json file, not the files to exclude. It does not seem like the createProgram method takes any arguments like this.
But, surely there is? Right? I have to imagine that this is possible. But, the documentation is severely lacking
I managed to figure out how to get the list of fileNames using the tsconfig.json and the TS compiler API.
const configPath = ts.findConfigFile(
"./", /*searchPath*/
ts.sys.fileExists,
"tsconfig.json"
);
if (!configPath) throw new Error("Could not find a valid 'tsconfig.json'.");
const configFile = ts.readJsonConfigFile(configPath, ts.sys.readFile);
const { fileNames } = ts.parseJsonSourceFileConfigFileContent(
configFile,
ts.sys,
'./'
);
console.log(fileNames)
This takes into account the includes and excludes specified in the tsconfig.json.
This might not be the best way to do this but I have been struggling to figure this out for a while.

Dynamically exporting functions in firebase

I'm having the typical (according to many posts) issue with cold boot times in cloud functions. A solution that seemed promised suggests to import / export only the function actually being executed, as can be seen here:
https://github.com/firebase/functions-samples/issues/170#issuecomment-323375462
if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === 'sendFollowerNotification') {
exports.sendFollowerNotification = require('./sendFollowerNotification');
}
Which is a Javascript example, but I'm using typescript. I've tried a number of variations, and while some build, in the end I'm always stuck with my function not being exported and deploy warning me that I'm going to delete the existing function.
This is one of the numerous attempts:
if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === 'generateInviteURL') {
import ('./invite_functions').then ((mod) => { console.log ("mod follows" ); console.log (mod); exports.generateInviteURL = functions.https.onRequest( mod.generateInviteURL ); } )
.catch ((err) => {console.log ("Trying to import/export generateInviteURL ", err);}) ;
}
At mentioned, at deploy time what happens is that I get a warning about the function being deleted.
I was able to "avoid" that message with something like this:
console.log ("Function name: ", process.env.FUNCTION_NAME);
function dummy_generateInviteURL (req, res) { ; }
exports.generateInviteURL = functions.https.onRequest( dummy_generateInviteURL );
if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === 'generateInviteURL') {
console.log ("Doing the good import");
import ('./invite_functions').then ((mod) => { console.log ("mod follows" ); console.log (mod); exports.generateInviteURL = functions.https.onRequest( mod.generateInviteURL ); } )
.catch ((err) => {console.log ("Trying to import/export generateInviteURL ", err);}) ;
}
console.log ("Exported");
console.log (exports.generateInviteURL);
Which the idea of course that an empty function would be always be exported but would be replaced with the real one if that's the one being called.
In that case logs look like this:
generateInviteURL Function name: generateInviteURL generateInviteURL
generateInviteURL Exported generateInviteURL
{ [Function: cloudFunction] __trigger: { httpsTrigger: {} } }
So the first part looks promising (the environment variable is defined), then the import does something (enters the then block, never the catch), but the exported variable is not replaced.
I'm not sure if this is a TypeScript problem, a firebase problem, or a developer problem - probably I'm just missing something obvious.
So the question - how can I avoid importing/exporting anything I don't need for each specific function?
You can stick to the original index.js, with minor changes. I have tried a few times and came with a solution. Am including a sample dir structure and two typescript files (index.ts and another for your custom function). With this you will never have to change the index.ts to modify or add functions.
Directory Structure
+ functions
|
-- + src
| |
| -- index.ts
| |
| -- + get
| |
| -- status.f.ts
-- package.json (auto generated)
|
-- package-lock.json (auto generated)
|
-- tsconfig.json (auto generated)
|
-- tslint.json (auto generated)
|
-- + lib (auto generated)
|
-- + node_modules (auto generated)
src/index.ts
import * as glob from "glob";
import * as camelCase from "camelcase";
const files = glob.sync('./**/*.f.js', { cwd: __dirname, ignore: './node_modules/**'});
for(let f=0,fl=files.length; f<fl; f++){
const file = files[f];
const functionName = camelCase(file.slice(0, -5).split('/').join('_')); // Strip off '.f.js'
if (!process.env.FUNCTION_NAME || process.env.FUNCTION_NAME === functionName) {
exports[functionName] = require(file);
}
}
src/get/status.f.ts
import * as functions from 'firebase-functions';
exports = module.exports = functions.https.onRequest((req, res) => {
res.status(200).json({'status':'OK'})
})
Once you have created the above file install npm packages 'glob' and 'camelcase',
then try to deploy the firebase functions
Firebase will deploy a function named 'getStatus'
NOTE that the name of the function is camel case version of folder names and the file name where the function exists, so you can export only one function per .f.ts file
EDIT
I have updated the dir structure. Note that index.ts and all the subsequent files and folders resides within the parent folder 'src'
I've been having similar issues, and I wrote a pretty cool solution that worked for me.
I decided to release it as an open-source package - I've never done that before so if anyone can check it out, contribute or give feedback that would be great.
The package is called better-firebase-functions - https://www.npmjs.com/package/better-firebase-functions
All you have to do is import and run it. Two lines. Pretty much everything else is automated.
It will pick up the default exports of all function files in your directory and deploy them as properly named functions.
Here is an example:
import { exportFunctions } from 'better-firebase-functions';
exportFunctions({
__filename, // standard node var (leave as is).
exports, // standard node var (leave as is).
functionDirectoryPath: './myFuncs', // define root functions folder
// relative to this file.
searchGlob: '**/*.js' // file search glob pattern.
});
The only other thing you need to do is export your function.http.onRequest()... as a default export from every file that contains a cloud function that you want to deploy. So:
export default functions.http.onRequest()...
/// OR
const func1 = functions.http.onRequest()...
export default func1;
And that's it!
UPDATE: Answer edited to reflect newer version of package.

node.js require all files in a folder?

How do I require all files in a folder in node.js?
need something like:
files.forEach(function (v,k){
// require routes
require('./routes/'+v);
}};
When require is given the path of a folder, it'll look for an index.js file in that folder; if there is one, it uses that, and if there isn't, it fails.
It would probably make most sense (if you have control over the folder) to create an index.js file and then assign all the "modules" and then simply require that.
yourfile.js
var routes = require("./routes");
index.js
exports.something = require("./routes/something.js");
exports.others = require("./routes/others.js");
If you don't know the filenames you should write some kind of loader.
Working example of a loader:
var normalizedPath = require("path").join(__dirname, "routes");
require("fs").readdirSync(normalizedPath).forEach(function(file) {
require("./routes/" + file);
});
// Continue application logic here
I recommend using glob to accomplish that task.
var glob = require( 'glob' )
, path = require( 'path' );
glob.sync( './routes/**/*.js' ).forEach( function( file ) {
require( path.resolve( file ) );
});
Base on #tbranyen's solution, I create an index.js file that load arbitrary javascripts under current folder as part of the exports.
// Load `*.js` under current directory as properties
// i.e., `User.js` will become `exports['User']` or `exports.User`
require('fs').readdirSync(__dirname + '/').forEach(function(file) {
if (file.match(/\.js$/) !== null && file !== 'index.js') {
var name = file.replace('.js', '');
exports[name] = require('./' + file);
}
});
Then you can require this directory from any where else.
Another option is to use the package require-dir which let's you do the following. It supports recursion as well.
var requireDir = require('require-dir');
var dir = requireDir('./path/to/dir');
I have a folder /fields full of files with a single class each, ex:
fields/Text.js -> Test class
fields/Checkbox.js -> Checkbox class
Drop this in fields/index.js to export each class:
var collectExports, fs, path,
__hasProp = {}.hasOwnProperty;
fs = require('fs');
path = require('path');
collectExports = function(file) {
var func, include, _results;
if (path.extname(file) === '.js' && file !== 'index.js') {
include = require('./' + file);
_results = [];
for (func in include) {
if (!__hasProp.call(include, func)) continue;
_results.push(exports[func] = include[func]);
}
return _results;
}
};
fs.readdirSync('./fields/').forEach(collectExports);
This makes the modules act more like they would in Python:
var text = new Fields.Text()
var checkbox = new Fields.Checkbox()
One more option is require-dir-all combining features from most popular packages.
Most popular require-dir does not have options to filter the files/dirs and does not have map function (see below), but uses small trick to find module's current path.
Second by popularity require-all has regexp filtering and preprocessing, but lacks relative path, so you need to use __dirname (this has pros and contras) like:
var libs = require('require-all')(__dirname + '/lib');
Mentioned here require-index is quite minimalistic.
With map you may do some preprocessing, like create objects and pass config values (assuming modules below exports constructors):
// Store config for each module in config object properties
// with property names corresponding to module names
var config = {
module1: { value: 'config1' },
module2: { value: 'config2' }
};
// Require all files in modules subdirectory
var modules = require('require-dir-all')(
'modules', // Directory to require
{ // Options
// function to be post-processed over exported object for each require'd module
map: function(reqModule) {
// create new object with corresponding config passed to constructor
reqModule.exports = new reqModule.exports( config[reqModule.name] );
}
}
);
// Now `modules` object holds not exported constructors,
// but objects constructed using values provided in `config`.
I know this question is 5+ years old, and the given answers are good, but I wanted something a bit more powerful for express, so i created the express-map2 package for npm. I was going to name it simply express-map, however the people at yahoo already have a package with that name, so i had to rename my package.
1. basic usage:
app.js (or whatever you call it)
var app = require('express'); // 1. include express
app.set('controllers',__dirname+'/controllers/');// 2. set path to your controllers.
require('express-map2')(app); // 3. patch map() into express
app.map({
'GET /':'test',
'GET /foo':'middleware.foo,test',
'GET /bar':'middleware.bar,test'// seperate your handlers with a comma.
});
controller usage:
//single function
module.exports = function(req,res){
};
//export an object with multiple functions.
module.exports = {
foo: function(req,res){
},
bar: function(req,res){
}
};
2. advanced usage, with prefixes:
app.map('/api/v1/books',{
'GET /': 'books.list', // GET /api/v1/books
'GET /:id': 'books.loadOne', // GET /api/v1/books/5
'DELETE /:id': 'books.delete', // DELETE /api/v1/books/5
'PUT /:id': 'books.update', // PUT /api/v1/books/5
'POST /': 'books.create' // POST /api/v1/books
});
As you can see, this saves a ton of time and makes the routing of your application dead simple to write, maintain, and understand. it supports all of the http verbs that express supports, as well as the special .all() method.
npm package: https://www.npmjs.com/package/express-map2
github repo: https://github.com/r3wt/express-map
Expanding on this glob solution. Do this if you want to import all modules from a directory into index.js and then import that index.js in another part of the application. Note that template literals aren't supported by the highlighting engine used by stackoverflow so the code might look strange here.
const glob = require("glob");
let allOfThem = {};
glob.sync(`${__dirname}/*.js`).forEach((file) => {
/* see note about this in example below */
allOfThem = { ...allOfThem, ...require(file) };
});
module.exports = allOfThem;
Full Example
Directory structure
globExample/example.js
globExample/foobars/index.js
globExample/foobars/unexpected.js
globExample/foobars/barit.js
globExample/foobars/fooit.js
globExample/example.js
const { foo, bar, keepit } = require('./foobars/index');
const longStyle = require('./foobars/index');
console.log(foo()); // foo ran
console.log(bar()); // bar ran
console.log(keepit()); // keepit ran unexpected
console.log(longStyle.foo()); // foo ran
console.log(longStyle.bar()); // bar ran
console.log(longStyle.keepit()); // keepit ran unexpected
globExample/foobars/index.js
const glob = require("glob");
/*
Note the following style also works with multiple exports per file (barit.js example)
but will overwrite if you have 2 exports with the same
name (unexpected.js and barit.js have a keepit function) in the files being imported. As a result, this method is best used when
your exporting one module per file and use the filename to easily identify what is in it.
Also Note: This ignores itself (index.js) by default to prevent infinite loop.
*/
let allOfThem = {};
glob.sync(`${__dirname}/*.js`).forEach((file) => {
allOfThem = { ...allOfThem, ...require(file) };
});
module.exports = allOfThem;
globExample/foobars/unexpected.js
exports.keepit = () => 'keepit ran unexpected';
globExample/foobars/barit.js
exports.bar = () => 'bar run';
exports.keepit = () => 'keepit ran';
globExample/foobars/fooit.js
exports.foo = () => 'foo ran';
From inside project with glob installed, run node example.js
$ node example.js
foo ran
bar run
keepit ran unexpected
foo ran
bar run
keepit ran unexpected
One module that I have been using for this exact use case is require-all.
It recursively requires all files in a given directory and its sub directories as long they don't match the excludeDirs property.
It also allows specifying a file filter and how to derive the keys of the returned hash from the filenames.
Require all files from routes folder and apply as middleware. No external modules needed.
// require
const { readdirSync } = require("fs");
// apply as middleware
readdirSync("./routes").map((r) => app.use("/api", require("./routes/" + r)));
I'm using node modules copy-to module to create a single file to require all the files in our NodeJS-based system.
The code for our utility file looks like this:
/**
* Module dependencies.
*/
var copy = require('copy-to');
copy(require('./module1'))
.and(require('./module2'))
.and(require('./module3'))
.to(module.exports);
In all of the files, most functions are written as exports, like so:
exports.function1 = function () { // function contents };
exports.function2 = function () { // function contents };
exports.function3 = function () { // function contents };
So, then to use any function from a file, you just call:
var utility = require('./utility');
var response = utility.function2(); // or whatever the name of the function is
Can use : https://www.npmjs.com/package/require-file-directory
Require selected files with name only or all files.
No need of absoulute path.
Easy to understand and use.
Using this function you can require a whole dir.
const GetAllModules = ( dirname ) => {
if ( dirname ) {
let dirItems = require( "fs" ).readdirSync( dirname );
return dirItems.reduce( ( acc, value, index ) => {
if ( PATH.extname( value ) == ".js" && value.toLowerCase() != "index.js" ) {
let moduleName = value.replace( /.js/g, '' );
acc[ moduleName ] = require( `${dirname}/${moduleName}` );
}
return acc;
}, {} );
}
}
// calling this function.
let dirModules = GetAllModules(__dirname);
Create an index.js file in your folder with this code :
const fs = require('fs')
const files = fs.readdirSync('./routes')
for (const file of files) {
require('./'+file)
}
And after that you can simply load all the folder with require("./routes")
If you include all files of *.js in directory example ("app/lib/*.js"):
In directory app/lib
example.js:
module.exports = function (example) { }
example-2.js:
module.exports = function (example2) { }
In directory app create index.js
index.js:
module.exports = require('./app/lib');

Resources