How can I call requireJS require(['app'], function() {}); only once at the beginning for the whole application so that any subsequent require(["..."], function(...){}); don't need to be wrapped within require(['app']?
This is my set up:
1) Load require.js
<script data-main="js/app.js" src="requirejs/require.min.js"></script>
2) Have app.js shims and basUrl configured properly.
requirejs.config({
baseUrl: "scripts/js",
paths: {
"jquery": "../bower_components/jquery/dist/jquery.min",
"modernizr": "../bower_components/modernizr/modernizr",
.
.
.
},
shim: {
"jquery.migrate": ['jquery'],
.
.
.
}
});
3) Dynamically load JS on different pages:
// Home Page
require(['app'], function() {
require(["jquery", "foundation", "foundation.reveal"], function ($, foundation, reveal){
$(document).foundation();
});
});
// Catalog Page
require(['app'], function() {
require(["jquery", "lnav/LeftNavCtrl","controllers/ProductCtrl", "controllers/TabsCtrl"], function ($, NavCtrl, ProductCtrl, TabsCtrl){
$(function() {
NavCtrl.initLeftNav();
});
});
});
Unless I wrap with require(['app'], function()) each time I call require("...") to load external JS or AMD modules, the app is not initialized and I get JavaScript errors. The above code works but it's not very efficient.
Is there a way to start my requireJS app before I try loading scripts?
I tried calling at the very beginning right after I load require.min.js:
require(["app"], function (app) {
app.run();
});
but it didn't work.
There are no provisions in RequireJS to ensure that a specific module is always loaded before any other module is loaded, other than having your first module load the rest. What you are trying to do is share your first module among multiple pages so it cannot perform the work of loading what is specific to each page.
One way you can work around this is simply to load app.js with a regular script element:
<script src="requirejs/require.min.js"></script>
<script src="js/app.js"></script>
Then the next script element can start your application without requiring app.js:
<script>
require(["jquery", "foundation", "foundation.reveal"], function ($, foundation, reveal){
$(document).foundation();
});
</script>
This is actually how I've decided to launch my modules in the applications I'm working on right now. True, it is not as optimized as it could be because of the extra network round-trip, but in the case of the applications I'm working on, they are still in very heavy development, and I prefer to leave this optimization for later.
Note that generally you don't want to use script to load RequireJS modules but your app.js is not a real module as it does not call define, so this is okay.
Another option would be to use a building tool like Grunt, Gulp, Make or something else and create one app.js per page and have each page load its own app.js file. This file would contain the configuration and the first require call to load the modules specific to your page.
Related
Maybe I have fundamentally misunderstood how requirejs config works but I thought my configuration below made some libraries global so I could just use them in other files while only having to require and define files that I needed to use within the individual script. However I cannot reference $ (jQuery) in my application code without getting a reference error indicating it is not globally accessible. I've isolated the problem to the simple example below.
My file set up is as follows:
test
|
|-index.html
|-TestApp.js
|-MainApp.js
|-lib
| |-require.js
| |-jquery.js
| |-loadash.js
| |-backbone.js
|-css
|-test.css
The library file versions are RequireJS 2.1.22, jQuery 2.0.3, Loadash 3.10.1 and Backbone 1.2.1. I'm just trying to set up my environment and the approach I am taking is to pass my TestApp.js file to require.js to load the required files and bootstrap the application code in MainApp.js. The script in index.html is as follows:
<!DOCTYPE html>
<html>
<head>
<link rel='stylesheet' type='text/css' href='css/test.css'/>
</head>
<body>
<div></div>
<script src="./lib/require.js" type="text/javascript" data-main="./TestApp.js"></script>
</body>
</html>
The referenced css script file simply ensured the div is visible as an orange square. See below:
div {
height: 100px;
width: 100px;
background-color: #FA6900;
border-radius: 5px;
}
It's the script line in index.html that then kicks off the application code by passing my configuration file to requirejs. This is the TestApp.js passed across as data-main. The TestApp.js is here:
require.config({
paths: {
'jquery': 'lib/jquery',
'lodash': 'lib/lodash',
'backbone': 'lib/backbone'
},
map: {
'*': {
// Backbone requires underscore. This forces requireJS to load lodash instead:
'underscore': 'lodash'
}
},
shim: {
jquery: {exports: '$'},
underscore: {
deps: ['jquery'],
exports: '_'
},
backbone: {
deps: ['underscore'],
exports: 'Backbone'
},
TestApp: {
deps: ['backbone'],
exports: 'TestApp'
}
}
});
require(['MainApp'], function(MainApp) {
MainApp.run();
});
The file above references the paths to the library files I want to use, I then remap loadash to be loaded when underscore is required (I need some of the extra loadash capability), I then use the shim to ensure the dependancies are correct as the files are loaded. Passing this config file to require.js in the index.html seems to be working as all of the files are showing as loaded in my browser. However the problem seems to be they do not appear to be globally accessible as I thought they would be.
Following the config section the last require call loads the MainApp.js file and calls the exposed run function. The MainApp.js looks like this:
define(function(require) {
var run = function() {
$(document).ready(function() {
$('div').click(function() {
$('div').fadeOut('slow');
});
});
};
return {
run: run
};
});
As far as I understood I should not need to require the files I already mentioned in the require config, I thought they should be loaded and available to this code. This is where I have misunderstood what is going on or have missed a step out. The exposed run function is being called but the first line that calls $ throws the error:
ReferenceError: Can't find variable: $
So my questions are:
What have I got wrong in my thinking?
(or) What am I doing incorrectly?
What should I be doing in order to preload and make available
frequently referenced libraries so that I do not need to require and
define them in every file I have?
As far as I understood I should not need to require the files I already mentioned in the require config, I thought they should be loaded and available to this code.
You misunderstood how RequireJS works. You should read the documentation from start to finish. For now, here are things you should change.
You should require jquery in your MainApp module:
define(function(require) {
var $ = require("jquery");
You should remove your shims that you have for jquery, underscore and backbone as they all call define and shim is only for code that does not call define. I don't know what TestApp is but if it is your own code, you really should make it into a proper AMD module and remove the shim.
#Louis has made me realise the error in what I was doing above. Changing the shim in TestApp.js so that is reads:
MainApp: {
deps: ['backbone'],
exports: 'MainApp'
}
Corrected the problem, now Backbone, $ and _ are all available to the rest of my application code without cluttering up each files require. i.e. I do not need to begin every file with:
define (['lib/jquery', 'lib/loadash', 'lib/backbone'], function($, _ , Backbone) {
Given in my actual app the list of common deps is quite large this means I only need to define locally used resources and can control the paths from a single location.
fter including require tag the application is behaving abnormal way .is there any way i can bootstrap my application apart from below code .
main.js
require(['/module.js'], function() {
angular.element(document).ready(function () {
angular.bootstrap(document, ['myApp']);
});
});
When I written as single file js file the code is working properly.
module.js
var name = 'myApp';
angular.module(name, [])
.controller('Controller', require(['controller.js']))
.factory('Service', require(['service.js']))
.filter('Number', require(['filter.js']));
I have included my main.js in index.html . index html has 3 views i am displaying them based on ng-show from index.html.
The problem is module.js loading properly and js files too. Script is not executing properly so that my entire index.html page including 3 views displayed automatically with error messages.
Control is not going to controller.js/service.js
Error :
Error: Unknown provider: depsProvider <- deps .
Did i miss any define code? Thanks in advance
Angular does not support AMD by default, You need to config angular to export angular object. Please check out the this post for more details.
require.config({
paths: {
'angular': '../lib/angular/angular'
},
shim: {
'angular': {
exports: 'angular'
}
}
});
Your module.js should be defined with define method of requirejs and it should return module.
You can omit file extesion (.js) while using requireJs
My program starts through this entry point in a twig template:
<script data-main="{{ asset('bundles/wwwcms/js/app') }}" src="{{ asset('bundles/wwwcms/js/require.js') }}"></script>
This outputs:
<script data-main="static.correct_require_url.net/js/app" src="static.correct_require_url/require.js"></script>
That all works fine, so require executes my app.js (config):
requirejs.config({
'baseUrl': 'js/lib',
'paths': {
'app': '../app',
'jquery': '//code.jquery.com/jquery-1.10.2.min',
'bootstrap': '//netdna.bootstrapcdn.com/bootstrap/3.0.2/js/bootstrap.min'
},
'shim': {
'bootstrap': {
deps: ['jquery']
}
}
});
// always require jquery and bootstrap onload
requirejs(['bootstrap']);
Which also works.
The directory structure is as follows:
app.js
require.js
/lib
- test.js
/app
- dirty.js
- import.js
Okay so here is where the error comes
For a page, let's say I want to load dirty.js and import.js. dirty.js depends on jquery, and import.js depends on "test.js" (something I just made up for demonstration purposes).
So I load the dependencies on the page this way:
<script type="text/javascript">
require(['app/dirty', 'app/import']);
</script>
When the page loads, dirty.js and import.js are loaded in just fine, from the correct url relative to "app". However, the dependency for import.js (test.js) does not get loaded correctly.
This is how import.js starts:
require(['jquery', 'test'], function($, test) {
...
});
As you can see, it's asking for lib/test.js. It pulls jQuery from a CDN, so that's taken care of. But for test.js, it uses the wrong path.
import.js (and all other modules loaded first) are pulled in using the correct static url path, but dependencies for modules are loaded using the wrong path- they are loaded using the url of that page!
So when I look at the network tab in the debugger console, import.js comes from:
static.blahblah.com/js/app/import.js.
but test.js comes from:
blahblah.com/route/to/current/page/js/app/test.js
(which obviously 404s every time)
What are possible reasons for this occurring? Am I doing something wrong? Any help would be greatly appreciated.
This is how the script tags look before require runs:
<script data-main="//static.bananajams.cloud.net/bundles/wwwcms/js/app" src="//static.bananajams.cloud.net/bundles/wwwcms/js/require.js"></script>
<script type="text/javascript">
require(['app/dirty', 'app/preview', 'app/import']);
</script>
Basically data-main is only a good idea if it's the single entry point for your code. It's loaded asynchronously, so there is no guarantees it runs before the other code in your app. See
RequireJS does not run data-main script before loading required modules
for more info on this.
I’m developing a multi-page app, using requirejs to manage my javascript libs / dependencies.
My idea is that i'll have a main.js that holds the config, and then an .js file for each page that needs it, for example "register.js"
My require config is in javascripts/main.js
requirejs.config({
baseUrl: '/javascripts',
waitSeconds: 200,
paths: {
'async': 'lib/require.async',
'jquery': 'lib/jquery-1.7.2.min',
'knockout': 'lib/knockout-3.0.0'
});
I’ve got a knockout view model that looks like this:
javascripts/viewModels/userDetailsViewModel.js
define(['knockout'], function(ko) {
return function() {
var self = this;
self.name = ko.observable();
self.email = ko.observable();
});
My ‘entry point’ is javascripts/register.js
require(['./main', 'knockout', 'viewModels/userDetailsViewModel'], function(main, ko, userDetailsViewModel) {
ko.applyBindings(new userDetailsViewModel());
});
On my register.html page, i’ve got the script reference like this:
<script data-main="/javascripts/register" src="/javascripts/lib/require.js"></script>
When my page loads, I get these errors in the console:
GET http://localhost:3000/javascripts/knockout.js 404 (Not Found)
and
Uncaught Error: Script error for: knockout
I’m not sure why it’s looking for knockout.js - I’ve specified knockout in the paths section of my config, to look in lib/knockout-3.0.0
My dir structure is:
javascripts/
Most of my pages js files go here
javascripts/viewModels
Has knockout viewmodels
javascripts/lib
Contains knockout, jquery, requirejs etc...
The problem is that RequireJS will execute the call require(['./main', 'knockout', 'viewModels/userDetailsViewModel'] without a configuration. Yes, ./main is listed before knockout but there is no order guarantee between the dependencies passed in a single require call. RequireJS may load ./main first, or knockout first. And even if ./main were loaded first by this specific call, I believe it would not have any impact on how the other modules loaded by this call would load. That is, I think this require would operate on the basis of the configuration that existed at the time it was called, and that any configuration changes caused by the modules it loads would take effect only for subsequent require calls.
There are many ways to fix this. This should work:
require(['./main', function(main) {
require(['knockout', 'viewModels/userDetailsViewModel'], function(ko, userDetailsViewModel) {
ko.applyBindings(new userDetailsViewModel());
});
});
Or you might want to restructure your files and what you pass to data-main so that your requirejs.config is loaded and executed before your first require call. Here's an example of restructuring. Change your entry point to be /javascripts/main.js:
<script data-main="/javascripts/main.js" src="/javascripts/lib/require.js"></script>
Change /javascripts/main.js so that it contains:
requirejs.config({
baseUrl: '/javascripts',
waitSeconds: 200,
paths: {
'async': 'lib/require.async',
'jquery': 'lib/jquery-1.7.2.min',
'knockout': 'lib/knockout-3.0.0'
});
require(['knockout', 'viewModels/userDetailsViewModel'], function(ko, userDetailsViewModel) {
ko.applyBindings(new userDetailsViewModel());
});
And remove /javascripts/register.js. This would be one way to do it. However, it is hard for me to tell whether this would be what you want in your specific project, because I do not know the whole project. The way to restructure for your specific project really depends on what other pages might use RequireJS, what information is common to all pages, what is specific to each page, whether you use a template system to produce HTML, etc.
I'm learning Requirejs and I started with two simple .html pages: index.html and second.html.
On the index.html I worte:
<script data-main="assets/js/app.min" src="js/vendor/require.js"></script>
The app.min.js file look like this:
requirejs.config({
baseUrl: 'js/vendor',
paths: {
app: '../app',
jquery: 'jquery-1.10.1.min'
}
});
requirejs(["app/main"]);
My app/main.js file has just a jQuery alert:
define(['jquery'], function($) {
$(function() {
alert('Hello World');
});
});
It works fine!
Now I'm worried just about one thing... What about if I need to load the app/main globally for all my pages and then another file like app/second that run only on second.html page?
Probably I'm missing something about Requirejs... I don't thinks that I need to load everything on the app.min.js file like did for the app/main.
I understand that I can define modules on separate js files but then how can I manage different files for different pages without loading everything in just one file? Probably I'm wrong, I hope you can open the light in my brain for that.
Thanks
I understand that a page might need its own code in addition to what is in app.min. You could do something like this:
<script data-main="assets/js/app.min" src="js/vendor/require.js"></script>
<script>
// You can call the config function as many times as you need to add new configuration.
requirejs.config({
// Presumably, baseUrl does not need to be changed.
// baseUrl: 'js/vendor',
paths: {
// additional paths you may need
}
});
// This loads the code proper to this page.
requirejs(["app/second"]);
</script>
If app/second depends on app/main make sure to have that dependency listed in app/second's define call.
Take a look at this example: https://github.com/requirejs/example-multipage. The example demonstrates how you can create page1.js and page2.js and in those files load the common stuff + page specific things. That's one of several ways to do it.
Another way to do which is what I often use is putting something like this in all your pages:
<script src="require.js"></script> <!-- just require -->
<script src="app.min.js"></script> <!-- your config and also loading the main module -->
and then on second.html, you would also add this
<script>require(["app/second"])</script>
You can use this setup for development, and for production you can replace the first 2 lines with just <script src="optimized-bundle.js"></script>. The optimized-bundle.js could include require.js + config + app/main + app/second. Or if you want to load app/second only on the second.html in production to make your main script smaller, you can have require.js + config + app/main in the primary bundle and optimize app/second into a separate bundle - the html would stay the same in both cases.
Hope this helps.