RequireJS shim for script containing only a callback - javascript

I have an external API which provides a script file with javascript callback function in it. It assumes the function is implemented in my code.
eg a JS file with the following content:
aCallback({json:'stuff'});
I would like to wrap this in a requireJS module but am not too sure how to go about it.
I have tried the following shim:
define("my-wrapper", [], function () {
return function(data){ console.log(data); }
}
);
var require = {
shim: {
"my-wrapper": {exports: "aCallback"},
"http://api.con/service": ["my-wrapper"]
}
};
require(["http://api.con/service"], function (service) {});
but it says when it try's to load the service that aCallback is undefined. What have I got wrong? Is there a better way to wrap this kind of script?

You might want to try requiring the callback as a dependency instead of using shim so that it does exist in the same scope.
require(["http://api.con/service", "my-wrapper"], function (service, aCallback) {
});
It does depend on how the service expects to consume the callback though.

Related

Trouble understanding the requireJS require() function

I'm new to Javascript and I'm having troubles understanding the following piece of code. I have read this post (https://stackoverflow.com/a/60669635/9867856) which suggests that mifosXComponents.js and mifosXStyles.js are being passed as arguments into the function function(componentsInit){...}, but isn't componentsInit a single function that returns a promise? How come two .js files are converted into a function? I'm confused.
require(['mifosXComponents.js', 'mifosXStyles.js'], function (componentsInit) {
componentsInit().then(function(){
require(['test/testInitializer'], function (testMode) {
if (!testMode) {
angular.bootstrap(document, ['MifosX_Application']);
}
});
});
});
If you require two modules (as per example) then RequireJS will:
load them async;
load their dependencies;
inject the modules to you callback, each as separate argument.
So you have a mistake in your code, your callback will receive actually two arguments, so you need to have two parameters:
// require two modules async,
// when they are loaded,
// they are injected to your callback
require(['mifosXComponents.js', 'mifosXStyles.js'], function (mifosXComponents, mifosXStyles) {
// now you can use both modules,
// seems that first one is a function which returns promise,
// but I have no idea what is the second one :)
mifosXComponents().then(function(){
require(['test/testInitializer'], function (testMode) {
if (!testMode) {
angular.bootstrap(document, ['MifosX_Application']);
}
});
});
});

convert a javascript library to AMD

I'm trying to use a library -- Google's libphonenumber -- in my require application that is not AMD. What is the best way to consume this? I know I can create a module like this:
define(['module'], function (module) {
// insert and return library code here.
});
But that doesn't seem great. It seems like I would have to refactor some of their code to get that working (e.g., turn it all into an object and return that object). I see a lot of libraries using a different pattern where they use an immediately invoked function that defines the module on the window object and returns it.
(function() {
var phoneformat = {};
window.phoneformat = phoneformat;
if (typeof window.define === "function" && window.define.amd) {
window.define("phoneformat", [], function() {
return window.phoneformat;
});
}
})();
** UPDATE **
Is there any reason not to just do this?
define(['lib/phoneformatter'], function(phoneformatter) {
});
I get access to all of my methods but now it seems they are global because I did not wrap the library in a define...
Use RequireJS's shim. It'll look something like this
requirejs.config({
shim: {
'libphonenumber': {
exports: 'libphonenumber' // Might not apply for this library
}
}
});
This will load libphonenumber and put its variables in the global scope
This ended up working for me:
define(['module'], function (module) {
// insert and return library code here.
});
I am not entirely sure why 'module' was necessary. But it doesn't work without it. Also, I just returned an object and attached functions to it like so:
return {
countryForE164Number: countryForE164Number,
nextFunction: nextFunction,
// more functions as needed.
}
There is not much in the way of documentation for using 'module' but from what I can ascertain: Module is a special dependency that is processed by requireJS core. It gives you information about the module ID and location of the current module. So it is entirely possible that I messed up the paths in config.

Can I add a method to a requirejs module used as dependency in another module and have it available every time the module is loaded as dependency?

If I have a module like this:
define([
'app'
, 'text!index.html!strip'
, 'css!index'
],
function (App, source) {
var response = {};
App.newMethod = function (foo) {
console.log("foo ="+foo);
};
// return response object
return response;
}
);
I'm wondering how to add methods to a module that is used as a dependency in another module. Sure I can add methods to the object, but will these also update the App object when it is called from another module?
Question:
Is there a way to add methods to a module, which is loaded as a dependency and have these methods available on all modules, which require this dependency?
Short answer:
Yes. The module needs to be an object/instance (not a class) and it will work with requirejs.
Long answer:
When you require a module as a dependence for the first time Requirejs generates an object, and for the next times you requires the module Requirejs will return the object it generated the first time. So all the times you require a module you get always the same reference of the object.
With
define([], function () {
var app = {
//my methods.
};
return app;
});
and
define(['app'], function (app) {
app.newMethod = function (){
// ...
};
});
you can use app like this:
define(['app'], function (app) {
app.newMethod();
});
But injecting methods from one object to an other is a really bad practice. If you need something from an object just add it when creating the object, not by injection.
define([], function () {
var app = {
newMethod: function () {
// ...
},
// my methods.
};
return app;
});
For example if object A injects a new method that will be used in object B, but B is called when A is not loaded then there would be an error Object #<Object> has no method 'newMethod'

RequireJS load string

In my app there are dynamic parts that are loaded from database as string that looks like:
"define(['dependency1', 'dependency2'], function(){"+
" // function body" +
"})"
which is just a simple requireJS module, as a string. I want to lazy load the script above using async require call. So, my main requireJS script looks like:
require(["jquery"], function($){
$(document).ready(function(){
// logic to load specific script from database
var scriptString = functionToLoadTheStringAbove();
// ideally i would like to call it like this
require([scriptString], function(){
// scriptString, dependency1, dependency2 are loaded
}
});
});
How do I load those string in requireJS? I know about text plugin, but it only allow loading from files. I tried eval but it doesn't resolve dependencies correctly.
This is quite late, but I just post my solution here in case anyone needs.
So I ended up asking in requireJS forum and examining the source of text! plugin and json! plugin. The cleanest way to load module from String in RequireJS is by making your own plugin to load the String, and then use onLoad.fromText() that will eval your String and resolve all dependencies.
Example of my plugin (let's call it db! plugin):
define([], function(){
var db = new Database(); // string is loaded from LocalStorage
return {
load: function(name, req, onLoad, reqConfig){
db.get(name, function(err, scriptString){
if (err) onLoad(err);
else onLoad.fromText(scriptString);
});
}
}
});
You can then use the plugin like:
require(["jquery", "db!myScript"], function($, myScript){
// jQuery, myScript and its dependencies are loaded from database
});
Note:
There's no way to require() from String without eval. This is what onLoad.fromText() does internally. Since eval is evil, you should only use it if you know what String you're going to eval(). If you're using it in browser extension, you might want to relax the CSP policy.
To name your String module, you can use explicit naming syntax. This way, your module will always have the same absolute name.
To answer the question a little more directly, create a plugin like so:
define("load-string",[], function(){
var strings=[],
re_package_name = /^string_module_(\d+)$/;
return {
normalize: function(name, _){
if(re_package_name.test(name)){
return name
}
var nml = "string_module_" + (strings.push(name)-1);
return nml;
},
load: function(name, _, onLoad, config){
if(re_package_name.test(name)){
onLoad.fromText(strings[name.match(re_package_name)[1]]);
}else{
onLoad.error("Invalid package name: ",name);
}
}
}
});
and use it like so:
var world_module = "define([],function(){return 'world!'})";
require(["load-string!" + world_module],
function(x){
console.log("Hello "+x);
})
You should be able to do :
require(["jquery"], function($){
$(document).ready(function(){
// logic to load specific script from database
var scriptString = functionToLoadTheStringAbove();
var olddefine = define; // require js define
var runme; // capture function
define = function (args,func){
runme = func;
}
eval(scriptString);
runme(); // run the function in current scope
define = olddefine; // restore requirejs function
// dependency1, dependency2 are loaded
});
});

Javascript - accessing namespace in different files

I can do this in node.js
var module = require('../path/module')
module.functionname()
So I thought I'd like to do that in client side Javascript to organize things slightly.
So each of my files now has a namespace. So say login.js has a namespace login.
My question is, what's the best way in ECMAScript 5 to implement something alongs these lines?
What you are trying to achieve can be done with AMDs (asynchronous module definitions). Check out RequireJS for that: http://requirejs.org/
With Require.js you can basically define a set of dependencies, let them get loaded asynchronously and execute code once all stuff was loaded nicely:
require(['dependency1.js', 'dependency2.js'], function(dep1, dep2) {
console.log(dep1.functionname())
})
The dependency will then declare it's functionalities with require's define method:
define(['a/possible/dependency.js'], function() {
return {
functionname: function() { return 1 }
}
})

Categories

Resources