In Requirejs, can I register the same path by different names? - javascript

I'm using RequireJS to manage an app that is implemented as an undetermined number of classes split across files.
The app has some some utility classes, and then some consumer classes which use the utility classes. Each consumer class uses RequireJS to load only the utility classes it needs, and is responsible for its own Require config.
Consumer classes aren't aware of each other, and the app as a whole doesn't know the needs of each consume class. It merely knows the consumer class exists, and loads it. The problem is, if two different consumer classes define the same path but with different names, the first one wins, and subsequent one times out.
For example, this is some utility.js
define( function(){
return function(msg){
console.log(msg);
};
});
This is consumer1.js
require.config({
paths: {
ut1: '/utility'
}
});
require(['ut1'], function(utility){
utility('hello from client1');
})
And this is consumer2.js
require.config({
paths: {
ut2: '/utility'
}
});
require(['ut2'], function(utility){
utility('hello from client2');
})
If used independently each consumer class works, but when called together, the second one returns an error "Load timeout for modules: ut2".
As part of the modular nature of the app design, consumer classes cannot know each other's content, so I cannot enforce naming rules, nor can I have a central app-level require.config. How can I stop one consumer from breaking another's require config?
I supposed I could write a global helper that managed names and paths, grouping common paths and returning the first path name only, but I'd prefer a simpler solution within Require itself.

You should use the map option:
map: {
consumer1: {
ut1: '/utility'
},
consumer2: {
ut2: '/utility'
}
}
And then you don't need a paths configuration for /utility. What this does is tell RequireJS that when consumer1 requires ut1, it should load the /utility module instead. When consumer2 requires ut2, RequireJS should load the /utility module instead.

Related

Wrong module loaded on webpack federation with angular

I have 3 apps on ports 4200, 4201 and 4202.
On my first app (on 4200) I have a route to other apps which loads their corresponding modules, a ProfileModule, and I'm creating components based on this module's exported components.
Note that my apps have the same module and exported component names.
This works perfectly but for some reason, when I change my route from an app to the other one, when components have already been loaded once, webpack retrieves the wrong module.
What I'm doing here is:
I'm routing to my second app (which is on 4201), it loads my ProfileModule from second-app
I'm routing to my third app (which is on 4202), it loads my ProfileModule from third-app
I'm going back to my second-app and it loads my ProfileModule from third-app instead of second-app
I guess it is due to the module names, but shouldn't it work if it's on a different remote?
Here is how I get my modules:
async function lookupExposedModule<T>(
remoteName: string,
exposedModule: string
): Promise<T> {
// Initializes the share scope. This fills it with known provided modules from this build and all remotes
await __webpack_init_sharing__("default");
const container = window[remoteName] as Container; // or get the container somewhere else
// Initialize the container, it may provide shared modules
await container.init(__webpack_share_scopes__.default);
const factory = await container.get(exposedModule);
const Module = factory();
return Module as T;
}
I found a solution here.
But in my case, I had the same names for different remotes in my webpack config.

react-i18next: All namespaces in one file + pass namespace in decorator

I was looking through all the i18next documentation, but still pretty confused as to how to do it. So far I replicated their example and I have the following.
Directory structure:
locales
->en
->ns1.json
->ns2.json
->fr
->ns1.json
->ns2.json
i18next configuration:
i18n
.use(XHR)
.init({
lng: 'en',
fallbackLng: 'en',
debug: false,
interpolation: {
escapeValue: false,
},
})
And I decorate my components like so:
#translate(['ns1'], { wait: true })
So I have directories for languages, and than one file per namespace. Each namespace is essentially translation of one view. So I have roughly a mapping from namespaces to React components.
What I want to do is put all those namespaces in 3 files, (because all my components are split into 3 sections of the app - admin, user, common). Each of those 3 files will have a bunch of namespaces. I want to still have one namespace per component, so I want to specify not just the file, but the namespace in the #translate decorator, so I don't have to specify it each time in my translate function.
Is that at all possible? If not, can I have all namespaces in one file instead of 3?
You can add more namespaces to the hoc - this asserts those get loaded on rendering (or wait for them when setting wait option)
#translate(['ns1', 'ns2'], { wait: true })
ns1 will be the default namespace in the t function passed to props:
t('key') -> will search key in ns1
access ns2:
t('ns2:key') -> will search key in ns2

How to share objects/methods between controllers without circular references?

Pretty straightforward question. Currently, what I do when I need to access objects' methods throughout most of the application, I do this in app.js
Ext.define('Utils', {
statics: {
myMethod: function() {
return 'myResult';
}
}
});
This works, but when I build the application, I get a warning about a circular reference (app.js of course needs all the other controller classes, but then said classes refer back to app.js).
I thought of using a package including a .js file that has all the objects/methods, but sometimes, within these methods I'll need access to the Ext namespace so that won't work.
Is there any better way to do this ?
Thanks!
You should not define the class Utils inside app.js. Each Ext.define statement should be in it's own file. Also the classname should be prefixed with your app name.
Ext.define('MyApp.Utils', {
statics: {
myMethod: function() {
return 'myResult';
}
}
});
should therefore be found in the file app/Utils.js. When compiling your sources into a compiled app.js, Sencha Cmd will take care of the proper ordering in the final file. The requires and uses directives give you enough flexibility to define any dependences between your classes.
Read all the docs about MVC to get a clear understanding.

Graphs - How to model dependent resources?

With out libraries, I'm trying to learn data structures.
I have these dependencies
jquery.js->jqueryui.js
(underscores.js, jquery.js) -> backbone.js
Bascially, jqueryui depends upon jquery. Bacbkone depends on both underscore and jquery. Jquery and underscore are not related.
I want to create a dependency tree have you to "shed light" on these relations.
I was told this is how it is done on this posted question. Particularly this comment.
As long as you don't have a circular dependency you can always build a
dependency forest, which consists only of directed trees and/or sole
nodes. On the trees you can simply use DFS. You then start by adding
all roots or single nodes into a queue and add other resources to the
queue when their dependency has been loaded. (note that if a resource
has several dependencies you cannot model your dependencies as a
forest, but it stays acyclic and you can use a similar approach). –
Zeta
... so I do have resources with multiple dependencies, so I can't use a dependency forest.
...further discussion has suggested a directed acyclic graph.
A directed acyclic graph. Every path from the starting point can be
done in parallel, however if a node has more than one incident edges
you have to wait for all dependencies being loaded. By the way, I
would represent example 3 as P:[U-underscore, U-jquery]
S:[U-underscore, U-backbone-js] S:[U-jquery, U-backbone.js], showing
the original dependency, but they are equivalent
Can I use a dependency tree? If not what data structure is suggested to model complex dependencies...and and finally how do I implement it?
I believe that I have solved this problem, albeit its a long time ago. Let the dependencies be described like this:
Module A
Module X
Module Y
Module B
Module X
Module A
Module C
Module A
Module B
Which means that Module A depends on Module X and Module Y - and so forth.
Iterate over the leaves in this forest and for each leaf with no dependencies (look that up at the base), put the leaf in the load queue and remove it from the forest, so first pass yields:
Module A
Module B
Module A
Module C
Module A
Module B
Queue: Module X, Module Y.
Second pass:
Module B
Module C
Module B
Queue: Module X, Module Y, Module A.
...and so forth. Modules found in the same pass can be loaded in parallel, so a way to represent this could be:
[[Module X, Module Y], [Module A], [Module B], [Module C]]
Which means that Module X and Module Y should be loaded first and that they can be loaded in parallel. The rest must be loaded sequentially.
My biggest concern with the approach above is that it has complexity O(n^2). It should be possible to improve. Detecting cycles can easily be done with a lookup map.
Considering your asking about modular code without a library but using libraries as the modules (jQuery, jQuery-ui, etc.), It seems as this question is actually two questions.
How can you make sense of the many external libraries you have (sans depending on linear loading with script tags)
How do you implement modular dependencies
To answer the first one, it is a bit complicated. Most modular dependency designed require some wrapping around the modules to keep track of them. Most JS libraries do not use such systems in the assumption that they will be loaded via script tags (linear loading). Some systems such as require.js will provide a modified version to be compatible while others attempt to inject script tags into the page in a predefined order. The more popular solutions are to use a build tool that will concatenate the different library file you have into one large file that will order them in the correct order.
Most libraries are nice and will contain their code inside to prevent clobbering other scripts that also load. Even jQuery offers a noConflict() method to prevent the $ syntax from clobbering what other libraries might expect (for example Zepto).
The answer to handling dependencies with external libraries depends on either modifying the libraries to comply with what ever modular system you have or to have a external system such as a build environment that will (for lack of a better term) compile them into the correct order.
That's the bad news. The good news is code you control can in fact use a dependency tree that works very well. require.js is one prime example of doing this. Although a system such as CommonJS or AMD can be very powerful you can implement a simple dependency API on your own.
Taking from Rye.js as the example of how to implement your own modular system for your code:
(function(global) {
var module_list = {};
global.require = function (module) {
return module_list[module];
};
global.define = function (module, fn) {
modules[module] = fn();
};
})(this);
Then you can define your own modules:
define("hello_world", function() {
function helloWorld() {
alert("Hello World!");
}
return {
sayHello: helloWorld
};
});
Then in another module that depends on that one:
define("greetings", function() {
var hello = require("hello_world");
function sayAll() {
hello.sayHello();
alert("Good-Bye!");
}
return {
sayAll: sayAll
};
});
The data structure I've shown you in my previous answer,
deps = {
"U-jqueryui": ["U-jquery"],
"group1": ["U-underscore", "U-jquery"],
"U-backbone.js": ["group1"]
}
is represents a DAG:
U-jquerui U-backbone.js
| |
| v
| group1
| / |
v L v
U-jquery U-underscore.js
From this, you can extract a dependency tree, like
root
| |
v v
U-jquery U-underscore.js
for group1. The collection of all possible trees is then called a forest.
so I do have resources with multiple dependencies, so I can't use a dependency forest.
No, you don't. Having resources with multiple dependencies only means you need a tree instead of a queue. Where it become no (multi-/poly-) tree any more is when you have a diamond shape in your DAG diagram, for example if you had a module U-myapp that relies on U-jquerui and U-backbone.js - it relies on U-jquery "twice".
However, I don't think we really need to use any algorithms for a whole graph.
If not what data structure is suggested to model complex dependencies
The one I've already shown you - just modeling direct dependencies. It allows you to represent a DAG (including polyforests) even if you don't need it yet.
and and finally how do I implement it?
I'd go with memoized promises (sorry, I like them). Every promise represents the fact that a module has been loaded and executed; and we memoize (cache) them by module name so we don't start them multiple times. The code then is rather simple:
var modulepromises = {};
function loadAndExecute(name) {
if (name in modulepromises) // memoized?
return modulepromises[name]; // we're on it already!
var dependencies = [];
if (name in deps)
dependencies = deps[name].map(loadAndExecute);
// all promises for direct dependencies (indirect deps are included) combined
// will be fulfilled already if empty array
var depsExecuted = Promise.when(dependencies);
if (name.slice(0, 2) == "U-") // if a group, don't load anything
var file = ajaxPromiseForModulesource(name);
return modulepromises[name] = /*memoize!*/ depsExecuted.then(function() {
if (file)
return file.then(function(code) {
execute(code); // eval?
return "module "+name+" executed";
});
return "group loaded";
});
}

require.js: how can I load a module that defines a name under a different name?

I'm trying to load underscore.js with require.js like this:
require(["libs/underscore-1.2.3.js"], function(_) {
...
});
But this doesn't work because underscore.js exports a module name: define('underscore', function() { ... }).
Without renaming lib/underscore-1.2.3.js, how can I load it with require.js?
Alright, after some more googling, I've found: https://github.com/documentcloud/underscore/pull/338#issuecomment-3245213
Where
#dvdotsenko all AMD loaders allow mapping a module ID to a partial path, usually the configuration is called 'paths', so to do what you want:
requirejs.config({
paths:
underscore: 'js/libs/underscore-1.2.3.min'
}
});
require(['underscore'], function () {});
Since underscore is used by other higher-level modules, like backbone, a common dependency name needs to be used to communicate a common dependency on underscore, and it makes sense to call that dependency 'underscore'. The paths config gives a way to do the mapping to a specific URL you want to use for that dependency.
This doesn't answer my question (ie, I still don't know how I'd go about loading underscore if all I had was a URL), but at least it's a functional workaround.
While this doesn't strike me as the most ideal solution, you can require your external files, and then require their registered module names in the inner block.
JSFiddle Example
require(
['require','http://documentcloud.github.com/underscore/underscore-min.js'],
function(require){
require(['underscore'],function(_){
var a = _.intersection([1,2,3],[2,3,4]);
document.write("Underscore is available in the closure : " + a);
})
}
)
It might not look pretty, but that might be a recommended pattern for loading up initial assets so that they can be required intuitively in dependent modules.

Categories