I wish to split a large configuration .js file into multiple smaller files yet still combine them into the same module. Is this common practice and what is the best approach so that the module would not need extending when new files are added.
An example such as but not needing to update math.js when a new file is added.
math
- add.js
- subtract.js
- math.js
// add.js
module.exports = function(v1, v2) {
return v1 + v2;
}
// subtract.js
module.exports = function(v1, v2) {
return v1 - v2;
}
// math.js
var add = require('./add');
exports.add = add;
var subtract = require('./subtract');
exports.subtract = subtract;
// app.js
var math = require('./math');
console.log('add = ' + math.add(5,5));
console.log('subtract =' + math.subtract(5,5));
You can use the spread operator ... or if that doesnt work Object.assign.
module.exports = {
...require('./some-library'),
};
Or:
Object.assign(module.exports, require('./some-library'));
If your NodeJs allows the spread (...) operator (check it here), you can do:
module.exports = {
...require('./src/add'),
...require('./src/subtract')
}
You can do this
// math.js
module.exports = function (func){
return require('./'+func);
}
//use it like this
// app.js
var math = require('./math');
console.log('add = ' + math('add')(5,5));
console.log('subtract =' + math('subtract')(5,5));
You could create a subfolder to assign functions and other objects automaticly.
mymodule.js
const pluginDir = __dirname + '/plugins/';
const fs = require('fs');
module.exports = {};
fs.readdirSync(pluginDir).forEach(file => {
Object.assign(module.exports,require(pluginDir + file));
});
plugins/mymodule.myfunction.js
module.exports = {
myfunction: function() {
console.log("It works!");
}
};
index.js
const mymodule = require('mymodule.js');
mymodule.myfunction();
// It works!
Related
I am trying to understand the following code from the browserify-css repo:
var gulp = require('gulp');
var gutil = require('gulp-util');
var path = require('path');
var browserify = require('browserify');
var sourceStream = require('vinyl-source-stream');
var fse = require('fs-extra');
var bundleStream = browserify()
.add('src/index.js')
.transform(require('browserify-css'), {
rootDir: 'src',
processRelativeUrl: function(relativeUrl) {
var stripQueryStringAndHashFromPath = function(url) {
return url.split('?')[0].split('#')[0];
};
var rootDir = path.resolve(process.cwd(), 'src');
var relativePath = stripQueryStringAndHashFromPath(relativeUrl);
var queryStringAndHash = relativeUrl.substring(relativePath.length);
//
// Copying files from '../node_modules/bootstrap/' to 'dist/vendor/bootstrap/'
//
var prefix = '../node_modules/';
if (_.startsWith(relativePath, prefix)) {
var vendorPath = 'vendor/' + relativePath.substring(prefix.length);
var source = path.join(rootDir, relativePath);
var target = path.join(rootDir, vendorPath);
gutil.log('Copying file from ' + JSON.stringify(source) + ' to ' + JSON.stringify(target));
fse.copySync(source, target);
// Returns a new path string with original query string and hash fragments
return vendorPath + queryStringAndHash;
}
return relativeUrl;
}
})
.bundle();
bundleStream
.pipe(sourceStream(bundleFile))
.pipe(gulp.dest(browserifyConfig.dest));
I don't understand the part
_.startsWith(relativePath, prefix)
Where is the underscore coming from? It's supposed to be javascript executed by a task runner. I've found that in the NodeJS REPL the underscore character outputs the result of the last executed expression, but that functionality can't be used inside scripts. It's also not an underscore.js instance because it is not being declared anywhere. startsWith is a String method.
So what am I missing?
That code is using the lodash library. You can see in this section of the readme that they're importing lodash with var _ = require('lodash');
Is there any possibility to include one file into another with Browserify?
I mean not standard Browserify behavior, but pasting one file into another in a specific place.
file1.js
console.log("abc");
file2.js
requirePaste("file1.js");
console.log("def");
output.js
console.log("abc");
console.log("def");
I need it for spreading an ES6 class into multiple files like this pattern:
ObjectManager.js
ObjectManager_Events.js
ObjectManager_Rendering.js
These files are about one class. So I can make something like this:
class ObjectManager {
constructor() {
}
requirePaste("./ObjectManager_Events");
requirePaste("./ObjectManager_Rendering");
}
EDIT:
I made a simple transform plugin for Browserify and it works great. There is one problem though it won't work with Watchify. this is because inline-required files aren't counted as being watched. Any idea on how to fix this?
const through = require('through2');
const fs = require('fs');
const path = require('path');
const regex = /require\([\s]*\/\*inline\*\/[\s]*"(.+)"\)/g;
function process(pathToFile, contents) {
while ( (occurence = regex.exec(contents)) ) {
contents = processOne(pathToFile, contents, occurence);
}
return contents;
}
function processOne(pathToFile, contents, occurence) {
const dir = path.dirname(pathToFile);
const includePath = occurence[1] + ".js";
const range = [occurence.index, occurence.index+occurence[0].length-1];
const pathToInnerFile = dir + "/" + includePath;
var innerContents = fs.readFileSync(pathToInnerFile, 'utf8');
innerContents = process(pathToInnerFile, innerContents);
var output = "";
output += contents.substring(0, range[0]);
output += innerContents;
output += contents.substring(range[1]+1);
return output;
}
module.exports = function(pathToFile) {
return through(
function(buf, enc, next) {
var result = process(pathToFile, buf.toString('utf8'));
this.push(result);
next();
}
);
};
That did the trick:
Basically we inform Watchify about file by emiting 'file' event.
const includedFiles = [];
function process(pathToFile, contents) {
includedFiles.push(pathToFile);
while ( (occurence = regex.exec(contents)) ) {
contents = processOne(pathToFile, contents, occurence);
}
return contents;
}
...
module.exports = function(pathToFile) {
return through(
function(buf, enc, next) {
var result = process(pathToFile, buf.toString('utf8'));
this.push(result);
includedFiles.forEach((filePath) => this.emit("file", filePath));
includedFiles.length = 0;
next();
}
);
};
I have a js file with following structure:
define("example/example", ["exports", "example/something", "example/other", "ex/sthg"], function(e, t, n, a, r) {
e["default"] = {something: 'example'}
}), define("examle/module", ["exports"], function(e) {
///
}), define("examle/module2", ["exports"], function(e) {
// and so on...
}), require("example/sthg")["default"].callSomething({
//
});
I'm looking for a way to unpack this file into original files, like example/example.js, example/module, example/module2 etc.
I've tried browser-unpack, but with no effect so I assume that isn't bundled with browserify. Syntax looks similar to AMD or RequireJS.
Is there any away to debundle file like that?
Quick monkey solution, which helps me enough - it creates modules tree with import list and function(e, t, n... as a file content. Maybe it can be useful for someone. In my case, it can be fully debundled (of course only to js, not jsx), but I don't want to play with js parsers.
var fs = require('fs');
var path = require('path');
var mkdirp = require('mkdirp');
const defineArgs = ['e', 't', 'n', 'a', 'r']
function parseFunction(func, deps) {
let funcStr = func.toString(),
depsArr = [],
depsStr = ''
// just to know what etnar is
for(let i in deps) {
if(deps[i]!='exports') {
depsArr.push('const ' + defineArgs[i] + ' = require("' + deps[i] + '")')
}
}
depsStr = depsArr.join('\n')
return depsStr + '\n' + funcStr
}
// override define
var define = function(filename, deps, func) {
console.log(filename + ': ' + deps)
let outPath = 'src/' + filename + '.js',
outDir = path.dirname(outPath),
out = parseFunction(func, deps)
try {
fs.lstatSync(outDir)
} catch (e) {
mkdirp(outDir, function(err) { if(err){console.error(err)} })
}
fs.writeFile(outPath, out, function(err) {
if(err){console.error(err)}
})
}
// paste your script below and run this via node
// define("example/example", ["exports", "example/something", .......
I am really stuck by nodejs cache system. I have this structure for my project :
Project/
apps/
jobs_processor/
app.js
processors.js
processors/
libs/
queue_manager.js
queue_manager.js require processors.js
var processors = require("../apps/jobs_processor/processors.js");
app.js require also processor.js
var processors = require("./processors.js");
If I take into account the documentation, I must have the same path may be to obtain the same object, is that right ? If so, how can I achieve that (have the same path) ?
Thanks.
EDIT:
If found a solution to my problem.
Here is the first version of queue_manager.js file
var _ = require("lodash");
var Utils = require("./utilities");
var Processors = require("../apps/jobs_processor/processors");
var Logger = require("./logger");
var QUEUES_CACHE = {};
exports.createJob = createJob;
exports.getCacheObject = getCacheObject;
function createJob(name, data) {
var cacheId = name.replace(/ /g, "_");
Logger.info("Cache ID: " + cacheId);
if (!QUEUES_CACHE[ cacheId ]) {
_.each(Processors, function (processor) {
Logger.debug("PROCESSOR NAME: " + processor.name);
Logger.debug("JOB NAME: " + name);
if (processor.name === name)
QUEUES_CACHE[ cacheId ] = processor;
});
if (!QUEUES_CACHE[ cacheId ])
throw new Error("Processor for job \"" + name + "\" not found.");
}
Logger.debug(Object.keys(QUEUES_CACHE));
return QUEUES_CACHE[ cacheId ].queue.add(data);
}
function getCacheObject() {
return QUEUES_CACHE;
}
And now the last version of the same file
var _ = require("lodash");
var Utils = require("./utilities");
var Logger = require("./logger");
exports.createJob = createJob;
function createJob(name, data) {
var Processors = require("../apps/jobs_processor/processors");
var processor;
_.each(Processors, function (element) {
Logger.debug("Processor name: " + element.name);
if (element.name === name)
processor = element;
});
return processor.queue.add(data);
}
Each time that i called createJob method, I require the processors module which is an array of each job processor that I have created.
Node.js will resolve the path before caching the module.
As long as your relative paths resolve to the same absolute path on disk, you're fine.
I am writing a Node.js module and I need to pass variable data from the main file to the functions. I am doing this:
var region;
var api_key;
exports.region = region;
exports.api_key = api_key;
module.exports = {
getSummonerId: function(sum, callback) {
var summoners = {};
var summoner = sum.replace(/\s+/g, '');
request("https://na.api.pvp.net/api/lol/" + region + "/v1.4/summoner/by-name/" + summoner + "?api_key=" + api_key, function(error, response, body) {
summoners[summoner] = JSON.parse(body);
callback(summoners[summoner][summoner].id);
});
}
}
And in the main file:
var lol = require('./apiwrapper.js');
lol.api_key = "example";
lol.region = "las";
lol.getChampions(function(data) {
console.log(data);
})
But from apiwrapper.js file, those two variables' value are always "undefined".
How can I fix this?
The value that is imported to the other module is module.exports. So, what you assign to module.exports is exported. Whatever was assigned earlier to it is lost.
The relation between module.exports and exports is that they refer to the same object initially:
var exports = module.exports = {};
So, assigning a property to either of them mutates the same object. However, you are assigning a new object to module.exports, so now both of them reference different objects.
A simple solution is to assign the new object to exports as well and then assign the other properties:
exports = module.exports = {...};
exports.region = region;
If you want to keep the order of the statements, then you have to extend the default exports object, instead of creating a new one:
Object.assign(exports, { ... });
Use:
module.exports = {
region: my_region,
api_key: my_api_key,
getSummonerId: function(sum, callback) {
var summoners = {};
var summoner = sum.replace(/\s+/g, '');
request("https://na.api.pvp.net/api/lol/" + region + "/v1.4/summoner/by-name/" + summoner + "?api_key=" + api_key, function(error, response, body) {
summoners[summoner] = JSON.parse(body);
callback(summoners[summoner][summoner].id);
});
}
}
In your case, "module.exports" is overwriting the previously exported variables. Which is the reason you are getting undefined for those.