RequireJS: optimizer generates name for define module - javascript

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."

Related

Require third party RequireJS modules with Webpack

I'm working on an application that needs to pull in the ReadiumJS library, which uses AMD modules. The app itself is written in es6 w/ webpack and babel. I've gotten the vendor bundle working correctly, and it's pulling in the built Readium file, but when I try to require any of the modules Webpack says it can't resolve them. Anyone ever do this before with Webpack and RequireJS? Here's some info that may help - not sure what else to include as this is my first time really using Webpack..
Folder Structure
/readium-src
/readium-js
/ *** all readium-specific files and build output (have to pull down repo and build locally)
/node_modules
/src
/app.js -> main entry for my app
/webpack.config.babel.js
webpack.config.js entries
entry: {
vendorJs: [
'jquery',
'angular',
'../readium-src/readium-js/build-output/_single-bundle/readium-js_all.js',
'bootstrap/js/alert.js' //bootstrap js example
],
appJs: './app.js'
}
Trying to require it in app.js
var readiumSharedGlobals = require('readium_shared_js/globals');
I never really got into using RequireJS, so really struggling to understand how to consume that type of module along side other types of modules with webpack. Any help greatly appreciated :)
Update
If I change my app.js to use this instead:
window.rqReadium = require('../readium-src/readium-js/build-output/_single-bundle/readium-js_all.js');
Then it appears to try to load all the modules, but I get a strange error:
Uncaught Error: No IPv6
At this point, I'm unsure of
Should I have to require the entire path like that?
Is this error something from webpack, requirejs, or Readium? Tried debugging, but couldn't find anything useful...
UPDATE 8/12/2016
I think this is related to an issue with a library that Readium is depending on: https://github.com/medialize/URI.js/issues/118
However, I'm still not clear on how to correctly import AMD modules with webpack. Here's what I mean:
Let's say I have an amd module defined in moneyService.amd.js like this:
define('myMoneyService', ['jquery'], function($) {
//contrived simple example...
return function getDollaz() { console.log('$$$'); }
});
Then, in a sibling file, app.js, I want to pull in that file.
//this works
var getDollaz = require('./moneyService.amd.js');
//this works
require(['./moneyService.amd.js'], function(getDollaz) { getDollaz(); }
//this does not
require(['myMoneyService' /*require by its ID vs file name*/], function(getDollaz) {
getDollaz();
}
So, if we cannot require named modules, how would we work with a third party lib's dist file that has all the modules bundled into a single file?
Ok, so there's a repo out there for an Electron ePub reader using Readium, and it's using webpack: https://github.com/clebeaupin/readium-electron This shows a great way to handle pulling in RequireJS modules with webpack.
One super awesome thing I found is that you can specify output.library and output.libraryTarget and webpack will transpose from one module format to another... freaking awesome! So, I can import the requirejs module, set output library and libraryTarget to 'readium-js' and 'commonjs2' respectively, then inside my application code I can do import Readium from 'readium-js';

RequireJS paths config saying "all modules are in this file"

In RequireJS, it's possible to configure paths explicitly for given modules. For example, you can specify that for module foo the module bar should be loaded instead (file bar.js should be loaded):
require.config({
paths: {
"foo": "bar"
}
});
How can I do the same, but for all modules?
I tried using an asterisk, but it will only create a mapping for module * literally:
require.config({
paths: {
"*": "bar"
}
});
According to your question and comment
The TypeScript compiler is able to compile multiple external modules into named AMD modules placed into a single output file. However, to effectively use those modules, RequireJS must be configured so that it knows where to find them.
There is a work-around can be applied. First of all, let's not define any module paths in config except the path for all modules.
require.config({
paths: {
"all": "path/to/all/modules"
},
deps: { "all" } // This to tell requireJS to load 'all' at initial state.
});
And then load the config/main file
<script data-main="scripts/main" src="scripts/require.js"></script>
From this requireJS will simply read all the define() blocks in modules.js. It will registering all the module names you got in the js file. For example if you got define('myModule', [function(){...}]); in your module.js. You can simply call to load it at any place without define a path for it.
For example some where in your code.
requirejs(['myModule', function(myModule){
myModule.doSemething();
});

Combining multiple files in grunt-requirejs

I have a Javascript application spanning multiple files using RequireJS, which I want to concatenate into one for the production environment.
I've been looking at grunt-contrib-requirejs but the instructions for setting up the configuration in Gruntfile.js assume that you already have the concatenated, production source. I'm aware that I could also use grunt-contrib-concat for this, but I was wondering if there's a way to do it with the grunt-contrib-requirejs module.
I've also tried using a wildcard selection for the name field in the configuration, but although Grunt works fine with specifications like app/**/*.js grunt-contrib-requirejs doesn't concatenate them when I specify this.
I found this example on how to do this, but when I include multiple entries in the modules array, running Grunt complains that certain files can't load their dependencies that are specified in the main file's require.config.
For example, if this is main.js:
require.config({
paths: {
'angular': 'http://some.cdn/angular.min'
},
shim: {
angular: {
exports: 'angular'
}
}
});
//Set up basic code
And this is controllers/ctrl.js:
define(['angular'], function(angular) {
...
});
Then it's apparently not loading the configuration from main.js and complains that there's no file /my/project/controllers/angular.js
I've also tried moving the configuration to a file specified with the mainConfigFile option, but this option does not work and it seems that this option was meant to take the Grunt configuration and not the RequireJS configuration.

Using r.js to optimize and concatenate files for use as a library

Okay, I've just gotten dropped into a project I have several different modules written in AMD format. I need to get these javascript files that are loosely related into one javascript file, that will then be referenced as yet another AMD module across different projects (probably from a CDN).
The problem I'm facing is when I run r.js against these files and get them into one file, when I pull that combined file into another project it just gets spit out as undefined.
To give an idea of what I'm talking about
words.spelling.js
define(['jquery', 'some.other.class'], function($, foo){
...
}
words.grammar.js
define(['jquery', 'some.other.class'], function($, foo){
...
}
words.translation.js
define(['jquery', 'some.other.class'], function($, foo){
...
}
Run through r.js into words.min.js
Then say I pull it into app.js as
require(['jquery', 'app/main/main', 'words.min'], function($, main, words) {
$(document).ready(function() {
console.log(words);
}
words just shows up as undefined.
Just concatenating them all doesn't do anything as that just gives me a bunch of define statements one after another.
I tried creating a fake class that has
define(['word.grammar', 'word.translation', 'word.spelling'], function( g, t, s){
return {
grammar: g,
translation: t,
spelling: s
};
});
and running that through r.js, but no dice there either. Am I missing something here or am I going to have re-write these in non-AMD format so I can concatenate them together and return one giant object? Keep in mind, words.min.js is going to have to be hosted on a CDN and cached as it'll be shared throughout a number of projects so I need that as a separate file.
One solution would be to use a paths configuration to map these module names to their actual file:
So in development you use something like this
require.config({
paths: {
'words.spelling': 'libs/words.spelling',
'words.grammar': 'libs/words.grammar',
'words.translation': 'libs/words.translation'
}
}
You'll want to pass the same paths config from development into the r.js optimizer, so that the module names it puts inside the combined file have just the name, not some extra path info. For example, you want the modules name inside your combined bundle to be: 'words.spelling', not 'some/other/path/words.spelling'
And then to use the combined version in another application, you do something like this to map all those module names to the same file:
require.config({
paths: {
'words.spelling': 'libs/words.min',
'words.grammar': 'libs/words.min',
'words.translation': 'libs/words.min'
}
}
Part of the confusion is that this is not the primary use of the r.js optimizer. It seems to be designed for use by the final web site developers, not by the module developers. But as you see above, it's possible to coerce it into that mode.

How can I instantiate optimised modules in requirejs outside of the optimised file?

In my require.config I create shorthands for a couple of paths that I use regularly:
require.config({
paths: {
text: 'components/requirejs-text/text',
url: 'config/url',
List: 'modules/List/main'
...
Then on the individual pages (in separate script files), I instantiate a module like this:
require(['List'], function(List){ new List; });
My plan was to optimise all files into one file, require that and instantiate a module as in my example, but since the paths of require.config aren't really relevant anymore (Because I now only have main.build.js) how can I instantiate my modules?
UPDATE: Let me rephrase:
I'm trying to instantiate a module outside of the optimised build script, how do I do that?
Wherever you want to include the List module just create a new paths configuration which points to the optimized file.
require.config({
paths: {
'List': 'js/myApp'
}
});
require(['List'], function(List) {
...
});
Move your config into a separate location (either inline in the head, or in a JS file) that is after the require.js library. Now you can load any modules in the future and they will all be able to read the config regardless of which ones are loaded first.
i think, we have one file called appInit.js, which do instantiate our application, so after that all other modules should instantiate on requirement, and also its not good practice to instantiate modules from every module.js,
consider single instance of Application and all other instance should relate to this application as components, services etc.,
every developer has his own coding style, choose what you are comfortable with..
if you are worrying about paths of modules, after building then don't worry paths are just the name of module, and it should work, but dynamically loaded or created modules won't work any more.

Categories

Resources