How do I require() from the console using webpack? - javascript

How do I require() / import modules from the console? For example, say I've installed the ImmutableJS npm, I'd like to be able to use functions from the module while I'm working in the console.

Here's another more generic way of doing this.
Requiring a module by ID
The current version of WebPack exposes webpackJsonp(...), which can be used to require a module by ID:
function _requireById(id) {
return webpackJsonp([], null, [id]);
}
or in TypeScript
window['_requireById'] =
(id: number): any => window['webpackJsonp'];([], null, [id]);
The ID is visible at the top of the module in the bundled file or in the footer of the original source file served via source maps.
Requiring a module by name
Requiring a module by name is much trickier, as WebPack doesn't appear to keep any reference to the module path once it has processed all the sources. But the following code seems to do the trick in lot of the cases:
/**
* Returns a promise that resolves to the result of a case-sensitive search
* for a module or one of its exports. `makeGlobal` can be set to true
* or to the name of the window property it should be saved as.
* Example usage:
* _requireByName('jQuery', '$');
* _requireByName('Observable', true)´;
*/
window['_requireByName'] =
(name: string, makeGlobal?: (string|boolean)): Promise<any> =>
getAllModules()
.then((modules) => {
let returnMember;
let module = _.find<any, any>(modules, (module) => {
if (_.isObject(module.exports) && name in module.exports) {
returnMember = true;
return true;
} else if (_.isFunction(module.exports) &&
module.exports.name === name) {
return true;
}
});
if (module) {
module = returnMember ? module.exports[name] : module.exports;
if (makeGlobal) {
const moduleName = makeGlobal === true ? name : makeGlobal as string;
window[moduleName] = module;
console.log(`Module or module export saved as 'window.${moduleName}':`,
module);
} else {
console.log(`Module or module export 'name' found:`, module);
}
return module;
}
console.warn(`Module or module export '${name}'' could not be found`);
return null;
});
// Returns promise that resolves to all installed modules
function getAllModules() {
return new Promise((resolve) => {
const id = _.uniqueId('fakeModule_');
window['webpackJsonp'](
[],
{[id]: function(module, exports, __webpack_require__) {
resolve(__webpack_require__.c);
}},
[id]
);
});
}
This is quick first shot at this, so it's all up for improvement!

Including this in a module will allow require([modules], function) to be used from a browser
window['require'] = function(modules, callback) {
var modulesToRequire = modules.forEach(function(module) {
switch(module) {
case 'immutable': return require('immutable');
case 'jquery': return require('jquery');
}
})
callback.apply(this, modulesToRequire);
}
Example Usage:
require(['jquery', 'immutable'], function($, immutable) {
// immutable and $ are defined here
});
Note: Each switch-statement option should either be something this module already requires, or provided by ProvidePlugin
Sources:
Based on this answer, which can be used to add an entire folder.
Alternative method from Webpack Docs - which allows something like require.yourModule.function()

I found a way that works, for both WebPack 1 and 2. (as long as the source is non-minified)
Repo: https://github.com/Venryx/webpack-runtime-require
Install
npm install --save webpack-runtime-require
Usage
First, require the module at least once.
import "webpack-runtime-require";
It will then add a Require() function to the window object, for use in the console, or anywhere in your code.
Then just use it, like so:
let React = Require("react");
console.log("Retrieved React.Component: " + React.Component);
It's not very pretty (it uses regexes to search the module wrapper functions) or fast (takes ~50ms the first call, and ~0ms after), but both of these are perfectly fine if it's just for hack-testing in the console.
Technique
The below is a trimmed version of the source to show how it works. (see the repo for the full/latest)
var WebpackData;
webpackJsonp([],
{123456: function(module, exports, __webpack_require__) {
WebpackData = __webpack_require__;
}},
[123456]
);
var allModulesText;
var moduleIDs = {};
function GetIDForModule(name) {
if (allModulesText == null) {
let moduleWrapperFuncs = Object.keys(WebpackData.m).map(moduleID=>WebpackData.m[moduleID]);
allModulesText = moduleWrapperFuncs.map(a=>a.toString()).join("\n\n\n");
// these are examples of before and after webpack's transformation: (which the regex below finds the var-name of)
// require("react-redux-firebase") => var _reactReduxFirebase = __webpack_require__(100);
// require("./Source/MyComponent") => var _MyComponent = __webpack_require__(200);
let regex = /var ([a-zA-Z_]+) = __webpack_require__\(([0-9]+)\)/g;
let matches = [];
let match;
while (match = regex.exec(allModulesText))
matches.push(match);
for (let [_, varName, id] of matches) {
// these are examples of before and after the below regex's transformation:
// _reactReduxFirebase => react-redux-firebase
// _MyComponent => my-component
// _MyComponent_New => my-component-new
// _JSONHelper => json-helper
let moduleName = varName
.replace(/^_/g, "") // remove starting "_"
.replace(new RegExp( // convert chars where:
"([^_])" // is preceded by a non-underscore char
+ "[A-Z]" // is a capital-letter
+ "([^A-Z_])", // is followed by a non-capital-letter, non-underscore char
"g"),
str=>str[0] + "-" + str[1] + str[2] // to: "-" + char
)
.replace(/_/g, "-") // convert all "_" to "-"
.toLowerCase(); // convert all letters to lowercase
moduleIDs[moduleName] = parseInt(id);
}
}
return moduleIDs[name];
}
function Require(name) {
let id = GetIDForModule(name);
return WebpackData.c[id].exports;
}

Being able to use require modules in the console is handy for debugging and code analysis. #psimyn's answer is very specific so you aren't likely to maintain that function with all the modules you might need.
When I need one of my own modules for this purpose, I assign a window property to it so I can get at it e.g window.mymodule = whatever_im_exporting;. I use the same trick to expose a system module if I want to play with it e.g:
myservice.js:
let $ = require('jquery');
let myService = {};
// local functions service props etc...
module.exports = myService;
// todo: remove these window prop assignments when done playing in console
window.$ = $;
window.myService = myService;
It is still a bit of a pain, but digging into the bundles, I can't see any way to conveniently map over modules.

The answer from #Rene Hamburger is good but unfortunately doesn't work anymore (at least with my webpack version). So I updated it:
function getWebpackInternals() {
return new Promise((resolve) => {
const id = 'fakeId' + Math.random();
window['webpackJsonp'].push(["web", {
[id]: function(module, __webpack_exports__, __webpack_require__) {
resolve([module, __webpack_exports__, __webpack_require__])
}
},[[id]]]);
});
}
function getModuleByExportName(moduleName) {
return getWebpackInternals().then(([_, __webpack_exports__, __webpack_require__]) => {
const modules = __webpack_require__.c;
const moduleFound = Object.values(modules).find(module => {
if (module && module.exports && module.exports[moduleName]) return true;
});
if (!moduleFound) {
console.log('couldnt find module ' + moduleName);
return;
}
return moduleFound.exports[moduleName];
})
}
getModuleByExportName('ExportedClassOfModule');

expose-loader is, in my opinion, a more elegant solution:
require("expose-loader?libraryName!./file.js");
// Exposes the exports for file.js to the global context on property "libraryName".
// In web browsers, window.libraryName is then available.

Adding the below code to one of your modules will allow you to load modules by id.
window.require = __webpack_require__;
In the console use the following:
require(34)

You could do something similar as psimyn advised by
adding following code to some module in bundle:
require.ensure([], function () {
window.require = function (module) {
return require(module);
};
});
Use require from console:
require("./app").doSomething();
See more

After making an npm module for this (see my other answer), I did a search on npms.io and seem to have found an existing webpack-plugin available for this purpose.
Repo: https://www.npmjs.com/package/webpack-expose-require-plugin
Install
npm install --save webpack-expose-require-plugin
Usage
Add the plugin to your webpack config, then use at runtime like so:
let MyComponent = require.main("./path/to/MyComponent");
console.log("Retrieved MyComponent: " + MyComponent);
See package/repo readme page for more info.
EDIT
I tried the plugin out in my own project, but couldn't get it to work; I kept getting the error: Cannot read property 'resource' of undefined. I'll leave it here in case it works for other people, though. (I'm currently using the solution mentioned above instead)

After both making my own npm package for this (see here), as well as finding an existing one (see here), I also found a way to do it in one-line just using the built-in webpack functions.
It uses WebPack "contexts": https://webpack.github.io/docs/context.html
Just add the following line to a file directly in your "Source" folder:
window.Require = require.context("./", true, /\.js$/);
Now you can use it (eg. in the console) like so:
let MyComponent = Require("./Path/To/MyComponent");
console.log("Retrieved MyComponent: " + MyComponent);
However, one important drawback of this approach, as compared to the two solutions mentioned above, is that it seems to not work for files in the node_modules folder. When the path is adjusted to "../", webpack fails to compile -- at least in my project. (perhaps because the node_modules folder is just so massive)

Related

How to prepend a JavaScript string to every module compiled by Webpack?

I want to prepend a JavaScript string to every module required in my code and compiled by Webpack.
For example, if my entry.js file looks like this:
import _ from 'lodash';
import $ from 'jquery';
import init from './init.js';
init();
I want my output.js bundle to consist of something like this:
function(module, exports, __webpack_require__) {
// prepended JavaScript goes here
// code for lodash module below
}
function(module, exports, __webpack_require__) {
// prepended JavaScript goes here
// code for jquery module below
}
function(module, exports, __webpack_require__) {
// prepended JavaScript goes here
// code for init.js module below
}
function(module, exports, __webpack_require__) {
// prepended JavaScript goes here
var _lodash = __webpack_require__(1);
var _jquery = __webpack_require__(2);
init();
}
I tried writing a simple loader, and it worked, except that it didn't include modules from node_modules since I'm excluding those from my /\.js$/ rule.
So I suspect I need to use a plugin. This is what I have so far:
var pluginName = "PrependJSPlugin";
var apply = (options, compiler) => {
compiler.hooks.compilation.tap(pluginName, compilation =>
compilation.hooks.afterOptimizeModules.tap(pluginName, modules => {
modules.forEach(mod => {
if (mod.resource !== void 0 && mod.resource.includes(".js")) {
var contId = "__WBP_PREPEND__";
var script = `
;var el = document.createElement('pre');
el.innerHTML = '${mod.resource}';
var container = document.getElementById('${contId}');
if (!container) {
container = document.createElement('div');
container.id = '${contId}';
container.appendChild(el);
document.getElementsByTagName('body')[0].appendChild(container);
} else {
container.appendChild(el);
}
`;
mod._source._value = script + mod._source._value;
}
});
})
);
};
module.exports = function(options) {
return {
apply: apply.bind(this, options)
};
};
For the most part, it seems like it's appending it correctly but the compiled output is getting corrupted somehow and I see syntax errors all over the place. I'm definitely doing something I shouldn't be doing with that _source property.
Can someone point me in the right direction?
Why do I want to do this?
This is not something that will go into production. I'm trying to debug a PhantomJS v1 error occurring in a third party service I use for rendering a PDF from an Angular page. Yikes, I know!
I'm catching errors with window.onerror and appending it to the body so they're displayed in the rendered PDF. Unfortunately, the errors don't include source file nor line numbers. So I'm trying to display the name of every module before it runs hoping to see at which one the JavaScript stops executing.

How to rollup multiple directories separately with one output

So, I have a directory:
mods/
-core/
--index.js
--scripts/
---lots of stuff imported by core/index
This works with typical rollup fashion if you want to rollup to for example mods/core/index.min.js
But I have many of these mods/**/ directories and I want to take advantage of the fact that they are rollup'd into iifes. Each mods/**/index.js will, rather than export, assign to a global variable that we presume is provided:
mods/core/index.js
import ui from './scripts/ui/'
global.ui = ui
mods/someMod/scripts/moddedClass.js
export default class moddedClass extends global.ui.something { /* some functionality extension */}
mods/someMod/index.js
import moddedClass from './scripts/moddedClass'
global.ui.something = moddedClass
So hopefully you can see how each mod directory can be rollup'd in typical fashion but, I need to then put the actual iifes inside another one so that:
mods/compiled.js
(function compiled() {
const global = {};
(function core() {
//typical rollup iife
})();
(function someMod() {
//typical rollup iife
})();
//a footer like return global or global.init()
})();
Any help towards this end would be greatly appreciated. The simplest possible answer, I think, is how I can simply get a string value for each mod's iife instead of rollup writing it to a file.
At that point I could just iterate the /mods/ directory, in an order specified by some modlist.json or something, and call rollup on each /mod/index.js, then build the outer iife myself from strings.
However, I suppose this would not be a full solution for sourcemapping? Or can multiple inline sourcemaps be included? With source mapping in mind, I wonder if another build step might be necessary, where each mod is transpiled before this system even gets to it.
Use rollup's bundle.generate api to generate multiple iifes and write them into one file using fs.appendFile.
For the sourcemaps you can use this module(it's from the same author of rollup) https://github.com/rich-harris/sorcery
Okay so the way I ended up solving this was using source-map-concat
It basically does what I described, right out of the box. The only thing I had to do was to asynchronously iterate the mod directory and rollup each mod, before passing the results to source-map-concat, since rollup.rollup returns a Promise.
I also ended up wanting in-line sourcemaps so that the code can be directly injected rather than written to a file, so I used convert-source-map for that.
The only issue left to solve is sub-source mapping. Sorcery would work great for that, if I was generating files, but I would like to keep it as string sources. For now it will at least show me what mod an error came from, but not the sub-file it came from. If anyone has info on how to do a sorcery-style operation on strings let me know.
Here's the relevant final code from my file:
const rollup = require("rollup")
const concat = require("source-map-concat")
const convert = require("convert-source-map")
const fs = require("fs")
const path = require("path")
const modsPath = path.join(__dirname, "mods")
const getNames = _ => JSON.parse(fs.readFileSync(path.join(modsPath, "loadList.json"), "utf8"))
const wrap = (node, mod) => {
node.prepend("\n// File: " + mod.source + "\n")
}
const rolls = {}
const bundles = {}
const rollupMod = (modName, after) => {
let dir = path.join(modsPath, modName),
file = path.join(dir, "index.js")
rollup.rollup({
entry: file,
external: "G",
plugins: []
}).then(bundle => {
rolls[modName] = bundle.generate({
format: "iife",
moduleName: modName,
exports: "none",
useStrict: false,
sourceMap: true
})
after()
})
}
const rollupMods = after => {
let names = getNames(), i = 0,
rollNext = _ => rollupMod(names[i++], _ => i < names.length - 1? rollNext() : after())
rollNext()
}
const bundleCode = after => {
rollupMods(_ => {
let mods = concat(getNames().map(modName => {
let mod = rolls[modName]
return {
source: path.join(modsPath, modName),
code: mod.code,
map: mod.map
}
}), {
delimiter: "\n",
process: wrap
})
mods.prepend("(function(){\n")
mods.add("\n})();")
let result = mods.toStringWithSourceMap({
file: path.basename('.')
})
bundles.code = result.code + "\n" + convert.fromObject(result.map).toComment()
after(bundles.code)
})
}
exports.bundleCode = bundleCode

NodeJs require error

I have a nodejs package and i have a linkedList code. I want to include my LinkedList code in my NodeJs js folder but I can't do it. What is the my fault ?
I want to use it like this
This is my code in my NodeJs folder.(app.js)
var KullaniciJS=require('KullaniciLibrary.js');
This is my required folder codes.(KullaniciLibrary.js)
function Kullanici(KullaniciAdi)
{
this.KullaniciAdi=KullaniciAdi;
this.Sonraki=null;
}
function KullaniciListe()
{
this.Bas=null;
this.Uzunluk=0;
}
KullaniciListe.prototype.Ekle=function(EklenecekKullaniciAdi)
{
var Bas=this.Bas;
if (!Bas) {
this.Bas = EklenecekKullaniciAdi;
this.Uzunluk++;
return EklenecekKullaniciAdi;
}
while (Bas.Sonraki!==null) {
Bas = Bas.Sonraki;
}
Bas.Sonraki = EklenecekKullaniciAdi;
this.Uzunluk++;
return EklenecekKullaniciAdi;
};
First you have to declare inside of your KullaniciLibrary.js file, what you want to export. you do this by adding following line at the end of the file:
module.exports = YOUREXPORT;
YOUREXPORT will probably just be the methodname (or some object).
After that, you wanna import it like this:
var KullaniciJS = require('./KullaniciLibrary');
Note that you have to prefix the name with ./ and you don't need to define the file-ending.
If you don't prefix the module with ./, node will search for the module in the node_modules folder, instead of the current directory
In nodejs to require a function from another file you have to export then function.
To export the function use:
module.export='your function name';
and to require the function use:
const variable=require(./filename)
for more understanding use this link:
https://nodejs.org/api/modules.html

In Webpack, how to use custom source template to construct specific module

I know some inner functionality inside Webpack. Something about dependencies, template, and module building. However, there is little comment inside its source and no full document site for now. So, i can't chain them all to deal with my problem.
With my current requirement, i need to render specific module with custom source template (similar to this MultiModule in webpack).
Note: To be clear, the generated module's dependency array is not static. For example, one time it may be ['./a', './b', './c'], another time it may be ['./b', './c','./d']. That is up to some dynamic config before build.
For more detail example, i need a module call main.js. In build time, it need to be dynamically generated with target dependencies like(for being not sure which modules would be dependencies):
// main.js
var a = require('./a')
var b = require('./b')
var c = require('./c')
var d = require('./d')
...
In fact, if i only need to dynamically require them all, i can just construct an entry point dynamically.
// webpack.config.js
{
entry: {
main: [
'./a',
'./b',
'./c',
...
]
},
}
and it(webpack) will generate a module may like this:
__webpack_require__(1);
__webpack_require__(2);
__webpack_require__(3);
return __webpack_require__(4);
But i need to do something more:
var a = __webpack_require__(1);
var b = __webpack_require__(2);
var c = __webpack_require__(3);
var d = __webpack_require__(4);
...
// do something with a,b,c,d... under my custom need
...
return somthing or nothing;
As you guys who know about webpack, it's very very complicated and hard to understand and track its plugin(event) hierarchy.
Need some expertise! :)
I'm sorry foy my unclear question before.
However, there is some kind of weird atmosphere. I set up a bounty for attention and guidance. Someone's free-minded answer drove me to make comment with impoliteness somehow. And then some peacemaker shows up with comments unrelated to the question or answer. That sucks.
Focusing on that thing just makes things worse and nothing helped. Not letting it go just means someone has petty mind.
Either lacking attention and lacking expert or not, I have to fight it myself. Fortunately, digging into webpack makes some progress.
Prerequisite
The day before popular webpack, there are fashions like grunt and gulp to construct a custom build flow (with their plugins). They can achieve most of custom requirement, especially generating a custom module(which webpack doesn't have obvious and direct way to deal with).
when you come to do something like automatic collecting custom dependencies, then generating a custom module is the next essential step. It can be commonly seen in product line/family design.
Solutions
#1
This is the simplest and direct way but lack of flexibility.
The source method of MultiModule is to generate the entry module with multi-dependencies. Just overriding it will hit the target.
// hack.js
const MultiModule = require('webpack/lib/MultiModule')
MultiModule.prototype.source = function(dependencyTemplates, outputOptions) {
var str = ['"hello world";\n'];
this.dependencies.forEach(function (dep, idx) {
if (dep.module) {
if (idx === this.dependencies.length - 1)
str.push("module.exports = ");
str.push("__webpack_require__(");
if (outputOptions.pathinfo)
str.push("/*! " + dep.request + " */");
str.push("" + JSON.stringify(dep.module.id));
str.push(")");
} else {
str.push("(function webpackMissingModule() { throw new Error(");
str.push(JSON.stringify("Cannot find module \"" + dep.request + "\""));
str.push("); }())");
}
str.push(";\n");
}, this);
return new RawSource(str.join(""));
}
At the fifth line, i add a string statement "hello world;"\n, nothing else changed.
module.exports = {
entry: {
main: ["./a", "./b"],
}
// something else
}
the output main.js may look like:
//...
/* 0 */
/*!******************!*\
!*** multi main ***!
\******************/
/***/ function(module, exports, __webpack_require__) {
"hello world";
__webpack_require__(/*! ./a */1);
module.exports = __webpack_require__(/*! ./b */2);
/***/ }
//...
Now we can do what we want with the source method, with the compatibility in mind.
#2
This way is much more flexible but also complex.
It requires at lease 5 files(sources are too long, I made them into snippets):
CustomMultiModule.js:
// CustomMultiModule.js
const MultiModule = require('webpack/lib/MultiModule')
const RawSource = require('webpack/lib/RawSource')
class CustomMultiModule extends MultiModule {
constructor(...args) {
super(...args)
}
source(dependencyTemplates, outputOptions) {
var str = ['"hello world";'];
this.dependencies.forEach(function(dep, idx) {
if (dep.module) {
if (idx === this.dependencies.length - 1)
str.push("module.exports = ");
str.push("__webpack_require__(");
if (outputOptions.pathinfo)
str.push("/*! " + dep.request + " */");
str.push("" + JSON.stringify(dep.module.id));
str.push(")");
} else {
str.push("(function webpackMissingModule() { throw new Error(");
str.push(JSON.stringify("Cannot find module \"" + dep.request + "\""));
str.push("); }())");
}
str.push(";\n");
}, this);
return new RawSource(str.join(""));
}
}
module.exports = CustomMultiModule
CustomMultiModuleFactory.js:
// CustomMultiModuleFactory.js
const MultiModuleFactory = require('webpack/lib/MultiModuleFactory')
const CustomMultiModule = require('./CustomMultiModule')
class CustomMultiModuleFactory extends MultiModuleFactory {
constructor() {
super()
}
create(context, dependency, callback) {
callback(null, new CustomMultiModule(context, dependency.dependencies, dependency.name));
};
}
module.exports = CustomMultiModuleFactory
CustomMultiEntryPlugin.js:
// CustomMultiEntryPlugin.js
const MultiEntryPlugin = require('webpack/lib/MultiEntryPlugin')
const MultiEntryDependency = require('webpack/lib/dependencies/MultiEntryDependency')
const CustomMultiModuleFactory = require('./CustomMultiModuleFactory')
class CustomMultiEntryPlugin extends MultiEntryPlugin {
constructor(context, entries, name) {
super(context, entries, name)
}
apply(compiler) {
compiler.plugin('after-plugins', function(compiler) {
compiler.plugin("compilation", function(compilation, params) {
var multiModuleFactory = new CustomMultiModuleFactory();
compilation.dependencyFactories.set(MultiEntryDependency, multiModuleFactory);
})
})
}
}
module.exports = CustomMultiEntryPlugin
CustomEntryOptionPlugin.js:
// CustomEntryOptionPlugin.js
const CustomMultiEntryPlugin = require('./CustomMultiEntryPlugin')
class CustomEntryOptionPlugin {
constructor() {}
apply(compiler) {
compiler.plugin("entry-option", function(context, entry) {
if (typeof entry === "object") {
Object.keys(entry).forEach(function(name) {
if (Array.isArray(entry[name])) {
compiler.apply(new CustomMultiEntryPlugin(context, entry[name], name));
}
});
}
});
}
}
module.exports = CustomEntryOptionPlugin
webpack.config.js:
// webpack.config.js
const CustomEntryOptionPlugin = require('./CustomEntryOptionPlugin')
module.exports = {
entry: {
main: ["./a", "/b"] // this dependencies array may be generated
...
},
output: {
path: path.join(__dirname, "js"),
pathinfo: true,
filename: "[name].[chunkhash].js",
chunkFilename: "[chunkhash].js"
}
plugins: [
new CustomEntryOptionPlugin(),
...
]
...
};
With the code above, we can achieve the same as #1. And we can gain more control over the target entry or other requirements, if we want.
Often in webpack you're only requiring one file, and maybe different libs that the files depend on. If you require main, then webpack is going to resolve the dependencies based on the CommonJS syntax which you can read about here. Does removing the extra requirements in your webpack.config.js file solve this? e.g. having only the following as the config:
// webpack.config.js
{
entry: [ "./main" ],
...
}
It sounds like you don't really understand how webpack works-- the idea of it is to emulate how Node's CommonJS syntax allows your javascript to be modular and placed in separate files, while also being performant and not requiring tons of AJAX requests by your browser. If you want to read more about Webpack's config file, check out this page.
As a side note, returning at the end of the module does absolutely nothing. If you want to export, you can use module.exports, but having a line like return true or something at the end of your main.js file doesn't get caught anywhere meaningful.

Node.js, require all modules in folder and use loaded module directly

In MyModule folder, I have this two JS files.
SayHello.js
module.exports.SayHello = function() {
return('Hello !');
}
SayByeBye.js
module.exports.SayByeBye = function() {
return('Bye Bye!');
}
In Node.js, I want to require all files in MyModule folder and call function SayHello & SayByeBye directly something like:
require(./MyModule)
console.log(SayHello());
console.log(SayByeBye());
EDIT:
With answer of #Yanick Rochon,I do this :
> ./app/my-module/index.js
global.SayHello = require('./my-module/SayHello').SayHello;
global.SayByeBye = require('./my-module/SayByeBye').SayByeBye;
> ./app/my-module/say-hello.js
module.exports.SayHello = function() {
return('Hello !');
};
> ./app/my-module/say-byebye.js
module.exports.SayByeBye = function() {
return('Bye Bye !');
};
> ./app/main.js
require('./my-module');
console.log(SayHello());
console.log(SayByeBye());
There's a section about global objects in the node documentation.
However, globals should be used with care. By adding modules to the global space I reduce testability and encapsulation. But in this case, I think using this method is acceptable.
First thing first...
I believe you are mistaking Node.js with PHP or .Net, in the sense that you don't "import" into the current module what is exported in other modules. Not unless you manually do it anyway. For example, when you call
require('./my-module');
(Note that I renamed your MyModule into Node.js naming convention.)
You don't load things into the current context; you just load the script and don't assign it to anything. To access what my-module exposes, you need to assign it, or use it directly. For example :
require('./my-module').someFunction();
or
var myModule = require('./my-module');
myModule.someFunction();
Modules are not namespaces, but JavaScript objects that exposes public properties outside of their own contexts (i.e. using module.exports = ...)
Answer
You have two most popular ways to accomplish this :
Solution 1
Create an index.json file inside your folder where you want to load all of your scripts. The returned JSON object should be all the modules to load automatically :
> ./app/index.json
[
"say-hello.js",
"say-goodbye.js"
]
You should also consider having all your files API compatible :
> ./app/say-hello.js
module.exports = function sayHello() {
return 'Hello !';
};
> ./app/say-goodbye.js
module.exports.sayGoodbye = function () {
return 'Goodbye !';
};
Then load and execute everything like this :
var path = require('path');
var basePath = './app/';
var files = require(basePath);
var mods = files.forEach(function (loaded, file) {
var mod = require(path.join(basePath, file));
// mod is a function with a name, so use it!
if (mod instanceof Function) {
loaded[mod.name] = mod;
} else {
Object.keys(mod).forEach(function (property) {
loaded[property] = mod.property;
});
}
}, {});
mods.sayHello();
mods.sayGoodbye();
Solution 2
Read all .js files inside your folder and import them. I highly recommend you use glob for this.
var glob = require("glob")
var path = require('path');
var basePath = './app/';
var mods = glob.sync(path.join(basePath, '*.js')).reduce(function (loaded, file) {
var mod = require(file);
// mod is a function with a name, so use it!
if (mod instanceof Function) {
loaded[mod.name] = mod;
} else {
Object.keys(mod).forEach(function (property) {
loaded[property] = mod.property;
});
}
return loaded;
}, {});
mods.sayHello();
mods.sayGoodbye();
Note on the difference between module.exports and exports
Typically module.exports === exports, but it is recommended to use module.exports for the following reason
exports = function Foo() { } // will not do anything
module.exports = function Foo() { } // but this will do what you expect
// however these two lines produce the same result
exports.foo = 'Bar';
module.exports.foo = 'Bar';
For this reason, module.exports is recommended in all cases.
It's not perfect, but something like this should help you accomplish this:
var fs = require('fs');
var path = require('path');
var files = fs.readdirSync(__dirname);
var ownFilename = __filename.substr(__filename.lastIndexOf(path.delimiter) + 1);
var modules = {};
for (var i = 0; i < files.length; i++) {
var filename = files[i];
if (filename.substr(-3) === '.js' && filename !== ownFilename) {
modules[filename.slice(0, -3)] = require('./' + filename);
}
}
console.log(modules.SayByeBye());
console.log(modules.SayHello());

Categories

Resources