I created a yeoman angular project that is not building properly. After I run run the production build (dist folder), I get this error:
Failed to load template: /bundles/craigslist/main.html
It seems to be copying the files, but since the html files get turned into a string that lives in dist/scripts.js, it throws an error when trying to find /bundles/craigslist/main.html
In my "/dist/scripts.js":
.config(["$routeProvider", function(a) {
a.when("/", {
templateUrl:"/bundles/craigslist/main.html",
controller:"CraigslistMainCtrl",
controllerAs:"craigslist_main_root"
})
Info if necessary:
instead of the pattern /scripts and /views, I use bundles that organize similar files together, regardless of extension. For example, I have a /bundles/craigslist folder, which has the craigslist templates, service and routes. I'm trying to adjust my Gruntfile.js to account for this.
This is my grunt file: https://gist.github.com/ivansifrim/f632832a4ba8f44bf828b5d88066a0ce
This is my folder structure:
I tried to apply what was discussed here Angular / grunt failed to load template without any luck.
Try :
usemin: {
html: ['<%= yeoman.dist %>/**/*.html'],
css: ['<%= yeoman.dist %>/styles/{,*/}*.css'],
js: ['<%= yeoman.dist %>/scripts/{,*/}*.js', '<%= yeoman.dist %>/bundles/{,*/}*.js'],
options: {
assetsDirs: [
'<%= yeoman.dist %>',
'<%= yeoman.dist %>/images',
'<%= yeoman.dist %>/styles'
],
patterns: {
js: [[/(images\/[^''""]*\.(png|jpg|jpeg|gif|webp|svg))/g, 'Replacing references to images']]
}
}
}
I read a lot about this issue but still did not find the solution.
I have an Angular application set up with Yeoman's generator whitout Sass. I tried to include fontawesome, so I used bower install components-font-awesome --save.
The problem is that when I grunt buildmy app, I have an error because fonts are not found in my dist folder :
GET http://myapp.com/bower_components/components-font-awesome/fonts/fontawesome-webfont.svg?v=4.0.3 404 (Not Found)
So I tried to add this to Grunt copy task in order to copy the fonts to the right directory:
{
expand: true,
cwd: '<%= yeoman.app %>/bower_components/components-font-awesome/fonts/',
src: ['**'],
dest: '<%= yeoman.dist %>/bower_components/components-font-awesome/fonts/'
}
But I am still getting the same error...
EDIT
Fonts seem to be available at http://myapp.com/dist/bower_components/components-font-awesome/fonts/fontawesome-webfont.svg?v=4.0.3
But not at the URI throwing the error (without /dist) ...
The only way I found to include icons in my Angular's application was to include glyphicons instead of fontawesome. The same problem is happening when grunt building my app with glyphicon, but the following copy task worked for me:
// Copies remaining files to places other tasks can use
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= yeoman.app %>',
dest: '<%= yeoman.dist %>',
src: [
'*.{ico,png,txt}',
'.htaccess',
'*.html',
'views/{,*/}*.html',
'bower_components/**/*',
'images/{,*/}*.{webp}',
'fonts/*'
]
}, {
expand: true,
cwd: '.tmp/images',
dest: '<%= yeoman.dist %>/images',
src: ['generated/*']
}]
},
styles: {
expand: true,
cwd: '<%= yeoman.app %>/styles',
dest: '.tmp/styles/',
src: '{,*/}*.css'
}
},
after running the build from the /dist folder I get:
Uncaught Error: [$injector:modulerr] http://errors.angularjs.org/1.2.1/$injector/modulerr?p0=ourname&p1=Error%3A…(http%3A%2F%2Flocalhost%3A8085%2Flib%2Fangular%2Fangular.min.js%3A32%3A462)
nothing I do seems to solve this problem
this is the grunt task flow - adapted 1 to 1 from yeoman angular-generator:
module.exports = function(grunt){
require('load-grunt-tasks')(grunt);
require('time-grunt')(grunt);
grunt.initConfig({
//pkg: grunt.file.readJSON('package.json'),
yeoman: {
// configurable paths
app: require('./bower.json').appPath || 'app',
dist: 'dist'
},
coveralls:{
options:{
coverage_dir:'coverage'
}
},
jshint:{
files:['app/js/**/*.js', 'Gruntfile.js'],
options:grunt.file.readJSON('.jshintrc')
},
watch:{
styles: {
files: ['<%= yeoman.app %>/css/{,*/}*.css'],
tasks: ['copy:css', 'autoprefixer']
},
livereload: {
options: {
livereload: '<%= connect.options.livereload %>'
},
files: [
'<%= yeoman.app %>/{,*/}*.html',
'.tmp/css/{,*/}*.css',
'{.tmp,<%= yeoman.app %>}/js/{,*/}*.js',
'<%= yeoman.app %>/img/{,*/}*.{png,jpg,jpeg,gif,webp,svg}'
]
}
},
autoprefixer: {
options: ['last 1 version'],
dist: {
files: [{
expand: true,
cwd: '.tmp/styles/',
src: '{,*/}*.css',
dest: '.tmp/styles/'
}]
}
},
connect: {
options: {
port: 9000,
// Change this to '0.0.0.0' to access the server from outside.
hostname: 'localhost',
livereload: 35729
},
livereload: {
options: {
open: true,
base: [
'.tmp',
'<%= yeoman.app %>'
]
}
},
test: {
options: {
port: 9001,
base: [
'.tmp',
'test',
'<%= yeoman.app %>'
]
}
},
dist: {
options: {
base: '<%= yeoman.dist %>'
}
}
},
clean: {
dist: {
files: [{
dot: true,
src: [
'.tmp',
'<%= yeoman.dist %>/*',
'!<%= yeoman.dist %>/.git*'
]
}]
},
// server: '.tmp'
},
rev: {
dist: {
files: {
src: [
'<%= yeoman.dist %>/js/{,*/}*.js',
'<%= yeoman.dist %>/css/{,*/}*.css',
'<%= yeoman.dist %>/img/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
'<%= yeoman.dist %>/css/fonts/*'
]
}
}
},
useminPrepare: {
html: '<%= yeoman.app %>/index.html',
options: {
dest: '<%= yeoman.dist %>',
html: {
steps: {'js': ['concat','ngmin']},
post: {}
}
}
},
usemin: {
html: ['<%= yeoman.dist %>/{,*/}*.html'],
css: ['<%= yeoman.dist %>/css/{,*/}*.css'],
options: {
assetsDirs: ['<%= yeoman.dist %>']
}
},
imagemin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/img',
src: '{,*/}*.{png,jpg,jpeg}',
dest: '<%= yeoman.dist %>/img'
}]
}
},
svgmin: {
dist: {
files: [{
expand: true,
cwd: '<%= yeoman.app %>/img',
src: '{,*/}*.svg',
dest: '<%= yeoman.dist %>/img'
}]
}
},
cssmin: {
// By default, your `index.html` <!-- Usemin Block --> will take care of
// minification. This option is pre-configured if you do not wish to use
// Usemin blocks.
// dist: {
// files: {
// '<%= yeoman.dist %>/styles/main.css': [
// '.tmp/styles/{,*/}*.css',
// '<%= yeoman.app %>/styles/{,*/}*.css'
// ]
// }
// }
},
htmlmin: {
dist: {
options: {
/*removeCommentsFromCDATA: true,
// https://github.com/yeoman/grunt-usemin/issues/44
//collapseWhituseminPrepareespace: true,
collapseBooleanAttributes: true,
removeAttributeQuotes: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeOptionalTags: true*/
},
files: [{
expand: true,
cwd: '<%= yeoman.app %>',
src: ['*.html', 'partials/*.html'],
dest: '<%= yeoman.dist %>'
}]
}
},
copy: {
dist: {
files: [{
expand: true,
dot: true,
cwd: '<%= yeoman.app %>',
dest: '<%= yeoman.dist %>',
src: [
'*.{ico,png,txt}',
'lib/**/*',
'img/{,*/}*.{gif,webp}',
'fonts/*',
'languages/*'
]
}, {
expand: true,
cwd: '.tmp/img',
dest: '<%= yeoman.dist %>/img',
src: [
'generated/*'
]
}]
},
styles: {
expand: true,
cwd: '<%= yeoman.app %>/css',
dest: '.tmp/css/',
src: '{,*/}*.css'
}
},
concurrent: {
server: [
'copy:styles'
],
test: [
'copy:styles'
],
dist: [
'copy:styles',
'imagemin',
'svgmin',
'htmlmin'
]
},
// cdnify: {
// dist: {
// html: ['<%= yeoman.dist %>/*.html']
// }
// },
ngmin: {
dist: {
files: [{
expand: true,
cwd: '.tmp/concat/js',
src: '*.js',
dest: '.tmp/concat/js'
}]
}
},
uglify: {
dist: {
options:{
compress:false,
mangle:false
},
files: {
'<%= yeoman.dist %>/js/scripts.js': [
'<%= yeoman.dist %>/js/scripts.js'
]
}
}
},
// concat:{
// options:{
// seperator:';'
// },
// dist:{
// src :['app/js/**/*.js', 'app/lib/**/*.js'],
// dest :'dist/app/js/<%pkg.name%>.js'
//
// }
// },
exec:{
instrument:{
cmd: function(){
return 'istanbul instrument app/js -o app/instrumentjs';
}
},
djangoUp:{
cmd: function(){
var command = 'workon stokeet-api && cd ../stokeet-api/ && python manage.py runserver> /dev/null 2>&1 && cd ../angular/ & ';
return command;
}
},
webserverUp:{
cmd: function(){
var command = 'cd ../angular/ && node ./scripts/web-server.js > /dev/null 2>&1 &';
return command;
}
}
},
karma:{
unit:{
configFile:'config/karma.conf.js',
autoWatch:true,
browsers:['PhantomJS']
},
ci:{
configFile:'config/karma.conf.js',
singleRun:true,
autoWatch:false,
browsers:['Firefox','PhantomJS']
},
buildTest:{
configFile:'config/karma.conf.js',
singleRun:true,
autoWatch:false,
browsers:['PhantomJS']
}
}
});
grunt.registerTask('coverage',['coveralls']);
grunt.registerTask('default',['jshint']);
grunt.registerTask('instrument',['exec: instrument']);
// grunt.registerTask('concat',['concat']);
grunt.registerTask('dev_up',['exec:djangoUp', 'exec:webserverUp']);
grunt.registerTask('test',[
'clean:server',
'concurrent:test',
'autoprefixer',
'connect:test',
'karma:buildTest']),
grunt.registerTask('build', [
'clean:dist',
'useminPrepare',
'concurrent:dist',
'autoprefixer',
'concat',
'copy:dist',
'ngmin',
'cssmin',
'uglify',
'rev',
'usemin'
]);
grunt.registerTask('server', function (target) {
if (target === 'dist') {
return grunt.task.run(['build', 'connect:dist:keepalive']);
}
grunt.task.run([
'clean:server',
'concurrent:server',
'autoprefixer',
'connect:livereload',
'watch'
]);
});
};
You can see I tried overriding the usemin default flow, but that didn't help
I suspect this has to do with the known angular minification problem, but since ngmin is running here, and all my code (Not sure about the plugins) does respect the angular minification safe array notation I'm not sure .
any ideas? I'll be glad for any help with this
I will try to be brief explaining the problem when building with usemin 2.0.x and ngmin in Angularjs (according my experience, I may be wrong in something, if yes please correct me):
The normal flow in the Build grunt task is that ngmin is executed before usemin and others, to let the code with injections like this:
...
angular.module("Config",[])
.config(["$httpProvider","CONSTANTS","ERRORS","HEADERS",function(a,b,c,d){var
...
usemin 0.1.x was using only 'concat', but the version 2.0.x is using 'concat' and 'uglifyjs' so, after concatenate the code, it changes the javascript code again, this corrupts the ngmin, as you can see in the following example:
...
angular.module("Config",[])
.config(function(a,b,c,d){var
...
So you have to stop it defining the flow in useminPrepare, like the following:
useminPrepare: {
html: '<%= yeoman.app %>/index.html',
options: {
dest: '<%= yeoman.dist %>',
flow: {
steps: {'js': ['concat']},
post: {}
}
}
},
Edit
You can add the task in the grunt tasks:
grunt.registerTask('build', [
'clean:dist',
'jshint',
'useminPrepare',
'imagemin',
'cssmin',
'ngmin',
'uglify',
'rev',
'usemin'
])
Hope it helps!
I was also facing the same issue after yo angular setup without any modifications.
The following discussion helped me resolve it:
https://github.com/DaftMonk/generator-angular-fullstack/issues/164
In a nutshell:
Search for
<!-- build:js scripts/vendor.js -->
and change it to
<!-- build:js(app/..) scripts/vendor.js -->
I think the default GruntFile.js has changed a bit in Yeoman since this question was answered.
This worked for me:
Uncommented out the following uglify block and added the mangle:false option.
uglify: {
options:{mangle:false},
dist: {
files: {
'<%= yeoman.dist %>/scripts/scripts.js': [
'<%= yeoman.dist %>/scripts/scripts.js'
]
}
}
},
Then I commented out the ngmin line (which took forever to run anyway).
The result is non-mangled js which is considerably larger, but runs my angular code well. Eventually I suppose ngmin will be smart enough to handle things more seamlessly, but until then I'm okay with the extra bytes.
Is everything working if you only serve the files (grunt server)?
So: No problem with angular this way?
Have your read the linked error page?
http://docs.angularjs.org/error/$injector:modulerr?p0=ourname&p1=Error:%E2%80%A6(http:%2F%2Flocalhost:8085%2Flib%2Fangular%2Fangular.min.js:32:462)
It tells you, that there is a problem with our "ourname" module.
Do you have some code for us?
I am not quite sure, what this changes, but you can also define it like:
useminPrepare: {
html: '<%= yeoman.app %>/index.html',
options: {
dest: '<%= yeoman.dist %>',
flow: {
steps: {'js': ['concat','ngmin']},
post: {}
}
}
},
https://github.com/yeoman/grunt-usemin#flow
Did you missed the "flow"?
Maybe one of the questions helps to find the solution ;)
if you are using Yeoman for building your angular application.
Simply type
yo doctor
This will help you to identify what all issues are present with your application.
Yeoman Doctor
Running sanity checks on your system
✔ Global configuration file is valid
✔ NODE_PATH matches the npm root
✖ Node.js version
Your Node.js version is outdated.
Upgrade to the latest version: https://nodejs.org
✔ No .bowerrc file in home directory
✔ No .yo-rc.json file in home directory
✔ npm version
Found potential issues on your machine :(
When I grunt build my AngularJS app grunt-rev has a problem dealing with the fonts. It will create the font folders just fine but does not place any fonts in them. Here is what it shows me.
Running "rev:dist" (rev) task
dist/scripts/scripts.js >> a3e641ec.scripts.js
dist/styles/main.css >> 970b8797.main.css
Warning: Unable to read "dist/fonts/Aller" file (Error code: EISDIR). Use --force to continue.
grunt-rev in my Gruntfile.js
rev: {
dist: {
files: {
src: [
'<%= yeoman.dist %>/scripts/{,*/}*.js',
'<%= yeoman.dist %>/styles/{,*/}*.css',
'<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
'<%= yeoman.dist %>/styles/fonts/*'
]
}
}
}
How to fix this?
I finally solved this problem by using the double asterisk ** method to match all the sub directories recursively. I don't know why that method was not used in my original Gruntfile.js. Instead it used the {,*/}* which did not behave recursively for some reason. So here is my new rev object in my Gruntfile.js
rev: {
dist: {
files: {
src: [
'<%= yeoman.dist %>/scripts/**/*.js',
'<%= yeoman.dist %>/styles/**/*.css',
'<%= yeoman.dist %>/images/**/*.{png,jpg,jpeg,gif,webp,svg}',
'<%= yeoman.dist %>/fonts/**/*.ttf'
]
}
}
},
I was having the same problem. They have a bug about it in version 0.1.0.
A workaround is to specify a file extension.
Before:
rev: {
dist: {
files: [{
expand: true,
cwd: '<%= config.dist %>/',
src: [
'images/**/*'
]
}]
}
}
After:
rev: {
dist: {
files: [{
expand: true,
cwd: '<%= config.dist %>/',
src: [
'images/**/*.{gif,jpeg,jpg,png}'
]
}]
}
}