Requirejs optimizer with angularjs - javascript

I am trying to make a sample application using angularjs, ui-router and requirejs to lazyload my controllers. It works good locally but I want to write requirejs optimizer for production environment, Tried using grunt:requirejs tool for this but it didnt work for me. It doesnt even give any script loading error or something..
<--index.html--!>
<!DOCTYPE html>
<html style="overflow-x:hidden">
<head>
</head>
<body class="no-padding">
<div data-ui-view="header"></div>
<div data-ui-view="module"></div>
<script data-main="app/main" src="bower_components/requirejs/require.js"></script>
</body>
</html>
//main.js
require.config({
baseUrl: "",
// Paths for just the core application and its controllers/factories/services
paths: {
"jquery": "bower_components/jquery/dist/jquery",
"angular": "bower_components/angular/angular.min",
"angular-ui-router": "bower_components/angular-ui-router/release/angular-ui-router.min",
"app": "app/app",
"underscore": "node_modules/underscore/underscore-min",
},
shim: {
//Tell requirejs to pipe in angular"s return variable as "angular"
"angular": {
exports: "angular"
},
},
// Say we have a dep on App, so it gets loaded
deps: ["app", 'lib']
});
//lib.js
define([
'jquery',
'underscore',
], function($){
});
//app.js
define([
'angular',
'angular-ui-router'
], function(){
var app = angular.module('app', ['ui.router']);
//lazy loading
var loadController = function(path){
return ['$q', function($q){
var defered = $q.defer();
require([path], function(){
defered.resolve();
});
return defered.promise;
}]
};
app.config(['$controllerProvider', function($controllerProvider){
app.registerController = $controllerProvider.register;
}]);
app.config(['$stateProvider', function($stateProvider){
//registering controller
// defining states
$stateProvider.state('app', {
url: '/',
views: {
'header':{
templateUrl:"<div>{{title}}</div>",
controller:"appCtrl"
},
'module':{
template:"<div>{{title}}</div>",
controller:"homeCtrl"
}
},
resolve: {
loadApp: loadController('../app/controllers/header'),
loadHome: loadController('../app/controllers/home')
}
});
}]);
angular.bootstrap(document, ['app']);
return app;
});
//home.js
define(function(){
angular.module('app').registerController('homeCtrl', ['$scope', '$state', function($scope,$state){
$scope.title = 'CONTENT';
}]);
});
//header.js
define(function(){
angular.module('app').registerController('appCtrl', ['$scope', '$state', function($scope,$state){
$scope.title = 'HEADER';
}]);
});
I was using grunt:requirejs task to compile an optimized dist file "main.js" and grunt copy for modified index.html inside dist directory:
grunt:requirejs and modified index.html -->
grunt.initConfig({
//...
requirejs: {
compile: {
options: {
name: 'node_modules/almond/almond',
mainConfigFile: 'app/main.js',
out: 'dist/main_opt.js',
baseUrl: './'
}
}
},
//...
})
<--dist/index.html--!>
<!DOCTYPE html>
<html style="overflow-x:hidden">
<head>
</head>
<body class="no-padding">
<div data-ui-view="header"></div>
<div data-ui-view="module"></div>
<script src='bower_components/requirejs/require.js'></script>
<script>
require.config({
paths: {
//Comment out this line to go back to loading
//the non-optimized main.js source file.
"main_opt": "dist/main_opt"
}
});
require(["main_opt"]);
</script>
</body>
</html>
When loading dist/index.html it gives me nothing, no error in browser, just doesnt work, if it was giving me script loading error for controllers it might have made any sense but its not. Completely clueless here..

There is nothing required in main.js file. You must require at least one of files declared in paths. Do it as follow:
require(['app'], function () {
console.log('app required successfully');
});
Put this lines of code in your main.js file. I hope it may help to find errors:
requirejs.onError = function (err) {
console.error('[require error] type: ', err.requireType, ' ,modules: ' + err.requireModules);
throw err;
};

Related

I am trying to bootstrap angularjs and Requirejs,but I always end up with dependency injection error [duplicate]

This question already has answers here:
AngularJS cannot find module with latest RequireJS
(2 answers)
Closed 6 years ago.
Actually I have been trying to develop a single page application using requirejs and angularjs. I have loaded all files that are necessary,while running the app without any other angular apps and without dependencies everything works fine,but when I call the requirejs definedjs files to load within the define() in app.js the application throws the following error,
[$injector:nomod] Module 'app' is not available! You either
misspelled the module name or forgot to load it. If registering a
module ensure that you specify the dependencies as the second
argument.
Here is my html
<!DOCTYPE html>
<html ng-app="app">
<head>
<meta charset="UTF-8">
<base href="/">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Advances in Central Science</title>
<link rel="icon" href="assets/images/favicon.ico" type="image/x-icon">
<!-- Requirejs -->
<script data-main="client/js/main" src="client/bower_libs/requirejs/require.js"></script>
</head>
<body>
<div ng-controller="mainCtrl">
<h1>{{message}}</h1>
<button class="btn btn-success">Success</button>
</div>
</body>
</html>
My Requirejs
// requirejs
require.config({
baseUrl: '/',
paths: {
// Aliases and paths of modules
'angular': 'client/bower_libs/angular/angular',
'uiRouter': 'client/bower_libs/angular-ui-router/release/angular-ui-router.min',
'bootstrap': 'client/bower_libs/bootstrap/dist/js/bootstrap.min',
'jquery': 'client/bower_libs/jquery/dist/jquery.min',
// paths
'app': 'client/js/app',
'includesjs': 'client/js/includesjs',
'includescss': 'client/js/includescss',
'modules': 'client/js/controllers/main'
},
map: {
// Maps
'*': {
'css': 'client/bower_libs/require-css/css.min.js'
}
},
shim: {
// Modules and their dependent modules
'angular': { exports: 'angular' },
'uiRouter': { deps: ['angular'] },
'bootstrap': { deps: ['jquery'] }
},
// kick start application
deps: ['client/js/initialize']
});
Initialize.js
define(['app', 'includesjs'], function() {
return true;
})
app.js(I cant get what I am doing wrong here)
=========working
define(['angular'], function(angular) {
var app = angular.module('app', []);
return app;
=========not Working
define(['angular','uiRouter'], function(angular) {
var app = angular.module('app', ['ui.router']);
return app;
});
includes.js
define([
'modules/mainCtrl'
], function() {
return true;
});
mainController.js
define(['app'], function(app) {
app.controller('mainCtrl', function($scope) {
$scope.message = "Hello,the page works like a charm";
})
});
I think you only need to define the uiRouter while defining the angular.
Try something like this.
define(['angular'], function(angular) {
var app = angular.module('app', ['ui.router']);
return app;
Its because you only need to define the dependencies on module level. Not on angular framework level. Hope that solves your issue

File Hashing using AngularJS

I am currently working on a Angualar JS project based on angularAMD.
Link: http://marcoslin.github.io/angularAMD/#/home
Here we include only the necessary dependent files in needed by the controllers and not all the files.
eg.
define(['angularAMD', 'common/services/service1', 'module1/services/service2',], function (angularAMD) {
'use strict';
angularAMD.controller('abcController', function ($scope, service1, service2) {
// controller code goes here
}
I have tried Grunt Hashing but
Grunt provides hashing but the location of the hashed files changes.
This does not change the path of the files inside individual controller as a result the application fails to run. i.e service1, service2
Question
I was wondering if there was a way to hash the files when we include a new files?
Is there any other way to solve this problem?
Thanks in Advance
how do u set up your modules. Your main.js may look like this
'use strict';
require.config({
waitSeconds: 0,
urlArgs: "bust=v1.0.0",
paths: {
bootstrap: 'Scripts/bootstrap.min',
jquery: 'Scripts/jquery-1.10.2.min',
angular: 'Scripts/angular.min',
angularRoute: 'Scripts/angular-route.min',
angularAMD: 'Scripts/angularAMD.min',
app: 'ngApp/app',
appConfig: 'ngApp/app.config',
/*register Services - Start*/
service1: 'ngServices/Common/service1',
service2: 'ngServices/module/service2',
/*register Services - End*/
/*register Filters - Start*/
/*register Filters - End*/
/*register Controllers - Start*/
/*register Controllers - End*/
},
// specifying library dependencies
shim: {
'bootstrap':{ deps:['jquery']},
'angular': { deps: ['jquery'], exports: 'angular' },
'angularRoute': { deps: ['angular'] },
'angularAMD': { deps: ['angular'] }
},
// define application bootstrap
deps: ['app']
});
and in your index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1">
</head>
<body data-ng-controller="appController as appCtrl" ng-cloak>
<div >
<ng-view></ng-view>
</div>
</div>
<script data-main="main" src="Scripts/require.js"></script>
</body>
</html>
and in your controllers
'use strict';
define(['angularAMD', 'service1', 'service2'],
function (angularAMD) {
angularAMD.controller('abcController', ['service1', 'service2',
function (service1, service1) {
var self = this,
// your code
}]);
});

Obfuscating js files with grunt-obfuscator: Uncaught ReferenceError: require is not defined

I was searching over the internet about how to obfuscate my JavaScript code and after use uglify that convert all my files minified but not obfuscated I decided to use grunt-obfuscator
After make this configuration on my simple project:
Gruntfile.js
module.exports = function (grunt) {
grunt.loadNpmTasks('grunt-obfuscator');
grunt.initConfig({
connect: {
server: {
options: {
port: 9000,
base: 'app/'
}
}
},
watch: {
project: {
files: ['app/**/*.js', 'app/**/*.html', 'app/**/*.json', 'app/**/*.css'],
options: {
livereload: true
}
}
},
obfuscator: {
files: [
'app/js/app.js',
'app/js/controllers.js'
],
entry: 'app/js/app.js',
out: 'app/js/obfuscated.js',
strings: true,
root: __dirname
}
});
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.registerTask('default', ['obfuscator', 'connect', 'watch']);
};
My app.js
(function () {
var app = angular.module('myapp', [
'ngRoute',
'myapp.controllers'
]);
app.config(['$routeProvider', function ($routeProvider) {
$routeProvider
.when('/', {
templateUrl: 'views/home.html'
})
.otherwise({
redirectTo: '/'
});
}]);
})();
My controller.js
(function() {
angular.module('myapp.controllers', [])
.controller('AppController', ['$scope',
function ($scope) {
$scope.name = "Test123";
}]);
})();
After execute grunt my obfuscated.js is really hard to read, which is really great. So I'm enter to my localhost which is loading now the obfuscated.js file but I'm getting this error:
Uncaught ReferenceError: require is not defined
What am I missing?
My obfuscated.js
!function(a,b){function c(b,d){var e,f;if("\x2e"!=b[0]&&"\x2f"!=b[0])return a(b);if(d=d||"\x72\x6f\x6f\x74",e=c.resolve(b),!e&&/\.json$/i.test(b))return a("\x2e\x2f"+c.basename(b));if(f=c.cache[e],!f)try{return a(b)}catch(g){throw Error("\x66\x61\x69\x6c\x65\x64\x20\x74\x6f\x20\x72\x65\x71\x75\x69\x72\x65\x20\x22"+b+"\x22\x20\x66\x72\x6f\x6d\x20"+d+"\n"+g.message+"\n"+g.stack)}return f.exports||(f.exports={},f.call(f.exports,f,f.exports,c.relative(e))),f.exports}c.cache={},c.basename=a("\x70\x61\x74\x68").basename,c.resolve=function(b){var d,e,f;if("\x2e"!=b[0])return a.resolve(b);for(d=[b,b+"\x2e\x6a\x73",b+"\x2f\x69\x6e\x64\x65\x78\x2e\x6a\x73",b+"\x2e\x6a\x73\x6f\x6e",b+"\x2f\x69\x6e\x64\x65\x78\x2e\x6a\x73\x6f\x6e"],e=0;f=d[e];e++)if(c.cache[f])return f},c.register=function(a,b){c.cache[a]=b},c.relative=function(a){function b(b){var d,e,f,g,h;if("\x2e"!=b[0])return c(b);for(d=a.split("\x2f"),e=b.split("\x2f"),d.pop(),f=0,g=e.length;g>f;f+=1)h=e[f],"\x2e\x2e"==h?d.pop():"\x2e"!=h&&d.push(h);return c(d.join("\x2f"),a)}return b.resolve=c.resolve,b.cache=c.cache,b},c.register("\x2e\x2f\x61\x70\x70\x2f\x6a\x73\x2f\x61\x70\x70\x2e\x6a\x73",function(a,b,c){!function(){var a=angular.module("\x6d\x79\x61\x70\x70",["\x6e\x67\x52\x6f\x75\x74\x65","\x6d\x79\x61\x70\x70\x2e\x63\x6f\x6e\x74\x72\x6f\x6c\x6c\x65\x72\x73"]);a.config(["\x24\x72\x6f\x75\x74\x65\x50\x72\x6f\x76\x69\x64\x65\x72",function(a){a.when("\x2f",{templateUrl:"\x76\x69\x65\x77\x73\x2f\x68\x6f\x6d\x65\x2e\x68\x74\x6d\x6c"}).otherwise({redirectTo:"\x2f"})}]),c.extensions["\x2e\x73\x65\x72\x76\x65\x72\x2e\x63\x6f\x6e\x74\x72\x6f\x6c\x6c\x65\x72\x2e\x6a\x73"]=c.extensions["\x2e\x6a\x73"],c.extensions["\x2e\x73\x65\x72\x76\x65\x72\x2e\x6d\x6f\x64\x65\x6c\x2e\x6a\x73"]=c.extensions["\x2e\x6a\x73"],c.extensions["\x2e\x73\x65\x72\x76\x65\x72\x2e\x72\x6f\x75\x74\x65\x73\x2e\x6a\x73"]=c.extensions["\x2e\x6a\x73"]}()}),c.register("\x2e\x2f\x61\x70\x70\x2f\x6a\x73\x2f\x63\x6f\x6e\x74\x72\x6f\x6c\x6c\x65\x72\x73\x2e\x6a\x73",function(){!function(){angular.module("\x6d\x79\x61\x70\x70\x2e\x63\x6f\x6e\x74\x72\x6f\x6c\x6c\x65\x72\x73",[]).controller("\x41\x70\x70\x43\x6f\x6e\x74\x72\x6f\x6c\x6c\x65\x72",["\x24\x73\x63\x6f\x70\x65",function(a){a.name="\x54\x65\x73\x74\x31\x32\x33"}])}()}),b.exports=c("\x2e\x2f\x61\x70\x70\x2f\x6a\x73\x2f\x61\x70\x70\x2e\x6a\x73")}(require,module);
UPDATE
There is no answer for this question since this plugin is not created for angularjs, only for Node.js. And the creator has not the minimal intention to make it for angular js. However it is a cool tool
there are several questions here.
Do I need to obfuscate all my js files in order to get this run?
no
An obfuscate file can work perfect with all your dependencies NON-obfuscated? yes
What am I missing?
Hard to tell, uglification can be very tricky.
First I'll verify if dependencies injections are well done or you can use ngAnnotate to do that for you
dependency shall be defined as example bellow:
.service('myService',['$rootScope',function($rootScope){ ... }]);
If that does not solve your issue, you have to dig on requireJS that seems to send an issue
Edit your code and paste your main.js for us see what you are trying to uglify

Code coverage with Dojo, Mocha and Blanket - always reporting 1 covered line

I have tried setting up Blanket.js to get reports on the code coverage of our Dojo app, which we are testing using Mocha. So far, Blanket seems to load, instrument the correct files, and it also seems to figure out which lines it should look for. However, every single file/module in the report shows up as having one line tested. It looks to me like it's the top "define" line. Here's a not minimal example, but it minimally represents our app setup and reproduces the problem.
File structure
▾ dojo-mocha-blanket/
▾ modules/
GUIWidget.html
GUIWidget.js
▾ test/
▾ lib/
blanket_mocha.js // from the blanket /dist
chai.js
mocha-blanket.js // adapter as per instructions
mocha.css
mocha.js
▾ spec/
GUIWidget.js
testrunner.html
index.html
Dojo setup
<html>
<head>
<title>Dojo-Mocha-Blanket</title>
</head>
<body>
<div id="GUIWidgetContainer"></div>
<script>
var dojoConfig = {
async: true,
baseUrl: "",
modulePaths: {
"modules": "modules"
}
};
</script>
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.10.3/dojo/dojo.js"></script>
<script>
require([
"dojo/dom",
"modules/GUIWidget"
], function (dom, GUIWidget) {
var widget = new GUIWidget({}, "GUIWidgetContainer");
});
</script>
</body>
</html>
Module to test
define([
"dojo/_base/declare",
"dijit/form/Select",
"dijit/_TemplatedMixin",
"dijit/_WidgetsInTemplateMixin",
"dijit/_WidgetBase",
"dojo/text!modules/GUIWidget.html"
], function(
declare,
Select,
_TemplatedMixin,
_WidgetsInTemplateMixin,
_WidgetBase,
template
) {
return declare("GUIWidget", [_WidgetBase, _TemplatedMixin, _WidgetsInTemplateMixin], {
templateString: template,
addNumbers: function(lhs, rhs) {
return lhs + rhs;
},
postCreate: function() {
this.inherited(arguments);
this.header.innerHTML = this.addNumbers(40, 2);
}
});
});
Test setup
<html>
<head>
<title>Mocha spec runner</title>
<link rel="stylesheet" href="lib/mocha.css">
</head>
<body>
<div id="mocha"></div>
<script src="lib/mocha.js"></script>
<script
src="lib/blanket_mocha.js"
data-cover-adapter="lib/mocha-blanket.js"
data-cover-only="/modules"></script>
<script src="lib/chai.js"></script>
<script>
mocha.setup("bdd");
mocha.globals(["dojo", "dijit"]);
mocha.setup();
expect = chai.expect;
</script>
<script>
var dojoConfig = {
async: true,
packages : [{
name : "modules",
location : "/modules"
} ]
};
</script>
<script src="//ajax.googleapis.com/ajax/libs/dojo/1.10.3/dojo/dojo.js"></script>
<script>
require(
{
paths: {
"spec": "/test/spec"
}
},
["spec/GUIWidget"], function() {
mocha.run();
});
</script>
</body>
</html>
The test
define([
"modules/GUIWidget"
], function(
GUIWidget
) {
describe("GUIWidget", function() {
var widget;
beforeEach(function() {
widget = new GUIWidget();
widget.startup();
});
it("Should set header to 42", function() {
expect(widget.header.innerHTML).to.equal("42");
});
it("Should add numbers", function() {
expect(widget.addNumbers(1, 2)).to.equal(3);
})
afterEach(function() {
widget.destroyRecursive();
});
});
});
Results
(larger image here)
Apologies for the long code and all the bootstrapping stuff, but I've found the setup to be non-trivial :) If anyone has any ideas of why this might be happening, I'd be all ears. Thanks!

Adding Angular to Requirejs application is displaying Error: [$injector:modulerr]

Im trying to add AngularJS to my web application which already makes use of RequireJS. I have followed a couple of YouTube and web tutorials but for some reason, when loading my test page, i am seeing:
1) Error: [$injector:modulerr] http://errors.angularjs.org/1.2.16/$injector/modulerr?p0=MyApp&p1=%5B%.....
2) TypeError: Modernizr is undefined
if (!Modernizr.history) {
3) For some reason jQuery has stopped working too.
Here's my tree:
resources
- CSS
- js
- controllers
- MainController.js
- libs
- angular.js
- jquery.js
- require.js
- mondernizr.js
......
......
......
main.js
app.js
pages
test.html
main.js
(function(require) {
'use strict';
require.config({
baseUrl: '/resources/js',
paths: {
'jquery' : 'libs/jquery',
'angular' : 'libs/angular',
'router' : 'libs/page',
'history' : 'libs/history.iegte8',
'event' : 'libs/eventemitter2'
},
shim: {
'zepto' : { exports: '$' },
'angular' : { exports : 'angular' },
'router' : { exports: 'page'}
}
});
require([
'controllers/MainController'
]);
})(this.require);
app.js
define(['angular'], function(angular) {
return angular.module('MyApp', []);
})
MainController.js
require(['app'], function(app) {
app.controller('MainController', function() {
this.message = "Hello World";
})
});
test.html
<!DOCTYPE html>
<html ng-app="MyApp">
<head>
<title>AngularJS Test</title>
</head>
<body>
<div ng-controller="MainController as main">
{{ main.message }}
</div>
<script src="/resources/js/libs/require.js" data-main="/resources/js/main"></script>
</body>
</html>
Using AngularJS v1.2.16
Any help appreciated.
UPDATE ******************************************
Have added <script src="http://ajax.googleapis.com/ajax/libs/angularjs/1.2.8/angular-route.js"></script> to my test.html page and the Error: [$injector... error has disappeared.
Only error now showing is:
TypeError: Modernizr is undefined
if (!Modernizr.history) {
Followed advice on here: http://activeintelligence.org/blog/archive/error-injectornomod-module-ngroute-is-not-available/
I went over to Modernizr's site and checked the code. I see that it does not call define to define itself as a module so Modernizr is not AMD-compliant and you need a shim for it to tell RequireJS what the module value should be:
shim: {
...
modernizr: { exports: 'Modernizr' }
}

Categories