RequireJS - Cannot Access External Module Function - javascript

I'm having an issue with RequireJS. Essentially, I'm not able to access a function defined inside another file from another one.
I need to do that because I want to export a given subset of functions like
define('submodule', [], function() {
let myFunction1 = function(){ return "Hello"; }
let myFunction2 = function(){ return " From"; }
let myFunction3 = function(){ return " Submodule!"; }
return {
myFunction1 : myFunction1,
myFunction2 : myFunction2,
myFunction3 : myFunction3,
};
});
And accessing them from another file
define('main', ['config', 'sub1', 'sub2', 'submodule'],
function(config, sub1, sub2, submodule) {
//Config
alert(config.conf);
//Submodule
let callSubmodule = function() {
alert(submodule.myFunction1() +
submodule.myFunction2() +
submodule.myFunction3());
}
//sub1
let callSub1 = function() {
alert(sub1.myFunction1());
}
//sub2
let callSub2 = function() {
alert(sub2.myFunction1());
}
});
The fact is that usually I'm able to do this with sub1 and
sub2, but, with submodule, I simply can't. I think it's somehow caused by the dependencies in require.config.js.
My require.config.js:
require(['common'], function () { //contains vendors
require(['config'], function () { //contains a js config file
require(['main'], function () { //main file
require(['sub1', 'sub2'], function () { //some subfiles
require(['submodule']);
});
});
});
});
For submodule.myFunction1() and othe two related functions I'm getting:
Uncaught (in promise) TypeError: Cannot read property 'myFunction1' of undefined
This is weird since I'm able to do that in other situations and I really can't understand why this is happening. For instance, I'm able to call sub1 and sub2 functions from main and other files but not submodule in particular.
Index.html
//Taken from Plunker
. . .
<script data-main="common" data-require="require.js#2.1.20" data-semver="2.1.20" src="http://requirejs.org/docs/release/2.1.20/minified/require.js"></script>
<script src="require.config.js"></script>
. . .
<button onclick = "callSubmodule()">Call Submodule</button>
<button onclick = "callSub1()">Call Sub1</button>
<button onclick = "callSub2()">Call Sub2</button>
common.js contains vendors, here's just an example
requirejs.config({
baseUrl : "",
paths : {
"jquery" : "http://code.jquery.com/jquery-latest.min.js"
}
});
sub1.js
define('sub1', ['submodule'], function(submodule) {
let myFunction1 = function(){ return "called sub1"; }
return {
myFunction1 : myFunction1
};
});
sub2.js
define('sub2', ['submodule'], function(submodule) {
let myFunction1 = function(){ return "called sub2"; }
return {
myFunction1 : myFunction1
};
});
I set up a Plunker with #SergGr help that tries to replicate application's structure but all the modules get undefined on click. On the real application this does not happen.
How can I solve this?

This is your code:
define('main', ['submodule'], function(submod) {
console.log(submodule.myFunction());
});
You have submod in the parameter list. But you then try to access submodule. Note that you return the function straight from your module (return myFunction), so your module has the value of the function myFunction and thus the module is what you should call. The code should be:
define('main', ['submodule'], function(submod) {
console.log(submod());
});

I Managed to solve this issue. Essentially, it was caused by a circular-dependency between the modules. So, a needed b and b needed a leading to one of them being undefined on the dependency resolution.
I found a solution to that on the answer provided by #jgillich at requirejs module is undefined.
So, I managed to solve using, in main
define('main', ['config', 'sub1', 'sub2', 'require'],
function(config, sub1, sub2, submodule, require) {
//Config
alert(config.conf);
//Submodule
let callSubmodule = function() {
alert(require('submodule').myFunction1() +
require('submodule').myFunction2() +
require('submodule').myFunction3());
}
});
As #jgillich said:
If you define a circular dependency ("a" needs "b" and "b" needs "a"), then in this case when "b"'s module function is called, it will get an undefined value for "a". "b" can fetch "a" later after modules have been defined by using the require() method (be sure to specify require as a dependency so the right context is used to look up "a"):
//Inside b.js:
define(["require", "a"],
function(require, a) {
//"a" in this case will be null if "a" also asked for "b",
//a circular dependency.
return function(title) {
return require("a").doSomething();
}
}
);
http://requirejs.org/docs/api.html#circular

The way you've named your modules I would expect they all came from a require config file. I would not expect that requirejs would know how to load those files without some sort of explicit compilation process. I also suspect that your server is returning something due to a 404 that JS is almost able to interpret without exploding.
Your setup seems and naming scheme seems quite strange. If you have the ability to start from scratch below are my recommendations.
Recommendations:
I'm noticing that you're using absolute paths. I highly recommend using relative paths for everything. There are many reasons for this.
Your data-main should be what you call "require.config.js". Your common.js is actually a require.config.js.
You load require.config.js (which is your main) separately using a script tag. You can do this but it's strange.
You can use the "commonjs" style syntax to require files without needing to use the array to define all your dependencies. I recommend that.
This is my recommendation for a set-up:
index.html
<script src="/js/config.js" />
<script src="http://requirejs.org/docs/release/2.1.20/minified/require.js" />
<script>
require('/js/main', function(main) {
main({});
});
</script>
/js/config.js
// setting requirejs to an object before its loaded will cause requirejs to use it as the config
window.requirejs = {
baseUrl : "/",
paths : {
"jquery" : "http://code.jquery.com/jquery-latest.min.js"
}
};
/js/main.js
define(function(require) {
const sum = require('./sum');
return (a, b) => sum(a, b);
});
/js/sum.js
define(function(require) {
return (a, b) => a + b;
});

Update (March 02, 2017)
Your plunker obviously will not work because you have direct calls from HTML to your module functions.
<button onclick = "callSubmodule()">Call Submodule</button>
<button onclick = "callSub1()">Call Sub1</button>
<button onclick = "callSub2()">Call Sub2</button>
RequireJS doesn't work that way. One of key purposes of RequireJS is to provide modules isolation and thus it just can't work that way: imagine if several different modules had functions callSubmodule.
To the best of my knowledge there is no way to bind calls from HTML back to the code in a RequireJS module, it should be other way around: module binds to HTML. And if you fix those issues, everything works fine for me as you can see at this fork of your plunker.
Old Answer
The bug is in your subModule.js
define('submodule', [], function() {
let myFunction = function(){ return "Hello"; }
//return myFunction; // old, wrong
return { myFunction: myFunction };
});
Even if you want to return just 1 function you should not return it as is, you should wrap it into an object and give it an explicit name.
P.S. if this is not your real issuse, please provide us real Minimal, Complete, and Verifiable example

Related

Accessing an Immediately Invoked Function Expression variable in Node.js in another file using require

File 1 - Monitor.js
var MONITOR = (function () {
// File Content
return {
doThing: function() {
doThing();
}
};
})();
File 2 - Test.js
var monitor = require('../public/js/monitor.js');
I want to access doThing() in File 2. I have tried various syntax and no luck so far.
From the frontend HTML I can simply include Monitor.js in a script tag, and call MONITOR.doThing(); without trouble but in Test.js this is proving difficult.
Any advice on how?
You have to export MONITOR so that someone else can access it with require().
Add this:
module.exports = MONITOR;
at the bottom of Monitor.js.
And, if you want the monitor.doThing() method to return some value, then you have to add a return statement to the function as in:
var MONITOR = (function () {
// File Content
return {
doThing: function() {
return "hello";
}
};
})();

How to get js function into webWorker via importScripts

I have a worker.js file:
self.importScripts('/static/utils/utils.js')
onmessage = (e) => {
let a = e.data[0]
let b = e.data[1]
let c = func1(a,b)
postMessage(c)
}
The utils.js file looks something like this:
module.exports = {
func1: function(a,b){
return a+b
}
I keep getting error:
Uncaught ReferenceError: module is not defined
at utils.js:1
Obviously require, and import and any other server side imports aren't working but I'm not sure why it's having a problem with my importScripts - https://developer.mozilla.org/en-US/docs/Web/API/WorkerGlobalScope/importScripts
The correct solution is to pack your worker with webpack. If you don't want to do that, read below.
I usually write myself a polyfill for node require:
// This will not work in normal UI thread
// None of this should make it into production
function require(moduleName) {
self.module = { exports: null };
// Nasty sttuff right here, probably should throw error instead
if (moduleName == "fs")
return null;
// This part is especially unprofessional
if (!moduleName.endsWith(".js"))
moduleName += ".js";
importScripts(moduleName);
return self.module.exports;
}
This makes use of the fact that importScripts is synchronous. Note that this will still cause errors if you try to load native node modules (eg. fs) or if other module properties are used.
Try this utils.js:
(function () {
self.func1 = function (a, b) {
return a + b
}
}());
Try to do this:
//inside worker.js
self.addEventListener("message",(event)=>{
importScripts("module.js")
utils.print1()
utils.print2()
})
//inside module.js
//setting a variable in global scope, allows worker.js to use it.
var utils = {
print1(){
console.log("This is a content from a module.")
},
print2(){
console.log("This is a another content from a module.")
}
}

Writing multiple functions in AMD javascript module

I am quite new to writing javascript code using AMD. I am stuck at figuring out how to write multiple functions in a file:
define(function(){
return {
and: function(a,b){
return (a&&b);
}
};
}
);
I tried writing another function plus in the following way:
define(function(){
return {
plus: function(a,b){
return (a+b);
}
};
}
);
But when I use grunt for testing, it is not able to detect the function plus
You should place each module in it's own file. At least requireJS (are you using that?) determines the module name by it's file name (without the .js).
So a file sitting in /modules/A.js will have the module name "modules/A".
If you really want to define multiple modules in one file, you can do it in a more explicit way like this:
define("A", [], function () { return ...whatever... });
define("B", [], function () { return ...whatever... });
Edit:
for defining one module with two functions you can use different patterns. For a singleton (i.e. no "Class") I usually do something like this:
define(function () {
var myModule = {
fn1: function () { .... },
fn2: function () { .... }
};
return myModule;
});

AngularJS lazy module definition

In my project I divided angular services in different files, each file/service should belongs to a common module named 'com.mysite.services', for example:
ServiceA.js
ServiceB.js
ServiceC.js
...and so on
however by defining them in this way:
angular.module('com.mysite.services', []).
service('ServiceA', function()
{
});
I overwrite the module for each file. In order to solve the problem I defined a wrapper function which will create the module if not defined and return instead a reference to it if defined:
function angular_module(name, deps)
{
var m;
try
{
m = angular.module(name);
}
catch (e)
{
m = angular.module(name, deps || []);
}
return m;
};
So, I can simple replace the "." with "_" in the declaration:
angular_module('com.mysite.services', []).
service('ServiceA', function()
{
});
This solved my problem, but my question is: is there a way to avoid my wrapper in favor of an Angular-ish solution? (it seems so dumb :P)
Not sure this is what you will need but you can do something like that
In a dedicated file create this :
// Bootstrap.js
angular.module('com.mysite.services', ['com.mysite.services.ServiceA', 'com.mysite.services.ServiceB', ....]);
And now for every service you can do something like
// ServiceA.js
angular.module('com.mysite.services.ServiceA', []).
service('ServiceA', function(){});
//ServiceB.js
angular.module('com.mysite.services.ServiceB', []).
service('ServiceB', function(){});
You can now depend on 'com.mysite.services' in your app and all your services will be made accessible.
You can create an App.js
var myModule = angular.module('com.mysite.services', []);
And in ServiceA.js :
myModule.service('ServiceA', function()
{
});

Why is the Simplified CommonJS Wrapper syntax not working on my Dojo AMD module?

Im starting to sort of wrap my head around requirejs and the new Dojo AMD structure, but I have a problem with some early tests:
cg/signup.js:
define(['dojo/_base/fx', 'dojo/dom'], function(fx, dom){
return function(){
this.hidePreloader = function(id){
var preloader = dom.byId(id);
fx.fadeOut({node : preloader}).play()
}
}
})
This works fine. In the master cg.js file:
require(['dojo/_base/kernel', 'dojo/_base/loader'])
dojo.registerModulePath('cg', '../cg')
require(['cg/signup', 'dojo/domReady!'], function(Signup){
var sp = new Signup();
sp.hidePreloader('preloader')
})
Bam. Done. However, in using the Simplified CommonJS Wrapper structure:
define(function(require){
var fx = require('dojo/_base/fx'),
dom = require('dojo/dom');
return function(){
this.hidePreloader = function(id){
var preloader = dom.byId(id);
fx.fadeOut({node : preloader}).play()
}
}
})
I get an undefinedModule error. It seems to come from the dojo/_base/fx line, but I don't know why.
UPDATE
For clarification.
index.html scripts
<script type="text/javascript" src="js/dojo/dojo.js.uncompressed.js" data-dojo-config="isDebug:true,async:true"></script>
<script type="text/javascript" src="js/cg.js"></script>
cg.js
require(['dojo/_base/kernel', 'dojo/_base/loader'])
dojo.registerModulePath('cg', '../cg')
require(['cg/signup', 'dojo/domReady!'], function(signup){
signup.testFunc()
})
js/cg/signup.js
define(['require', 'exports'], function(require, exports){
var dom = require('dojo/_base/kernel');
// Any other require() declarations (with very very few exceptions like 'dojo/_base/array throw undefinedModule errors!!!
// without any error causing requires, this works fine.
exports.testFunc = function(){
alert("hello")
}
})
dojo completely supports the Simplified CommonJS Wrapper format. however, there is a precondition... you must have no dependencies array.
define(function (require, exports, module) {
var fx = require('dojo/_base/fx'),
dom = require('dojo/dom');
// continue...
});
this will NOT work the same
define(['require', 'exports', 'module'], function (require, exports, module) {
var fx = require('dojo/_base/fx'),
dom = require('dojo/dom');
// continue...
});
nor will this...
// in this case require, exports and module will not even exist
define([], function (require, exports, module) {
var fx = require('dojo/_base/fx'),
dom = require('dojo/dom');
// continue...
});
Here is a little wrapper around Dojo define that uses code taken from RequireJS to calculate the dependencies based on the toString of the definition function. It wraps the current "define" in the global namespace, calculates the dependencies and then call's the wrapped define.
defineWrapper.js:
// Workaround for the fact that Dojo AMD does not support the Simplified CommonJS Wrapper module definition
(function() {
var commentRegExp = /(\/\*([\s\S]*?)\*\/|([^:]|^)\/\/(.*)$)/mg,
cjsRequireRegExp = /require\(\s*["']([^'"\s]+)["']\s*\)/g,
ostring = Object.prototype.toString;
function isArray(it) {
return ostring.call(it) === '[object Array]';
}
function isFunction(it) {
return ostring.call(it) === '[object Function]';
}
var oldDefine = define;
define = function(name, deps, callback) {
//Allow for anonymous functions
if (typeof name !== 'string') {
//Adjust args appropriately
callback = deps;
deps = name;
name = null;
}
//This module may not have dependencies
if (!isArray(deps)) {
callback = deps;
deps = [];
}
//If no name, and callback is a function, then figure out if it a
//CommonJS thing with dependencies.
if (!deps.length && isFunction(callback)) {
//Remove comments from the callback string,
//look for require calls, and pull them into the dependencies,
//but only if there are function args.
if (callback.length) {
callback
.toString()
.replace(commentRegExp, '')
.replace(cjsRequireRegExp, function(match, dep) {
deps.push(dep);
});
//May be a CommonJS thing even without require calls, but still
//could use exports, and module. Avoid doing exports and module
//work though if it just needs require.
//REQUIRES the function to expect the CommonJS variables in the
//order listed below.
deps = (callback.length === 1 ? ['require'] :
['require', 'exports', 'module']).concat(deps);
}
}
if(name === null) {
return oldDefine(deps, callback);
} else {
return oldDefine(name, deps, callback);
}
}
})();
How would you use it?
<script src="...dojo..."></script>
<script src="defineWrapper.js"></script>
<script>require(["some_simplified_commonjs_defined_module"], function(module) {
// use module here
});</script>
Note that Dojo does not support the simplified CommonJS style for dependency detection when doing a build. This means you'll either need to use the normal dependency list style, or you'll have to duplicate all your dependencies when defining layers in the build profile.
Here's the relevant bug in their tracker:
http://bugs.dojotoolkit.org/ticket/15350
is require defined? I don't see where that argument value would come from. I think you might have to do something like
define(["require"], function(require){ ...
I started to think that maybe I wasn't meant to learn Dojo. But, it all comes together with a little more reading. I'm not sure exactly what I did different or whatever, but here's the working layout.
index.html scripts and config
<script type="text/javascript">
dojoConfig = {
async : true,
isDebug : true,
debugAtAllCosts : true,
packages : [{
name : 'cg',
location : '/../js/cg'
}]
}
</script>
<script src="http://ajax.googleapis.com/ajax/libs/dojo/1.7.1/dojo/dojo.js"></script>
<script type="text/javascript" src="js/cg.js"></script>
js/cg.js
require(['cg/signup', 'dojo/ready'], function(signup){
signup.init('preloader')
})
js/cg/signup.js
define(['dojo', 'require'], function(dojo, require){
var fx = require('dojo/_base/fx')
return new function(){
this.init = function(id){
fx.fadeOut({node : dojo.byId(id)}).play()
}
}
})
Again, not entirely sure why the var fx = require(...) statement works differently in this one than the others, could be the build I downloaded vs. the CDN, who cares. It works. Some links I used to help for others possibly in the same boat:
Writing Modular JS
AMD vs CommonJS Wrapper
Dojo Toolkit AMD
Dojo Config (1.7)

Categories

Resources