I'm using Webjars to import AngularJS into my web project.
For some reason the minified version of AngularJS won't be served even though I'm referencing those in my main. I was expecting to see angular.min.js and angular-route.min.js being loaded, but I'm seeing the regular angular.js and angular-route.js. What am I doing wrong here?
My main.js:
'use strict';
requirejs.config({
paths: {
'angular': '../lib/angularjs/angular.min',
'angular-route': '../lib/angularjs/angular-route.min',
'async': '../lib/requirejs-plugins/src/async'
},
shim: {
'angular': {
exports : 'angular'
},
'angular-route': {
deps: ['angular'],
exports : 'angular'
}
}
});
require(['angular', './controllers', './directives', './filters', './services', 'angular-route','./places-autocomplete','async','./gmaps'],
function(angular, controllers) {
initialize();
// Declare app level module which depends on filters, and services
angular.module('myApp', ['myApp.filters', 'myApp.services', 'myApp.directives', 'ngRoute']).
config(['$routeProvider', function($routeProvider) {
....
}]);
angular.bootstrap(document, ['myApp']);
});
My html loads requirejs like this:
<script>
#Html(org.webjars.RequireJS.getSetupJavaScript(routes.WebJarAssets.at("").url))
</script>
<script data-main="#routes.Assets.versioned("javascripts/main.js")"
src="#routes.WebJarAssets.at(WebJarAssets.locate("require.min.js"))"></script>
and the above requirejs.config snippet resides in main.js
I looked into the sources of requirejs. Here's what I found:
requirejs splits each path, you defined in the config object, into its components (i.e. the directories, the filename and the extension). For some reason (node module naming conventions) the last extension is dropped. They do not check if that's a '.js'. Then this path array is used to access a module. Without a plugin rquirejs only handles .js files. It adds a .js if nessecary.
Now you can see what happens in your example. In the first step requirejs drops the .min extension. When it loads the module it joins the path components and adds a .js to the end. Then it loads the full module and not the minified version.
If you add a .js to your paths, then this .js was dropped and the .min is still there.
Try to add
enforceDefine: true,
Related
As we know, when use RequireJS in the configuration file we must define 'paths' and 'shim'. When writing tests (Karma, Jasmine), we need to create an additional configuration file for RequireJS and re-define the same data.
I try to extract common parts and load them dynamically. In Angular JS application, everything works without problems, but in test i have always error '404'. But let's get to the beginning. Simple example structure:
.
|-- newApp
| |-- app
| | `-- app.require.js
| |-- newApp.require.js
| `-- index.html
`-- test
|-- test.karma.js
`-- test.require.js
index.html load RequireJS config file
<script data-main="newApp.require.js" src="bower_components/requirejs/require.js"></script>
newApp.require.js init RequireJS
require([
'app/app.require'
], function (appRequire) {
"use strict";
require.config({
baseUrl: 'app',
paths: appRequire.paths,
shim: appRequire.shim,
deps: [
'NewAppBootstrap'
]
});
});
app.require.js Module / object with paths and shim
define([
'some/others/components.require'
], function (componentsRequire) {
"use strict";
var appRequire = {
'NewApp': 'app.module',
'NewAppBootstrap': 'app.bootstrap',
'NewAppRoute': 'app.routes'
};
var vendorRequire = {
'jQuery': {
exports: '$'
},
'angular': {
exports: 'angular'
}
};
return {
paths: Object.assign(
appRequire,
componentsRequire
),
shim: vendorRequire
};
});
Up to this point everything works fine. Now I would like to file app.require.js load into test.require.js. And the problems begin...
test.require.js
var TEST_REGEXP = /(spec|test)\.js$/i;
var allTestFiles = [];
Object.keys(window.__karma__.files).forEach(function (file) {
'use strict';
if (TEST_REGEXP.test(file)) {
var normalizedTestModule = file.replace(/^\/base\/|\.js$/g, '');
allTestFiles.push(normalizedTestModule);
}
});
require([
'app/app.require'
], function (appRequire) {
"use strict";
require.config({
baseUrl: '/base/newApp',
waitSeconds: 200,
paths: appRequire.paths,
shim: appRequire.shim,
deps: allTestFiles,
callback: window.__karma__.start
});
});
Unfortunately, I still have error:
WARN [web-server]: 404: /app/app.require.js
PhantomJS 2.1.1 (Linux 0.0.0) ERROR: 'There is no timestamp for app/app.require.js!'
PhantomJS 2.1.1 (Linux 0.0.0) ERROR
Error: Script error for "app/app.require"
http://requirejs.org/docs/errors.html#scripterror at node_modules/requirejs/require.js:143
I tried different paths, but still nothing. Does anyone know how to load this file? Whether it is at all possible load file in this place? I would be grateful for any tips.
By the time your code hits this require call:
require([
'app/app.require'
],
There is no RequireJS configuration in effect, and data-main is not used, so by default RequireJS takes the directory that contains the HTML page that loads RequireJS as the baseUrl (See the documentation.) Since index.html sits at the root, then RequireJS resolves your module name to /app/app.require.js and does not find it.
You can work around it by using a full path:
require([
'base/newApp/app/app.require'
],
Or if it so happens that other code later is going to try to access this same module as app/app.require, then you should have a minimal configuration before your first require call:
require.config({
baseUrl: '/base/newApp',
});
It is perfectly fine to call require.config multiple times. Subsequent calls will override values that are atomic (like baseUrl) and marge values that can be merged. (An example of the latter would be paths. If the first call sets a paths for the module foo and a 2nd call sets a paths for the module bar, then the resulting configuration will have paths for both foo and bar.)
I have src of my application. I use AngularJS. I use RequireJS as module loader. I use Grunt as task runner. When I run application using src: everything is good. When I build application with Grunt, application is not working. I got no errors in console.
Main thing I noticed: my code (code of my application: app.js and files under js/) does not appear in output file which is set in grunt task settings. Also, I don't think there is something about AngularJS.
Main config file:
require.config({
paths: {
'angular' : '../components/angular/angular',
/* etc..... */
'jquery': '../components/jquery/dist/jquery',
'application': './app'
},
shim: {
/* etc */
application: {
deps: ['angular']
},
angular: {
exports : 'angular'
}
},
baseUrl: '/js'
});
require(['application', 'angular', 'ngRoute', 'bootstrap' /* ngRoute and bootstrap from etc :) */], function (app) {
app.init();
});
My app in app.js is:
define([
'require', 'angular', 'main/main', 'common/common'
], function (require) {
'use strict';
var angular = require('angular');
var app = angular.module('myApp', ['ngRoute', 'main', 'common']);
app.init = function () {
angular.bootstrap(document, ['myApp']);
};
app.config(['$routeProvider',
function ($routeProvider) {
$routeProvider
./* ... some code */
}
]);
return app;
});
I add main RequireJS config file at the end of body tag:
<script type="text/javascript" src="components/requirejs/require.js" data-main="js/bootstrap.js"></script>
Now I have problem. I have Grunt as build system. I have this task:
grunt.initConfig({
requirejs: {
compile: {
options: {
baseUrl: "public/js",
mainConfigFile: "public/js/bootstrap.js",
name: 'bootstrap',
out: "build/js/bootstrap.js",
optimize: 'none'
}
}
},
// etc
I have no optimisation, so I get ~11k lines of code in output file.
As I said. Main problem is: no AngularJS code and no application code in output file.
Why? I set up mainConfigFile correctly. Problem is in RequireJS config file? But everything is okay, when I am running my app on src.
It would be better if you can provide the exactly error output you get. And where you got it (from browser's console or from terminal during build process)
For now I will suggest some adjustments what could possibly help with your case.
angular: {
exports : 'angular'
}
Here you have already export angular.js into global local variable (inside every require and define block).
And by doing var angular = require('angular'); you are possibly asynchronously override angular variable inside your app.js module.
For 'require' being added into define block, as r.js always reading what module got to be loaded in very first step, and then merged into single file. And this may confuse r.js to merging requireJS into itself.
Suggest this adjustment for your app.js:
define([ // Removed 'require' because no needed , it is already global and usable anywhere
'angular', 'main/main', 'common/common'
], function () {
'use strict';
// var angular = require('angular'); // This is a very common mistake. You are not going to call angular this way, requireJS difference with commonJS.
var app = angular.module('myApp', ['ngRoute', 'main', 'common']);
app.init = function () {
angular.bootstrap(document, ['myApp']);
};
app.config(['$routeProvider',
function ($routeProvider) {
$routeProvider
./* ... some code */
}
]);
return app;
});
And last but not least data-main="js/bootstrap.js" I think it should be js/main.js or a typo.
EDIT added explanations for 'require' in define block, and angular local variable.
I do a grunt serve:dist and within I build with grunt-contrib-requirejs an all.js file based on my RequireJS main.js file which have require.config and a require section.
I think all.js should be in my distribution that file which I have to include on startup in my index.html, because everything is in there. Is this right?
<script src="require.js" data-main="all.js"></script>
I also create based on all my template HTML files a template JavaScript file with ngTemplates and bootstrap it so the template file named templates.js looks like this:
define([
'angular'
], function(angular) {
angular.module('MyApp.templates', []).run(['$templateCache', function($templateCache) {
'use strict';
$templateCache.put('templates/MyTest.html',
"<h1>Title</h1>\r" +
// ...
// other put on $templateCache
}]);
});
So I have a $templateCache which I want to use. But I do not how this can be done. I think I have to load the templates.js because it is not included in all.js and therefore I should inject it in some way.
I had similar issue and I found a way to solve it.
Basically, I have templates.js to return just a function to inject to run block.
For example: templates.js
define([], function()){
return ['$templateCache", function($templateCache){
'use strict';
$templateCache.put('templates/MyTest.html',
"<h1>Title</h1>\r" +
// ...
// other put on $templateCache
}];
}
and then, in your app.js file, you can inject this function into run block
define(['templates'], function(templates){
angular.module('app')
.run(templates);
})
I hope this helped, please let me know if you are not clear with something.
I was under the impression that the RequireJS Optimizer would look through the defined dependencies and gather up all of the referenced js files in an application and bundle them up into a single, large js file.
You'd then be able to reference that single file in your html script include.
But this doesn't seem to be the case. When I run this, I get a large file, but it includes the original main.js file that includes paths to files in a directory structure.
What is the point of that? Why does the new large file contain paths outside of itself if everything needed is contained within? It seems like the optimizer would rewrite the paths to point to "./" or something.
When I bundle up the entire app and reference that in the page, I'm getting errors about missing files that ARE included in the large js file:
Uncaught object require.js:70
GET http://localhost/ui/js/modules/mod_limeLight.js 404 (Not Found) require.js:729
Uncaught Error: Script error for: mod_limelight
http://requirejs.org/docs/errors.html#scripterror
build.js:
({
baseUrl: "./src/ui/scripts",
name: "main",
mainConfigFile : "src/ui/scripts/main.js",
out: "dist/ui/scripts/main-built.js"
})
main.js
'use strict';
require.config({
"paths": {
"jquery": "libs/jquery-1.11.0.min",
"twitter_bootstrap": "../bower_components/bootstrap/dist/js/bootstrap.min",
"respondjs": "../bower_components/respond/dest/respond.min",
"debouncejs": "libs/dw-debounce",
"carousel": "libs/jquery.carouFredSel-6.2.1-packed",
"swipe": "libs/jquery.touchSwipe.min",
"app": "app",
"OOo_config": 'libs/oo_conf_entry-ck', // Opinion Lab pop-up
//modules
"addthis": "//s7.addthis.com/js/300/addthis_widget",
"mod_addThis": "modules/mod_AddThis",
"limelight": "//assets.delvenetworks.com/player/embed",
"mod_limelight": "modules/mod_limeLight"
},
"shim": {
"twitter_bootstrap": ["jquery"],
"carousel": ["jquery"],
"swipe": ["jquery"],
"packeryjs": ["jquery"]
}
});
require([
"jquery",
"app",
"OOo_config",
"respondjs",
"mod_addThis",
"mod_limelight"
], function ($, app) {
app.init();
});
example module starts off like:
define([
"jquery", "debouncejs", "limelight"
],
function ($) {
'use strict';
var playerElement = ...
});
Then running:
node r.js -o build.js
What am I missing? Why is it trying to fetch files that are contained in that large js file?
Thanks,
Scott
It identifies the included modules using their usual paths, because that’s simple and unambiguous, and it works. The files aren’t fetched, of course.
I'm having pretty simple directory structure for scripts:
/js/ <-- located in site root
libs/
jquery-1.10.1.min.js
knockout-2.2.1.js
knockout.mapping.js
models/
model-one.js
model-two.js
...
require.js
config.js
Since the site engine uses clean URLs I'm using absolute paths in <script>:
<script type="text/javascript" data-main="/js/config.js" src="/js/require.js"></script>
RequireJS config:
requirejs.config({
baseUrl: "/js/libs",
paths: {
"jquery": "jquery-1.10.1.min",
"knockout": "knockout-2.2.1",
"komapping": "knockout.mapping"
}
});
Somewhere in HTML:
require(["jquery", "knockout", "komapping"], function($, ko, mapping){
// ...
});
So the problem is that RequireJS completely ignores baseUrl and paths defined in config file. I get 404 error for every module required in the code below. I see in browser console that RequireJS tries to load these modules from /js/ without any path translations:
404: http://localhost/js/jquery.js
404: http://localhost/js/knockout.js
404: http://localhost/js/komapping.js
However after the page is loaded and the errors are shown I type in console and...
> require.toUrl("jquery")
"/js/libs/jquery-1.10.1.min"
Why so? How to solve this problem?
It's my first experience using RequireJS, so I'm feeling like I've skipped something very simple and obvious. Help, please.
Update
Just discovered this question: Require.js ignoring baseUrl
It's definitely my case. I see in my Network panel that config.js is not completely loaded before require(...) fires own dependency loading.
But I don't want to place my require(...) in config because it is very specific for the page that calls it. I've never noticed such problem with asynchronicity in any example seen before. How do authors of these examples keep them working?
Solved.
The problem was that config file defined in data-main attribute is loaded asynchronously just like other dependencies. So my config.js accidentally was never completely loaded and executed before require call.
The solution is described in official RequireJS API: http://requirejs.org/docs/api.html#config
... Also, you can define the config object as the global variable require before require.js is loaded, and have the values applied automatically.
So I've just changed my config.js to define global require hash with proper configuration:
var require = {
baseUrl: "/js/libs",
paths: {
"jquery": "jquery-1.10.1.min",
"knockout": "knockout-2.2.1",
"komapping": "knockout.mapping"
}
};
and included it just BEFORE require.js:
<script type="text/javascript" src="/js/config.js"></script>
<script type="text/javascript" src="/js/require.js"></script>
This approach allows to control script execution order, so config.js will always be loaded before next require calls.
All works perfectly now.
Fixed the issue.
My config was being loaded asynchronously, and therefore the config paths weren't set before my require statement was being called.
As per the RequireJS docs Link here, I added a script call to my config before the require.js call. And removed the data-main attribute.
var require = {
baseUrl: '/js',
paths: {
'jquery': 'vendor/jquery/jquery-2.0.3.min',
'picker': 'vendor/pickadate/picker.min',
'pickadate': 'vendor/pickadate/picker.date.min'
},
shim: {
'jquery': {
exports: '$'
},
'picker': ['jquery'],
'pickadate': {
deps: ['jquery', 'picker'],
exports: 'DatePicker'
}
}
}
All is now working