RequireJS non-AMD files - javascript

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.

Related

Dynamic requirejs configuration extending

I'm using requirejs for multipage project. Each page is an App. All of the apps have some common dependencies, i.e. jquery, backbone, underscore etc.
I want to move all this dependencies to the one single file.
That's how the js folder structure looks like:
js
base-app-require-configuration.coffee
app
homepeage
init.coffee
build.js
application.coffee
app1
init.coffee
build.js
application.coffee
app2
init.coffee
build.js
application.coffee
Homepage application example:
js/base-app-require-configuration.coffee
define ->
requirejs.config
urlArgs: "bust=#{ new Date().getTime() }"
# yep, tricky paths here
paths:
jquery: '../../jquery.min'
underscore: '../../underscore-min'
backbone: '../../backbone.min'
js/app/homepage/init.coffee
define [
'../../base-app-require-configuration'
], (
baseRequireConfig
) ->
requirejs.config
paths:
'jquery.alphanum': '../../jquery.alphanum'
shim:
'jquery.alphanum':
deps: ['jquery']
require [
'jquery'
'application'
], (
$
Application
) ->
$ -> new Application
js/app/homepage/build.js
({
mainConfigFile: ['../../base-app-require-configuration.js', 'init.js'],
wrapShim: 'true',
baseUrl: './',
name: 'init',
findNestedDependencies: true,
out: 'init.js'
})
My data-name is init.js
The thing works pretty well for multiple apps with the common dependencies moved to one sigle file - base-app-require-configuration.coffee, except one thing: the only way to compress/optimize this using r.js is to set the flag findNestedDependencies to true, because otherwise r.js won't see requirejs.config calls nested into define/require.
My questions are:
Is using findNestedDependencies a good practice?
Is there a prettier way to organize my dependencies without repeating?
If there is such a way - will it be compatible with r.js?
Let me share this solution with you.
I'm also looking for the similar solution with requirejs (how to organize the multipage project without repetitions of a long configuration, with a "shim" feature), and I have found the following one (I would be glad if this snippet can help you):
Inside HTML:
...
<script src="js/lib/require.js"></script>
<script>
//Load common code that includes config, then load the app
//logic for this page. Do the requirejs calls here instead of
//a separate file so after a build there are only 2 HTTP
//requests instead of three.
requirejs(['./js/common'], function (common) {
//js/common sets the baseUrl to be js/ so
//can just ask for 'app/main1' here instead
//of 'js/app/main1'
requirejs(['app/main1']);
});
</script>
...
where "common.js" contains the common configuration of requirejs for your project. This sample is from: https://github.com/requirejs/example-multipage-shim/blob/master/www/page1.html.
The full code of a sample project is here: https://github.com/requirejs/example-multipage-shim. The sample "build.js" file also providen, I see there is no necessity in "findNestedDependencies" in this case.
Sure, there is a bit more code inside HTML, but I think this is not significant downside.
Is using findNestedDependencies a good practice?
Not sure. the only thing i know, is that this option can slow down the bundling process quite a lot:
Is r.js dependency tracing significantly slower since v2.1.16? Or is it just me?
Is there a prettier way to organize my dependencies without repeating?
If there is such a way - will it be compatible with r.js?
this is a great article out organising backbone modules using r.js:
https://cdnjs.com/libraries/backbone.js/tutorials/organizing-backbone-using-modules

Creating a JS library and declare what other libraries in depends on

So I'm writing a php-package which will be put on github&packagist. It generates and writes data to a file, and the package will also come with a js-library which job is to read that data-file and display it to the user.
Now, this js-library depends on other libraries, jquery being one among a couple others.
What would be a clean way of declaring those dependencies?
I don't mind using require.js and I have in fact used it for several other projects. But those projects have been complete "apps", not libraries that others are to include in their projects. So in those cases it was no concern adding dependencies and configuring require.js, and it only had to be done once. But this time I want to be able to include this library with minimal amount of code, preferbly without long instructions on how to load it correctly and what other libraries the developer would need to load in as well.
In short: I want to distribute a library that depends on other libraries, which me or another developer can include in another project with minimal amount of code and without knowledge of what other libraries this one depends on.
I'm sure this has been asked before, but I can't seem to find anything on it. I do find lot of information on how to declare dependencies in main projects, but not in libraries.
You have two options:
Bundle your application into a single file(including 3th party libraries)
Just bundle your application into a single file (without including 3th party libraries)
In both cases you will need to create an automated build. You can use gulp to create tasks to concatenate all your files into a single file like framework.js and framework.min.js files that other developers will import.
You can use If you are using require.js you could use the gulp-requirejs plugin to run the requirejs optimizer:
var gulp = require('gulp'),
rjs = require('gulp-requirejs');
gulp.task('requirejsBuild', function() {
rjs({
baseUrl: 'path/to/your/base/file.js',
out: 'FILENAME\_TO\_BE\_OUTPUTTED',
shim: {
// standard require.js shim options
},
// ... more require.js options
})
.pipe(gulp.dest('./delpoy/')); // pipe it to the output DIR
});
If you decide to include the 3th party libraries as well, use the No conflict fucntion to avoid problems if somebody has already loaded jquery.
If you decide to don't include the libraries you can look for some variables in the global scope in your library and throw errors if the dependencies are not available.
if(typeof $ === "undefined") throw new Error("Framework requires > Jquery 1.9.0");
You can usually find the version of a library with ease, for example in jquery:
$.prototype.jquery
Update
I would personally recommend to use Browserify. If you are using requirejs, you can use browserify-ftw to automatically migrate your project from AMD to CommonJS.
The Browserify optimizer will generate a bundle.js file that your users will be able to import directly without having to download 3th party dependencies or configuring a module loader.
Hope it helps :)

Predefining AMD module dependencies in RequireJS config

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.

How to prevent browserify-shim from requiring all shims?

I am using browserify and browserify-shim in a project, run through gulp using gulp-browserify.
gulp.src(['./resources/js/main.js'])
.pipe(browserify({
shim: {
angular: {
path: './node_modules/angular/angular.js',
exports: 'angular'
},
'angular-animate': {
path: './node_modules/angular-animate/angular-animate.js',
exports: 'ngAnimate',
depends: {
angular: 'angular',
jQuery: 'jQuery'
}
},
[...]
}
}))
.pipe(concat('app.js'))
.pipe(gulp.dest('./web/js'));
This setup works fine and, for most parts, as intended. However, Browserify will always include all shimmed libraries in the build, even if none of them is called by require().
The documentation seems to be non-existant on this topic. Is there a way to prevent this? It seems very counter-intuitive to me - the build should only contain what I actually require.
(Update: I installed angular and other libs using napa/npm)
When you shim with Browserify, it's making those libraries (and specifically the objects you tell it to "export") global. The convention is to still use require() for those libraries, however, doing so is just best practice so that if the library were to convert to module.exports down the road, you won't have to replace the global references in your code. Plus, it's nicer to list all of the files you require at the top in good node form. :)
So to answer your question, by shimming those libraries, you've told browserify to include them as global variables so they can be used anywhere, so they'll be included in the build automatically, regardless of whether you require() them.
If you want to include some and not others based on something like gulp.env, you could try building the options object separately and passing it into the browserify function.

requireJS configuration for Modernizr

I am trying to load the Modernizr feature detects dynamically with requireJS.
As Modernizr has built in AMD support this shouldn't be a problem.
My requireJS configuration contains the paths to the Modernizr source directory and to the feature detects directory:
requirejs.config({
paths: {
"modernizr" : "components/modernizr/src",
"feature-detects": "components/modernizr/feature-detects"
}
});
Lets assume one of my views would require the svg test.
My view definition might look like this
define(["feature-detects/svg"], function() { .. });
Unfortunately the svg.js can't find Modernizr.js because all feature detects and Modernizr source files load Modernizr without specifying any directory: define(['Modernizr'], ...
Which results in a very ugly require.config
requirejs.config({
paths: {
"Modernizr": "components/modernizr/src/Modernizr",
"addTest": "components/modernizr/src/addTest",
"ModernizrProto": "components/modernizr/src/ModernizrProto",
"setClasses": "components/modernizr/src/setClasses",
"hasOwnProp": "components/modernizr/src/hasOwnProp",
"tests": "components/modernizr/src/tests",
"is": "components/modernizr/src/is",
"docElement": "components/modernizr/src/docElement",
"feature-detects": "components/modernizr/feature-detects"
}
});
Is there a cleaner way to tell requireJS to search in components/modernizr/src/ whenever it couldn't find the file?
Update
I created an example github project which includes the basic setup and a running demonstration.
Modernizr's AMD structure is (currently) just for its own internal build process. We've discussed exposing this so that it can be used as you've tried, but haven't agreed on a convenient way to do this yet. A Modernizr plugin for RequireJS could be one option.
Are you using Bower? If so, it's worth noting Modernizr isn't suitable for use with Bower yet.
The recommended way to tie Modernizr into your build process at the moment is using grunt-modernizr, which will automatically find references to Modernizr detects in your code (or you can explicitly define them), then you can just use the resulting Modernizr build like any other AMD dependency whenever you need it:
define(['path/to/built/modernizr.js'], function (Modernizr) {
if (Modernizr.svg) {
...
}
});
My suggestion would be to have a shim
Config
paths: {
'Modernizr': 'PATH TO MODERNIZR'
},
shim: {
'Modernizr': {
exports: 'Modernizr'
}
}
=================
You can use define in your script
define(['Modernizr'],function(Modernizr) {
'use strict';
console.log(Modernizr)
// This should log the Modernizr function
//For Example
if(Modernizr.boxshadow){
// Do something here
}
});
If I understand your question correctly, wouldn't you just define your feature like so:
define([
"modernizr",
"feature-detects/svg"
], function(Modernizr) {
Modernizr.addTest();
});
This way modernizr will be loaded before your feature detection code runs.

Categories

Resources