Predefining AMD module dependencies in RequireJS config - javascript

For the sake of loading times, I'm interested in predefining all AMD module dependencies. This is because at the moment, the module file must load before require.js can work out its dependencies. Here's an illustration to show what I mean:
Is there any way to do this with require.js? I know you can define dependencies for the shimmed modules, but can you do this for your own custom AMD modules?

You are looking for something you can put in the configuration you pass to RequireJS that would do what you want. There is no analogue to shim for modules that call define. However, what you could do is add the deps option to your configuration:
deps: ['module', 'dep1', 'dep2', 'dep3']
This will tell RequireJS to start loading immediately your module and the dependencies. You will have to maintain this list yourself but this would be true with shim too.
Otherwise, you can do what kryger suggested in a comment: use r.js to build module into a single bundle that contains it and all of its dependencies. Whenever module is loaded, all of its dependencies are loaded at the same time. This is more efficient than using deps but might make things slightly more complicated if you ever need to load any of the dependencies by themselves. You'd have to use the runtime option bundles to tell RequireJS where these modules are. And just like deps you'd have to maintain this list yourself.

Related

Using Rollup + Svelte with third party AMD libraries

I understand that Svelte can produce AMD output and find some details on how to do this in the docs. I can also find some info on how to configure Rollup to output AMD modules. But what about input? What do I need to do when I have AMD modules as dependencies?
For example, suppose I have two different third party libraries that are both distributed as AMD libraries and I want to use those libraries in my Svelte project. How would I need to modify eg. this nested components demo to allow these AMD modules to be used as dependencies in my Svelte components?
Also, am I able to configure whether I bundle these libraries together with my Svelte components? If so, where would I need to do that?
Note
I also raised this issue on Github.
AMD modules are a pain to convert to ES modules, so you may find it difficult to bundle them with Rollup. (There's rollup-plugin-amd but it comes with caveats.)
But you can easily treat them as external dependencies that get loaded separately — just import them as normal then configure Rollup:
// rollup.config.js
export default {
// ...
format: 'amd',
external: ['an-external-amd-module'],
paths: {
'an-external-amd-module': 'https://my-cdn.com/an-external-amd-module.js'
}
};
You can see a demo here (repo here) — note that we're loading an exernal AMD module called the-answer, even though it's a regular import, because of the Rollup config.

Module loading order in requirejs

We ran into an interesting problem in an existing project,
We're using requireJS
All our modules are AMD compliant(and we have a lot of them)
We need to include a subset of babel-polyfill as an AMD module to the project.
It's not possible to manually add this dependency to all modules one by one
Our code is optimized and bundled using r.js
Our main file looks something like this : // main.js
require(
[
'router',
'someOtherModule', /* In reality we have quite a few more here */
], function(Router, AppModule) {/*... app code ...*/}
)
So we'd like to load this polyfill module before any other module is loaded in main.js
What won't work :
Shim - Shim is used for non AMD module.
Adding the polyfill to the list above router - in the minified code that r.js spits out, there's no guarantee that polyfill will actually be in the code before router, it's not the defined behavior and thus cannot be counted on.
Wrapping everything with another require['polyfill'] call seems to screw up the r.js optimizer, it won't seem the bundle together the other modules if they're wrapped in require[].
Since the polyfill is an AMD module, we can't just include it in the <HEAD>
Option 3 is still something we're investigating to see if it's possible.
So the question is - Is what we're trying to do possible?
Whenever I load polyfills I always always always load them in a script element in head. I never load them through RequireJS. Loading them through RequireJS gives rise to all kinds of problems, as you discovered. You wrote:
Since the polyfill is an AMD module, we can't just include it in the <HEAD>.
The babel-polyfill package builds itself into a script that can be loaded through a script element by using Browserify:
#!/bin/sh
set -ex
BROWSERIFY_CMD="../../node_modules/browserify/bin/cmd.js"
UGLIFY_CMD="../../node_modules/uglify-js/bin/uglifyjs"
mkdir -p dist
node $BROWSERIFY_CMD lib/index.js \
--insert-global-vars 'global' \
--plugin bundle-collapser/plugin \
--plugin derequire/plugin \
>dist/polyfill.js
node $UGLIFY_CMD dist/polyfill.js \
--compress keep_fnames,keep_fargs,warnings=false \
--mangle keep_fnames \
>dist/polyfill.min.js
If you inspect dist/polyfill.js, you'll see it is not an AMD module. (The define function it calls is not AMD's define function.)
You should be able to adapt this method to your whatever subset of babel-polyfill you use.

RequireJS: optimizer generates name for define module

I'm using gulp.js and an optimization tool for requirejs (gulp-requirejs) it combines all scritps into one file. I have one define module with no name but it generates a name for it. The problem is I don't know how to call that module from another file.
For example in page1.js:
...
define("map",["jquery"],function($){
...
});
define("lib", ["jquery"],function($){
...
});
and in page2.js I would like to call page1.js lib module but I am not sure how to do it? I would prefer if the optimization tool did not set a name then my code works but this way I have no idea how to make it work. Any ideas?
It is not possible to use multiple modules in a single file, unless these modules are named. Otherwise RequireJS won't know how to relate a request for a module with the actual code that defines it.
The typical scenario when optimizing all modules into a single bundle is that there is going to be one specific module in the bundle which serves as the entry point of your application, and then you can just put that module name in paths:
require.config({
paths: {
lib: 'path/to/page1',
}
});
If you do not have a single entry point but may in fact also have code outside the bundle that will initiate loading modules that are in the bundle, then you need to list those modules in bundles:
require.config({
paths: {
lib: 'path/to/page1',
},
bundles: {
lib: ['map', ...],
}
});
The bundles setting I have shown above says essentially "when you look for the module named map, fetch the module lib, and you will have the definition of map."

RequireJS order of dependencies

if you have a RequireJS module like so:
define(
[
'#patches',
'backbone',
'underscore',
'react',
'#allCollections',
'#allModels',
'app/js/routers/router',
'#allTemplates',
'#allControllers',
'#allRelViews'
],
function(){
var patches = arguments[0];
});
is there any way to know which dependency gets loaded first? In my case, '#patches' is a few window.X utility functions that I want to load before anything else. Do I need to configure this a different way to ensure this?
(in my case "#' is just my own notation to denote a module whose path is predefined in my main config file)
From the documentation : http://requirejs.org/docs/api.html#mechanics
"RequireJS waits for all dependencies to load, figures out the right order in which to call the functions that define the modules, then calls the module definition functions once the dependencies for those functions have been called. Note that the dependencies for a given module definition function could be called in any order, due to their sub-dependency relationships and network load order."
I think this may help: http://www.sitepoint.com/understanding-requirejs-for-effective-javascript-module-loading/ (see "Managing the Order of Dependent Files")
RequireJS uses Asynchronous Module Loading (AMD) for loading files. Each dependent module will start loading through asynchronous requests in the given order. Even though the file order is considered, we cannot guarantee that the first file is loaded before the second file due to the asynchronous nature. So, RequireJS allows us to use the shim config to define the sequence of files which need to be loaded in correct order. Let’s see how we can create configuration options in RequireJS.
requirejs.config({
shim: {
'source1': ['dependency1','dependency2'],
'source2': ['source1']
}
});
Hope it helps
EDIT: As said in comments, using Shim for AMD module is a bad idea, use only shim for non AMD modules and manage dependencies order there.
For AMD module requirejs will manage the order of loading.
A good link from the comments (thanks Daniel Tulp) ==> Requirejs why and when to use shim config

RequireJS non-AMD files

I'm attempting to use LeafletJS with requireJS and some LeafletJS plugins. I know that if you are using files that aren't AMD modules, you need to shim them in the config. Does this mean I will have to shim each individual plugin with the LeafletJS dependency? Ex:
require.config({
paths: {
'leaflet': 'vendor/leaflet/leafletjs',
'leafletplugin1': 'vendor/leaflet/leafletplugin1',
'leafletplugin2': 'vendor/leaflet/leafletplugin2'
},
shim: {
'leafletplugin1': {
deps: 'leaflet'
},
'leafletplugin2': {
deps: 'leaflet'
}
}
});
The problem is that I plan to have many libraries with many plugins, and this config will get extremely long since I have to not only shim each individual plugin but also provide a path for each. Is there a simpler way to do this? It would be nice if I could even define a require.config inside of a module for use only with that module, that way I could keep my project better organized and less cluttered.
Also, there is no other way to simply require(['leafletplugin1'], function(){}); without shimming it, correct?
EDIT: Just to clarify, this doesn't have to be a LeafletJS-specific question/answer. This is just the current example I'm working with.
Option 1: depending on your build process and..
Number of plugs
Total size of plugins
would be concat all of the 'leaf' plugins into a single file.
Option 2: Turn all the plugins into proper modules.
This would mean having a ~/leaf directory and a ~/leafModule directory and having the build process "wrap" each plugin into a proper module.
In a similar situation, I did option 2. Was fairly easy and made the rest of my code far easier to work on.

Categories

Resources