generator-ionic
generator-ionic copied to clipboard
HTML5 Mode true after reload/refresh Cannot GET /app/welcome
I have read many posts and googled it a lot, but couldn't able to work HTML5 mode true in my app. when i grunt serve app is working fine with all navigation etc, but when i refresh i am getting error Cannot GET /app/welcome
any help would be great
PS. i have checked this http://stackoverflow.com/questions/16569841/angularjs-html5-mode-reloading-the-page-gives-wrong-get-request?lq=1
You need to enable URL rewrite in the server to get this to work properly...
Setting of url rewrite is different for different servers....
@johntomcy I do understand that server setting my differ, but when i am running locally, is there a way to get it work.
I am really sorry for posting full Grunt file, but i am helpless, Please guide me where i am doing wrong.
Thanks
// Generated on 2015-02-16 using generator-ionic 0.7.0
'use strict';
var _ = require('lodash');
var path = require('path');
var cordovaCli = require('cordova');
var spawn = process.platform === 'win32' ? require('win-spawn') : require('child_process').spawn;
var modRewrite = require('connect-modrewrite');
var mountFolder = function(connect, dir){
return connect.static(require('path').resolve(dir));
};
module.exports = function(grunt){
// Load grunt tasks automatically
require('load-grunt-tasks')(grunt);
// Time how long tasks take. Can help when optimizing build times
require('time-grunt')(grunt);
// Define the configuration for all the tasks
grunt.initConfig({
// Project account
yeoman: {
// configurable paths
app: 'app',
scripts: 'scripts',
fonts: 'fonts',
styles: 'styles',
images: 'images',
test: 'test',
dist: 'www'
},
// Watches files for changes and runs tasks based on the changed files
watch: {
bower: {
files: ['bower.json'],
tasks: ['wiredep', 'newer:copy:app']
},
html: {
files: ['<%= yeoman.app %>/**/*.html'],
tasks: ['newer:copy:app']
},
js: {
files: ['<%= yeoman.app %>/<%= yeoman.scripts %>/**/*.js'],
tasks: ['newer:copy:app', 'newer:jshint:all']
},
compass: {
files: ['<%= yeoman.app %>/<%= yeoman.styles %>/**/*.{scss,sass}'],
tasks: ['compass:server', 'autoprefixer', 'newer:copy:tmp']
}
},
// The actual grunt server account
connect: {
options: {
port: 9000,
livereload: 35729,
// Change this to '0.0.0.0' to access the server from outside.
hostname: '0.0.0.0'
},
server: {
options: {
middleware: function (connect) {
return [
modRewrite (['!\\.html|\\.js|\\.svg|\\.css|\\.png|\\.jpg$ /index.html [L]']),
mountFolder(connect, 'app')
];
}
}
},
livereload: {
options: {
open: true,
base: [
'.tmp',
'<%= yeoman.app %>'
],
// MODIFIED: Add this middleware configuration
middleware: function(connect, options){
var middlewares = [];
middlewares.push(modRewrite(['^[^\\.]*$ /index.html [L]'])); //Matches everything that does not contain a '.' (period)
options.base.forEach(function(base){
middlewares.push(connect.static(base));
});
return middlewares;
}
}
},
dist: {
options: {
base: '<%= yeoman.dist %>'
}
},
coverage: {
options: {
port: 9002,
open: true,
base: ['coverage']
}
}
},
// Make sure code styles are up to par and there are no obvious mistakes
jshint: {
options: {
jshintrc: '.jshintrc',
reporter: require('jshint-stylish')
},
all: [
'Gruntfile.js',
'<%= yeoman.app %>/<%= yeoman.scripts %>/**/*.js'
],
test: {
options: {
jshintrc: 'test/.jshintrc'
},
src: ['test/unit/**/*.js']
}
},
// Empties folders to start fresh
clean: {
dist: {
files: [{
dot: true,
src: [
'.temp',
'<%= yeoman.dist %>/*',
'!<%= yeoman.dist %>/.git*'
]
}
]
},
server: '.temp'
},
autoprefixer: {
options: {
browsers: ['last 1 version']
},
dist: {
files: [{
expand: true,
cwd: '.temp/<%= yeoman.styles %>/',
src: '{,*/}*.css',
dest: '.temp/<%= yeoman.styles %>/'
}
]
}
},
// Automatically inject Bower components into the app
wiredep: {
app: {
src: ['<%= yeoman.app %>/index.html'],
ignorePath: /\.\.\//
},
sass: {
src: ['<%= yeoman.app %>/styles/{,*/}*.{scss,sass}'],
ignorePath: /(\.\.\/){1,2}lib\//
}
},
// Compiles Sass to CSS and generates necessary files if requested
compass: {
options: {
sassDir: '<%= yeoman.app %>/<%= yeoman.styles %>',
cssDir: '.temp/<%= yeoman.styles %>',
generatedImagesDir: '.temp/<%= yeoman.images %>/generated',
imagesDir: '<%= yeoman.app %>/<%= yeoman.images %>',
javascriptsDir: '<%= yeoman.app %>/<%= yeoman.scripts %>',
fontsDir: '<%= yeoman.app %>/<%= yeoman.styles %>/fonts',
importPath: '<%= yeoman.app %>/bower_components',
httpImagesPath: '/<%= yeoman.images %>',
httpGeneratedImagesPath: '/<%= yeoman.images %>/generated',
httpFontsPath: '/<%= yeoman.styles %>/fonts',
relativeAssets: false,
assetCacheBuster: false,
raw: 'Sass::Script::Number.precision = 10\n'
},
dist: {
options: {
generatedImagesDir: '<%= yeoman.dist %>/<%= yeoman.images %>/generated'
}
},
server: {
options: {
debugInfo: true
}
}
},
// Reads HTML for usemin blocks to enable smart builds that automatically
// concat, minify and revision files. Creates configurations in memory so
// additional tasks can operate on them
useminPrepare: {
html: '<%= yeoman.app %>/index.html',
options: {
dest: '<%= yeoman.dist %>',
staging: '.temp',
flow: {
html: {
steps: {
js: ['concat', 'uglifyjs'],
css: ['cssmin']
},
post: {}
}
}
}
},
// Performs rewrites based on the useminPrepare configuration
usemin: {
html: ['<%= yeoman.dist %>/{,*/}{,*/}{,*/}*.html'],
css: ['<%= yeoman.dist %>/{,*/}/{,*/}{,*/}*.css'],
options: {
assetsDirs: [
'<%= yeoman.dist %>',
'<%= yeoman.dist %>/images'
]
}
},
// The following *-min tasks produce minified files in the dist folder
cssmin: {
options: {
//root: '<%= yeoman.app %>',
noRebase: true
},
dist: {
files: [
{
expand: true,
cwd: '.temp/<%= yeoman.styles %>',
src: ['*.css'],
dest: '.temp/<%= yeoman.styles %>'
}
],
noRebase: true
}
},
htmlmin: {
dist: {
options: {
collapseWhitespace: true,
collapseBooleanAttributes: true,
removeCommentsFromCDATA: true,
removeOptionalTags: true
},
files: [{
expand: true,
cwd: '<%= yeoman.dist %>',
src: ['*.html', 'templates/**/*.html'],
dest: '<%= yeoman.dist %>'
}
]
}
},
// Copies remaining files to places other tasks can use
copy: {
dist: {
files: [
{
expand: true,
dot: true,
cwd: '<%= yeoman.app %>',
dest: '<%= yeoman.dist %>',
src: [
'<%= yeoman.images %>/**/*.{png,jpg,jpeg,gif,webp,svg}',
'*.html',
'scripts/**/*.html',
'templates/**/*.html',
'fonts/*'
]
},
{
expand: true,
dot: true,
cwd: '.temp/<%= yeoman.styles %>/',
dest: '<%= yeoman.dist %>/<%= yeoman.styles %>',
src: ['*.css']
},
{
expand: true,
cwd: '.temp/<%= yeoman.images %>',
dest: '<%= yeoman.dist %>/<%= yeoman.images %>',
src: ['generated/*']
},
{
expand: true,
flatten: true,
cwd: '<%= yeoman.app %>',
dest: '<%= yeoman.dist %>/fonts',
src: ['bower_components/ionicons/fonts/*.*']
}
]
},
styles: {
expand: true,
cwd: '<%= yeoman.app %>/<%= yeoman.styles %>',
dest: '.temp/<%= yeoman.styles %>/',
src: '{,*/}*.css'
},
fonts: {
expand: true,
cwd: 'app/lib/ionic/release/fonts/',
dest: '<%= yeoman.app %>/fonts/',
src: '*'
},
vendor: {
expand: true,
cwd: '<%= yeoman.app %>/vendor',
dest: '.temp/<%= yeoman.styles %>/',
src: '{,*/}*.css'
},
app: {
expand: true,
cwd: '<%= yeoman.app %>',
dest: '<%= yeoman.dist %>/',
src: [
'**/*',
'!**/*.(scss,sass,css)'
]
},
tmp: {
expand: true,
cwd: '.temp',
dest: '<%= yeoman.dist %>/',
src: '**/*'
}
},
concurrent: {
ionic: {
tasks: [],
options: {
logConcurrentOutput: true
}
},
server: [
'compass:server',
'copy:styles',
'copy:vendor',
'copy:fonts'
],
test: [
'compass',
'copy:styles',
'copy:vendor',
'copy:fonts'
],
dist: [
'compass:dist',
'copy:styles',
'copy:vendor',
'copy:fonts'
]
},
filerev: {
dist: {
src: [
'<%= yeoman.dist %>/scripts/{,*/}{,*/}{,*/}*.js',
'<%= yeoman.dist %>/vendor/{,*/}{,*/}{,*/}*.js',
'<%= yeoman.dist %>/styles/{,*/}*.css',
'<%= yeoman.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp,svg}',
'<%= yeoman.dist %>/styles/fonts/{,*/}*'
]
}
},
// ngAnnotate tries to make the code safe for minification automatically by
// using the Angular long form for dependency injection.
ngAnnotate: {
dist: {
files: [{
expand: true,
cwd: '.temp/concat/<%= yeoman.scripts %>',
src: '*.js',
dest: '.temp/concat/<%= yeoman.scripts %>'
}
]
}
}
});
// Register tasks for all Cordova commands
_.functions(cordovaCli).forEach(function(name){
grunt.registerTask(name, function(){
this.args.unshift(name.replace('cordova:', ''));
// Handle URL's being split up by Grunt because of `:` characters
if(_.contains(this.args, 'http')||_.contains(this.args, 'https')){
this.args = this.args.slice(0, -2).concat(_.last(this.args, 2).join(':'));
}
var done = this.async();
var exec = process.platform === 'win32' ? 'cordova.cmd' : 'cordova';
var cmd = path.resolve('./node_modules/cordova/bin', exec);
var flags = process.argv.splice(3);
var child = spawn(cmd, this.args.concat(flags));
child.stdout.on('data', function(data){
grunt.log.writeln(data);
});
child.stderr.on('data', function(data){
grunt.log.error(data);
});
child.on('close', function(code){
code = code ? false : true;
done(code);
});
});
});
// Since Apache Ripple serves assets directly out of their respective platform
// directories, we watch all registered files and then copy all un-built assets
// over to <%= yeoman.dist %>/. Last step is running cordova prepare so we can refresh the ripple
// browser tab to see the changes. Technically ripple runs `cordova prepare` on browser
// refreshes, but at this time you would need to re-run the emulator to see changes.
grunt.registerTask('ripple', ['wiredep', 'newer:copy:app', 'ripple-emulator']);
grunt.registerTask('ripple-emulator', function(){
grunt.config.set('watch', {
all: {
files: _.flatten(_.pluck(grunt.config.get('watch'), 'files')),
tasks: ['newer:copy:app', 'prepare']
}
});
var cmd = path.resolve('./node_modules/ripple-emulator/bin', 'ripple');
var child = spawn(cmd, ['emulate']);
child.stdout.on('data', function(data){
grunt.log.writeln(data);
});
child.stderr.on('data', function(data){
grunt.log.error(data);
});
process.on('exit', function(code){
child.kill('SIGINT');
process.exit(code);
});
return grunt.task.run(['watch']);
});
// Dynamically configure `karma` target of `watch` task so that
// we don't have to run the karma test server as part of `grunt serve`
grunt.registerTask('watch:karma', function(){
var karma = {
files: ['<%= yeoman.app %>/<%= yeoman.scripts %>/**/*.js', '<%= yeoman.test %>/spec/**/*.js'],
tasks: ['newer:jshint:test', 'karma:unit:run']
};
grunt.config.set('watch', karma);
return grunt.task.run(['watch']);
});
// Wrap ionic-cli commands
grunt.registerTask('ionic', function(){
var done = this.async();
var script = path.resolve('./node_modules/ionic/bin/', 'ionic');
var flags = process.argv.splice(3);
var child = spawn(script, this.args.concat(flags), {stdio: 'inherit'});
child.on('close', function(code){
code = code ? false : true;
done(code);
});
});
grunt.registerTask('test', [
'wiredep',
'clean',
'concurrent:test',
'autoprefixer',
'karma:unit:start',
'watch:karma'
]);
grunt.registerTask('serve', function(target){
if(target === 'compress'){
return grunt.task.run(['compress', 'ionic:serve']);
}
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.registerTask('server', ['connect:server']);
grunt.config('concurrent.ionic.tasks', ['ionic:serve', 'watch']);
grunt.task.run(['wiredep', 'init', 'concurrent:ionic']);
});
grunt.registerTask('emulate', function(){
grunt.config('concurrent.ionic.tasks', ['ionic:emulate:' + this.args.join(), 'watch']);
return grunt.task.run(['init', 'concurrent:ionic']);
});
grunt.registerTask('run', function(){
grunt.config('concurrent.ionic.tasks', ['ionic:run:' + this.args.join(), 'watch']);
return grunt.task.run(['init', 'concurrent:ionic']);
});
grunt.registerTask('build', function(){
return grunt.task.run(['init', 'ionic:build:' + this.args.join()]);
});
grunt.registerTask('init', [
'clean',
//'ngconstant:development',
'wiredep',
'concurrent:server',
'autoprefixer',
'newer:copy:app',
'newer:copy:tmp'
]);
grunt.registerTask('build_web', [
'clean:dist',
'wiredep',
'compass:dist',
'useminPrepare',
'concurrent:dist',
'autoprefixer',
'concat',
'ngAnnotate',
'copy:dist',
'cdnify',
'cssmin:generated',
'cssmin:dist',
'uglify',
'filerev',
'usemin',
'htmlmin'
]);
grunt.registerTask('compress', [
'clean',
//'ngconstant:production',
'wiredep',
'useminPrepare',
'concurrent:dist',
'autoprefixer',
'concat',
'ngAnnotate',
'copy:dist',
'cssmin',
'uglify',
'usemin',
'htmlmin'
]);
grunt.loadNpmTasks('grunt-contrib-connect');
grunt.registerTask('server', ['connect:server']);
grunt.registerTask('coverage',
['karma:continuous',
'connect:coverage:keepalive'
]);
grunt.registerTask('default', [
'wiredep',
'newer:jshint',
'karma:continuous',
'compress'
]);
};
@anjum121
You will have to create your own web server because 'ionic server' creates a server that don't support modRewrite.
Here what I did:
1- Web Server for Production ( Nodejs + Express)
_server.js_
https://gist.github.com/lucasalmeida92/7f67f5183318d44f348b
2- Web Server for Development ( Nodejs + Gulp + BroswerSync + Connect History Api Fallback)
_gulpfile.js_
https://gist.github.com/lucasalmeida92/592185d6bfdc5626cf5a
3- Gulp task for Mobile App build (with gulp-replace package)
When you put <base href="/">
inside the head tag in your index.html file, the application will work fine with Html5Mode enabled in a web browser, but in your mobile application you gotta use <base href=".">
instead.
To automate this, I created a gulp task with gulp-replace node package to do the job for me:
gulp.task('build:device', ['sass', 'compressJs', 'jade-templates'],function () {
return gulp.src(paths.jade[1])
.pipe(replace('base(href="/")', 'base(href=".")'))
.pipe(jade())
.pipe(gulp.dest('./www/'));
});
So before I run "ionic build android"
i run "gulp build:device"
.
4- Url paths Cautions
You will have to be careful with url paths.
-
href urls must start with "/". Ex.:
<a href="/app/list">link</a>
-
src urls must start without "/". Ex.:
<img src="img/banner.jpg">