requirejs module alias/remap - javascript

I'm currently integrating foreign code into our application.
Part of the process, I must substitute one of their requirejs modules with ours.
Obviously I can't modify their code, otherwise I'd have to do the change at every update. What I can do is modify the main.js (data-main of requirejs).
Here is, roughly, what they have:
requirejs.config({
packages: [
'beerpong'
]
});
So they have this beerpong package, with some modules in there. Among these modules, there is the beer.js file. It can be required with a require('beerpong/beer').
Aside from this, I have my files, in a separate folder, say vodkapong/beersubstitute. What I would like is that, whenever someone require('beerpong/beer'), that requirejs actually serves him my vodkapong/beersubstitute instead.
tl;dr: How can I remap an existing module to use my module instead?
PS: Sadly, we're not actually writing a beerpong game... One day maybe!

You could use the map option. It can remap an AMD module for a specific module or for all modules with the "*" name. An example would be:
require.config({
map: {
"*": {
"beerpong/beer": "vodkapong/beersubstitute"
}
},
...
});

You can do something like this -
require.config({
paths: {
jquery_ui_scrollbar: 'libs/jquery/jquery.custom-scrollbar'
}
});
require(['dependency1', 'dependency2'], function (dep1, dep2) {
// code goes here
});
And in your define call you can do this -
define(['jquery_ui_scrollbar'], function(scrollbar) {});

Related

requirejs dependencies load order doesn't work

I have such a code:
requirejs.config({
urlArgs: "bust=" + (new Date()).getTime(),
paths: {
mods: 'default',
myFriend: 'myFriend',
myCoworker: 'myCoworker'
},
shim: {
mods: ['myFriend', 'myCoworker']
}
});
require(['mods'], function (mods) {
// something to do
});
and modules which are the dependencies:
myFriend.js
var mess = `<a really huge text, almost 200 Kbytes>`
console.log('This code is ran in the myFriend module...', {mess:mess});
myCoworker.js
console.log('This code is ran in the myCoworker module...');
var wrk = {
name: 'John'
};
So I hope, that accordingly to shim is should always load myFriend.js (that is checked by console.output) before myCoworker.js. But it doesn't. The console output shows:
This code is run in the myCoworker module...
and then
This code is run in the myFriend module...
Probably I have missed something, but what?
The entire code is here: http://embed.plnkr.co/zjQhBdOJCgg8QuPZ5Q8A/
Your dealing with a fundamental misconception in how RequireJS works. We use shim for files that do not call define. Using shim makes it so that RequireJS will, so to speak, add a kind of "virtual define" to those files. The shim you show is equivalent to:
define(['myFriend', 'myCoworker'], function (...) {...});
The dependency list passed to a define or require call does not, in and of itself, specifies a loading order among the modules listed in the dependency list. The only thing the dependency list does is specify that the modules in the list must be loaded before calling the callback. That's all.
If you want myFriend to load first, you need to make myCoworker dependent on it:
shim: {
mods: ['myFriend', 'myCoworker'],
myCoworker: ['myFriend'],
}
By the way, shim is really meant to be used for code you do not control. For your own code you should be using define in your code instead of setting a shim in the configuration.

requirejs dependencies grouping

I am trying to integrate requirejs framework to my app.
Is possible to create a virtual module (which doesn't exists as a physically file), where i could group all the jquery-validation plugins together?
For example, i need to load 4 dependencies everytime i want to use jquery-validate.
Instead of requesting them, each time, i create a jquery-val "virtual module", which should request all the dependencies automatically.
However, trying to load "jquery-val" actually tries to load the file from disk (which i don't have).
What should be the best practice in solving this issue?
// config
requirejs.config({
baseUrl: '/Content',
paths: {
'jquery': 'frameworks/jquery-3.1.1.min',
"jquery-validate": "frameworks/jquery.validate.min",
"jquery-validate-unobtrusive": "frameworks/jquery.validate.unobtrusive.min",
"jquery-unobtrusive-ajax": "frameworks/jquery.unobtrusive-ajax.min"
},
shim: {
"jquery-val": ["jquery", "jquery-validate", "jquery-validate-unobtrusive", "jquery-unobtrusive-ajax"]
}
});
// Solution 1: working, but ugly
define(["jquery", "jquery-validate-unobtrusive", "jquery-unobtrusive-ajax"], function ($) {
// My Module
});
// Solution 2: not working
define(["jquery-val"], function () {
// My Module
});
// Solution 3: create jquery-val.js file, which loads the dependencies automatically
// jquery-val.js
(function (global) {
define(["jquery", "jquery-validate-unobtrusive", "jquery-unobtrusive-ajax"], function ($) {
});
}(this));
take some time and read:
http://requirejs.org/docs/api.html#modulenotes
One module per file.: Only one module should be defined per JavaScript file, given the nature of the module name-to-file-path lookup algorithm. You shoud only use the optimization tool to group multiple modules into optimized files.
Optimization Tool
To answer your question:
It is good practice to define one module per file, so you don't need to define explicit a name for the module AND do the need for inserting it somewhere to be available before the other modules are loaded.
So you could require just the file: require("../services/myGroupModule") and this file would hold your module and requireJS would take care of the loading dependencies (and later the optimizations for concatenating into one file!). Here the module name is the file name.
You could nevertheless do the following and loading it as a file module or like you tried to define it beforehand and give the module a name:
//Explicitly defines the "foo/title" module:
define("myGroupModule",
["dependency1", "dependency2"],
function(dependency1, dependency2) {
return function myGroupModule {
return {
doSomething: function () { console.log("hey"); }
}
}
}
);
Maybe you should also give a look at some new module loaders:
WebPack 2: https://webpack.js.org/
SystemJS: https://github.com/systemjs/systemjs

Got confused about define with dependencies in RequireJS

I know in RequireJS, we can use define() to define a module with dependencies.
The things I got confused is such chunk code in jQuery.
// ready.js
define([
"../core",
"../core/init",
"../deferred"
], function( jQuery ) {
// ...
})
Actually I can not figure out the dependencies with "../core" and "../core/init",
as RequireJS says,
RequireJS also assumes by default that all dependencies are scripts, so it does not expect to see a trailing ".js" suffix on module IDs.
But there isn't a file called ../core.js, just a ../core directory.
So is ../core dependency needless?
You're right, you don't have to specify folders as dependencies, only scripts that you want to load.
// ready.js
define([
"../core/init",
"../deferred"
], function(init, deferred) {
// ...
});
And to say more, RequireJS does not even allow you to mark the entire folder as a dependency.

How to use require.js with complicated source tree, or import something else from CommonJS'es main.js?

My JS code is Backbone.js based, so I think it is a good idea to separate "classes" with this logic as shown on picture (though I'm not sure where to place templates - in this packages or in global templates folder, and do not mind main.js - it is not related to CommonJS packages) :
Now since there is fairly lot of them - I've decided to use require.js to deal with this bunch of <script src=... tags but got stuck with app.js config file (which is the only one that I include like this -
<script data-main="/static/js/app.js" src="/static/js/libmin/require.js"></script>
What do I mean with stuck - of course I can iterate all this js files in require statement using names like PlayerApp/PlayerAppController.js, or using paths directive (not sure if it will make the code look not that ugly), but it would be cool if I can use something like python's from package import *, and of course there is no such thing in require.js.
The most similar thing is packages directive, but seems like it allows you to import only main.js from each package, so then the question is - what is the most correct way to load other files of concrete package from CommonJS's main.js? I have even found a way to determine current .js file's name and path - like this, and given that I can make up other files names in current package(if I will keep naming them with the same pattern), but still do not know how to import them from main.js
Edit:
There might be an opinion that it is not very clear what exactly am I asking, so let me get this straight: how on Earth do I import a huge amount of javascript files with that project structure in the most nice way?
You are mis-understanding the purpose of a module loader. require.js is not there to make it easy for you to import all of your packages into the current namespace (i. e. the browser). It is there to make it easy to import everything you need to run app.js (based on your data-main attribute). Don't try to import * - instead, just import thingYouNeed.
Configuration
What you will want to do is set up your require.config() call with all the necessary paths for libraries like Backbone that don't support AMD and then update your code to explicitly declare its dependencies:
require.config({
// Not *needed* - will be derived from data-main otherwise
baseUrl: '/static/js/app',
paths: {
// A map of module names to paths (without the .js)
backbone: '../libmin/backbone',
underscore: '../libmin/underscore',
jquery: '../libmin/jquery.min',
jqueryui.core: '../libmin/jquery.ui.core'
// etc.
}
shim: {
// A map of module names to configs
backbone: {
deps: ['jquery', 'underscore'],
exports: 'Backbone'
},
underscore: {
exports: '_'
},
jquery: {
exports: 'jQuery'
},
// Since jQuery UI does not export
// its own name we can just provide
// a deps array without the object
'jqueryui.core': ['jquery']
}
});
Dependencies
You will want to update your code to actually use modules and declare your dependencies:
// PlayerAppModel.js
define(['backbone'], function(Backbone) {
return Backbone.Model.extend({modelStuff: 'here'});
});
// PlayerAppView.js
define(['backbone'], function(Backbone) {
return Backbone.View.extend({viewStuff: 'here'});
});
// PlayerAppController.js
define(['./PlayerAppModel', './PlayerAppView'],
function(Model, View) {
// Do things with model and view here
// return a Controller function of some kind
return function Controller() {
// Handle some route or other
};
});
Now, when you require(['PlayerApp/PlayerAppController'], function(Controller) {}) requirejs will automatically load jQuery, underscore, and Backbone for you. If you never actually use mustache.js then it will never be loaded (and when you optimize your code using the r.js compiler, the extra code will be ignored there as well).

How can I use a local file during Require.js optimisation, but a CDN-hosted version at runtime?

My page includes several components that exist as separate AMD modules. Each of these components is turned into a single file by the Require.js optimiser. Because several of these components share dependencies (e.g. jQuery and d3), the optimiser paths config uses CDN URLs for those dependencies, rather than bundling them into the optimised file.
Here's where it gets tricky. I've written a module loader plugin for Ractive.js called rvc.js, which allows me to include Ractive components that are defined in HTML files. (Yes, I'm asking for help on how to use my own library.)
This works fine - code like this gets optimised as you'd expect:
define( function ( require ) {
var ChartView = require( 'rvc!views/Chart' );
var view = new ChartView({ el: 'chart' });
});
Because Ractive is used by several of the components, it should be served from a CDN like jQuery and d3. But it's used by rvc.js during the optimisation process, which means that the Ractive entry for the optimiser's paths config can't point to a CDN - it has to point to a local file.
Is there a way to tell Require.js 'use the local file during optimisation, but load from CDN at runtime'?
So here's the solution I eventually settled on. It feels somewhat kludgy, but it works:
Stub out the loaders and the library you don't want bundled
Add an onBuildWrite function that rewrites modules depending on the library, so that they think they're requiring something else entirely - in this case Ractive_RUNTIME
Add an entry to your runtime AMD config's paths object, so that Ractive_RUNTIME points to the CDN
My optimiser config now looks like this:
{
baseUrl: 'path/to/js/',
out: 'build/js/app.js',
name: 'app',
optimize: 'none',
paths: {
'amd-loader': 'loaders/amd-loader',
'rvc': 'loaders/rvc',
'Ractive': 'lib/Ractive'
},
stubModules: [ 'amd-loader', 'rvc', 'Ractive' ],
onBuildWrite: function ( name, path, contents ) {
if ( contents === "define('Ractive',{});" ) {
// this is the stub module, we can kill it
return '';
}
// otherwise all references to `Ractive` need replacing
return contents.replace( /['"]Ractive['"]/g, '"Ractive_RUNTIME"' );
}
}
Meanwhile, the script that loads the app.js file created by the optimiser has a config entry that points to the CDN:
require.config({
context: uniqueContext,
baseUrl: baseUrl,
paths: {
'amd-loader': 'loaders/amd-loader',
'rvc': 'loaders/rvc',
'Ractive': 'lib/Ractive',
'Ractive_RUNTIME': 'http://cdn.ractivejs.org/releases/0.3.9/Ractive.min'
}
});

Categories

Resources