From 9cc92ccb258dd60d70bee983adbf382f0fc701c4 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Tue, 10 Sep 2013 12:29:43 +0200 Subject: [PATCH 1/5] serve all css minimized & static files from /build --- .gitignore | 2 +- Gruntfile.js | 18 +++++++++++------- src/server.js | 1 + views/index.jade | 6 +++--- views/static/layout.jade | 6 +++--- 5 files changed, 19 insertions(+), 14 deletions(-) diff --git a/.gitignore b/.gitignore index db9a64ac62..c0f0054b81 100644 --- a/.gitignore +++ b/.gitignore @@ -7,7 +7,7 @@ config.json npm-debug.log lib public/bower_components -public/build +build src/*/*.map src/*/*/*.map diff --git a/Gruntfile.js b/Gruntfile.js index 00ecbbf19d..8858a8a5e9 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -11,7 +11,7 @@ module.exports = function(grunt) { uglify: { buildApp: { files: { - 'public/build/app.js': [ + 'build/app.js': [ 'public/bower_components/jquery/jquery.min.js', 'public/bower_components/bootstrap-growl/jquery.bootstrap-growl.min.js', 'public/bower_components/angular/angular.min.js', @@ -65,7 +65,7 @@ module.exports = function(grunt) { }, buildStatic: { files: { - 'public/build/static.js': [ + 'build/static.js': [ 'public/bower_components/jquery/jquery.min.js', 'public/bower_components/habitrpg-shared/dist/habitrpg-shared.js', 'public/bower_components/angular/angular.min.js', @@ -89,8 +89,8 @@ module.exports = function(grunt) { paths: ['public'] }, files: { - 'public/build/app.css': ['public/css/index.styl'], - 'public/build/static.css': ['public/css/static.styl'] + 'build/app.css': ['public/css/index.styl'], + 'build/static.css': ['public/css/static.styl'] } } }, @@ -98,15 +98,19 @@ module.exports = function(grunt) { cssmin: { build: { files: { - 'public/build/app.css': ['public/build/app.css'], - 'public/build/static.css': ['public/build/static.css'] + 'build/app.css': ['build/app.css'], + 'build/static.css': ['build/static.css'], + 'build/bower_components/habitrpg-shared/dist/spritesheets.css': ['public/bower_components/habitrpg-shared/dist/spritesheets.css'], + 'build/bower_components/bootstrap/docs/assets/css/bootstrap.css': ['public/bower_components/bootstrap/docs/assets/css/bootstrap.css'], + 'build/bower_components/bootstrap/docs/assets/css/bootstrap-responsive.css': ['public/bower_components/bootstrap/docs/assets/css/bootstrap-responsive.css'], + 'build/bower_components/bootstrap/docs/assets/css/docs.css': ['public/bower_components/bootstrap/docs/assets/css/docs.css'] } } }, nodemon: { dev: { - ignoredFiles: ['public/*', 'Gruntfile.js', 'views/*'] // Do not work! + ignoredFiles: ['public/*', 'Gruntfile.js', 'views/*', 'build/*'] // Do not work! } }, diff --git a/src/server.js b/src/server.js index c38e877895..2ee1125bb0 100644 --- a/src/server.js +++ b/src/server.js @@ -99,6 +99,7 @@ app.use(passport.initialize()); app.use(passport.session()); app.use(app.router); +app.use(express['static'](path.join(__dirname, "/../build"))); app.use(express['static'](path.join(__dirname, "/../public"))); // development only diff --git a/views/index.jade b/views/index.jade index 0e49804f75..433e6be686 100644 --- a/views/index.jade +++ b/views/index.jade @@ -14,16 +14,16 @@ html display: none; } - // CSS + // CSS Remember to update also in Grunfile.js cssmin task! link(rel='stylesheet', href='/bower_components/bootstrap/docs/assets/css/bootstrap.css') - link(rel='stylesheet', href='/build/app.css') + link(rel='stylesheet', href='/app.css') // HabitRPG Shared link(rel='stylesheet', href='/bower_components/habitrpg-shared/dist/spritesheets.css') - if(env.NODE_ENV == 'production'){ - script(type='text/javascript', src='build/app.js') + script(type='text/javascript', src='/app.js') - }else{ // Remember to update the file list in Gruntfile.js! script(type='text/javascript', src='/bower_components/jquery/jquery.min.js') diff --git a/views/static/layout.jade b/views/static/layout.jade index f9b5ef3e8d..6c22de5eac 100644 --- a/views/static/layout.jade +++ b/views/static/layout.jade @@ -13,17 +13,17 @@ html meta(charset='utf-8') meta(name='viewport', content='width=device-width, initial-scale=1.0') - // CSS + // CSS Remember to update also in Grunfile.js cssmin task! link(rel='stylesheet', href='/bower_components/bootstrap/docs/assets/css/bootstrap.css') // Keep this out of build because the one after has some images and would like not to override it link(rel='stylesheet', href='/bower_components/bootstrap/docs/assets/css/bootstrap-responsive.css') link(href='/bower_components/bootstrap/docs/assets/css/docs.css', rel='stylesheet') - link(rel='stylesheet', href='/build/static.css') + link(rel='stylesheet', href='/static.css') // JS - if(layoutEnv.NODE_ENV == 'production'){ - script(type='text/javascript', src='/build/static.js') + script(type='text/javascript', src='/static.js') - }else{ // Remember to update the file list in Gruntfile.js! script(type='text/javascript', src='/bower_components/jquery/jquery.min.js') From f71590449c281f8f4fa92c0da629a7e8fd3e36a6 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Tue, 10 Sep 2013 12:39:17 +0200 Subject: [PATCH 2/5] add hash to build files & correct minor fix --- Gruntfile.js | 22 +++++++++++++++++++--- package.json | 1 + 2 files changed, 20 insertions(+), 3 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 8858a8a5e9..bda73f22d7 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -5,7 +5,7 @@ module.exports = function(grunt) { grunt.initConfig({ clean: { - build: ['public/build'] + build: ['build'] }, uglify: { @@ -108,6 +108,21 @@ module.exports = function(grunt) { } }, + // UPDATE IT! + hashres: { + build: { + options: { + fileNameFormat: '${name}-${hash}.${ext}' + }, + src: [ + 'build/*.js', 'build/*.css', + 'build/bower_components/bootstrap/docs/assets/css/*.css', + 'build/bower_components/habitrpg-shared/dist/*.css' + ], + dest: 'make-sure-i-do-not-exist' + } + }, + nodemon: { dev: { ignoredFiles: ['public/*', 'Gruntfile.js', 'views/*', 'build/*'] // Do not work! @@ -134,8 +149,8 @@ module.exports = function(grunt) { }); // Register tasks. - grunt.registerTask('build:prod', ['clean:build', 'uglify', 'stylus', 'cssmin']); - grunt.registerTask('build:dev', ['clean:build', 'stylus', 'cssmin']); + grunt.registerTask('build:prod', ['clean:build', 'uglify', 'stylus', 'cssmin', 'hashres']); + grunt.registerTask('build:dev', ['clean:build', 'stylus', 'cssmin', 'hashres']); grunt.registerTask('run:dev', [ 'build:dev', 'concurrent' ]); @@ -147,5 +162,6 @@ module.exports = function(grunt) { grunt.loadNpmTasks('grunt-nodemon'); grunt.loadNpmTasks('grunt-concurrent'); grunt.loadNpmTasks('grunt-contrib-watch'); + grunt.loadNpmTasks('grunt-hashres'); }; diff --git a/package.json b/package.json index 5e24f91961..74e72c179a 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "grunt-contrib-clean": "~0.5.0", "grunt-contrib-cssmin": "~0.6.1", "grunt-contrib-watch": "~0.5.x", + "grunt-hashres": "~0.3.2", "grunt-nodemon": "~0.1.1", "grunt-concurrent": "~0.3.1", "bower": "~1.2.4", From 21823564c23dd74e562818125e5d7817c0365c73 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Tue, 10 Sep 2013 14:40:00 +0200 Subject: [PATCH 3/5] add caching --- Gruntfile.js | 13 ++++++++++--- package.json | 3 ++- src/middleware.js | 37 ++++++++++++++++++++++++++++++++++++- src/server.js | 4 +++- views/index.jade | 10 +++++----- views/static/layout.jade | 13 ++++++------- 6 files changed, 62 insertions(+), 18 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index bda73f22d7..8e65954c76 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -108,6 +108,12 @@ module.exports = function(grunt) { } }, + copy: { + build: { + files: [{expand: true, cwd: 'public/', src: 'favicon.ico', dest: 'build/'}] + } + }, + // UPDATE IT! hashres: { build: { @@ -115,7 +121,7 @@ module.exports = function(grunt) { fileNameFormat: '${name}-${hash}.${ext}' }, src: [ - 'build/*.js', 'build/*.css', + 'build/*.js', 'build/*.css', 'build/favicon.ico', 'build/bower_components/bootstrap/docs/assets/css/*.css', 'build/bower_components/habitrpg-shared/dist/*.css' ], @@ -149,8 +155,8 @@ module.exports = function(grunt) { }); // Register tasks. - grunt.registerTask('build:prod', ['clean:build', 'uglify', 'stylus', 'cssmin', 'hashres']); - grunt.registerTask('build:dev', ['clean:build', 'stylus', 'cssmin', 'hashres']); + grunt.registerTask('build:prod', ['clean:build', 'uglify', 'stylus', 'cssmin', 'copy:build', 'hashres']); + grunt.registerTask('build:dev', ['clean:build', 'stylus', 'cssmin', 'copy:build', 'hashres']); grunt.registerTask('run:dev', [ 'build:dev', 'concurrent' ]); @@ -159,6 +165,7 @@ module.exports = function(grunt) { grunt.loadNpmTasks('grunt-contrib-clean'); grunt.loadNpmTasks('grunt-contrib-stylus'); grunt.loadNpmTasks('grunt-contrib-cssmin'); + grunt.loadNpmTasks('grunt-contrib-copy'); grunt.loadNpmTasks('grunt-nodemon'); grunt.loadNpmTasks('grunt-concurrent'); grunt.loadNpmTasks('grunt-contrib-watch'); diff --git a/package.json b/package.json index 74e72c179a..ce0234c1a9 100644 --- a/package.json +++ b/package.json @@ -30,7 +30,8 @@ "grunt-contrib-stylus": "~0.8.0", "grunt-contrib-clean": "~0.5.0", "grunt-contrib-cssmin": "~0.6.1", - "grunt-contrib-watch": "~0.5.x", + "grunt-contrib-watch": "~0.5.3", + "grunt-contrib-copy": "~0.4.1", "grunt-hashres": "~0.3.2", "grunt-nodemon": "~0.1.1", "grunt-concurrent": "~0.3.1", diff --git a/src/middleware.js b/src/middleware.js index 376b00f177..67afee8461 100644 --- a/src/middleware.js +++ b/src/middleware.js @@ -1,5 +1,7 @@ var nconf = require('nconf'); var _ = require('lodash'); +var fs = require('fs'); +var path = require('path'); module.exports.forceSSL = function(req, res, next){ var baseUrl = nconf.get("BASE_URL"); @@ -26,12 +28,45 @@ module.exports.cors = function(req, res, next) { return next(); }; +var buildFiles = []; + +var walk = function(folder){ + var res = fs.readdirSync(folder); + + res.forEach(function(fileName){ + file = folder + '/' + fileName; + if(fs.statSync(file).isDirectory()){ + walk(file); + }else{ + var relFolder = path.relative(path.join(__dirname, "/../build"), folder); + var old = fileName.replace(/-.{8}(\.[\d\w]+)$/, '$1'); + + if(relFolder){ + old = relFolder + '/' + old; + fileName = relFolder + '/' + fileName; + } + + buildFiles[old] = fileName + } + }); +} + +walk(path.join(__dirname, "/../build")); + +var getBuildUrl = function(url){ + console.log("CALLED ", url) + if(buildFiles[url]) return buildFiles[url]; + + return filename; +} + module.exports.locals = function(req, res, next) { res.locals.habitrpg = res.locals.habitrpg || {} _.defaults(res.locals.habitrpg, { NODE_ENV: nconf.get('NODE_ENV'), IS_MOBILE: /Android|webOS|iPhone|iPad|iPod|BlackBerry/i.test(req.header('User-Agent')), - STRIPE_PUB_KEY: nconf.get('STRIPE_PUB_KEY') + STRIPE_PUB_KEY: nconf.get('STRIPE_PUB_KEY'), + getBuildUrl: getBuildUrl }); next() } diff --git a/src/server.js b/src/server.js index 2ee1125bb0..cb1a0c18f0 100644 --- a/src/server.js +++ b/src/server.js @@ -99,7 +99,9 @@ app.use(passport.initialize()); app.use(passport.session()); app.use(app.router); -app.use(express['static'](path.join(__dirname, "/../build"))); + +var oneYear = 31536000000; +app.use(express['static'](path.join(__dirname, "/../build"), { maxAge: oneYear })); app.use(express['static'](path.join(__dirname, "/../public"))); // development only diff --git a/views/index.jade b/views/index.jade index 433e6be686..33d3f8212a 100644 --- a/views/index.jade +++ b/views/index.jade @@ -4,7 +4,7 @@ html title HabitRPG | Your Life The Role Playing Game // ?v=1 needed to force refresh - link(rel='shortcut icon' href='/favicon.ico?v=1') + link(rel='shortcut icon' href='/#{env.getBuildUrl("favicon.ico")}?v=2') script(type='text/javascript'). window.env = !{JSON.stringify(env)}; @@ -15,15 +15,15 @@ html } // CSS Remember to update also in Grunfile.js cssmin task! - link(rel='stylesheet', href='/bower_components/bootstrap/docs/assets/css/bootstrap.css') + link(rel='stylesheet', href='/#{env.getBuildUrl("bower_components/bootstrap/docs/assets/css/bootstrap.css")}') - link(rel='stylesheet', href='/app.css') + link(rel='stylesheet', href='/#{env.getBuildUrl("app.css")}') // HabitRPG Shared - link(rel='stylesheet', href='/bower_components/habitrpg-shared/dist/spritesheets.css') + link(rel='stylesheet', href='/#{env.getBuildUrl("bower_components/habitrpg-shared/dist/spritesheets.css")}') - if(env.NODE_ENV == 'production'){ - script(type='text/javascript', src='/app.js') + script(type='text/javascript', src='/#{env.getBuildUrl("app.js")}') - }else{ // Remember to update the file list in Gruntfile.js! script(type='text/javascript', src='/bower_components/jquery/jquery.min.js') diff --git a/views/static/layout.jade b/views/static/layout.jade index 6c22de5eac..07814bd1dc 100644 --- a/views/static/layout.jade +++ b/views/static/layout.jade @@ -7,23 +7,22 @@ html block title title HabitRPG | Your Life the Role Playing Game - // ?v=1 needed to force refresh - link(rel='shortcut icon' href='/favicon.ico?v=1') + link(rel='shortcut icon', href='/#{env.getBuildUrl("favicon.ico")}?v=2') meta(charset='utf-8') meta(name='viewport', content='width=device-width, initial-scale=1.0') // CSS Remember to update also in Grunfile.js cssmin task! - link(rel='stylesheet', href='/bower_components/bootstrap/docs/assets/css/bootstrap.css') + link(rel='stylesheet', href='/#{env.getBuildUrl("bower_components/bootstrap/docs/assets/css/bootstrap.css")}') // Keep this out of build because the one after has some images and would like not to override it - link(rel='stylesheet', href='/bower_components/bootstrap/docs/assets/css/bootstrap-responsive.css') - link(href='/bower_components/bootstrap/docs/assets/css/docs.css', rel='stylesheet') + link(rel='stylesheet', href='/#{env.getBuildUrl("bower_components/bootstrap/docs/assets/css/bootstrap-responsive.css")}') + link(rel='stylesheet', href='/#{env.getBuildUrl("bower_components/bootstrap/docs/assets/css/docs.css")}') - link(rel='stylesheet', href='/static.css') + link(rel='stylesheet', href='/#{env.getBuildUrl("static.css")}') // JS - if(layoutEnv.NODE_ENV == 'production'){ - script(type='text/javascript', src='/static.js') + script(type='text/javascript', src='/#{env.getBuildUrl("static.js")') - }else{ // Remember to update the file list in Gruntfile.js! script(type='text/javascript', src='/bower_components/jquery/jquery.min.js') From 940861ad67a7127ecdadc9bbbe0860d0ac1760d1 Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Tue, 10 Sep 2013 14:43:30 +0200 Subject: [PATCH 4/5] small comment fix --- Gruntfile.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gruntfile.js b/Gruntfile.js index 8e65954c76..63a665e329 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -114,7 +114,7 @@ module.exports = function(grunt) { } }, - // UPDATE IT! + // UPDATE IT WHEN YOU ADD SOME FILES NOT ALREADY MATCHED! hashres: { build: { options: { @@ -131,7 +131,7 @@ module.exports = function(grunt) { nodemon: { dev: { - ignoredFiles: ['public/*', 'Gruntfile.js', 'views/*', 'build/*'] // Do not work! + ignoredFiles: ['public/*', 'Gruntfile.js', 'views/*', 'build/*'] } }, From 6e8a57004f6e170ed5d06dfc98e0ee879c02240b Mon Sep 17 00:00:00 2001 From: Matteo Pagliazzi Date: Tue, 10 Sep 2013 14:54:23 +0200 Subject: [PATCH 5/5] exclude build in nodemonignore --- .nodemonignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.nodemonignore b/.nodemonignore index e384b68122..17de44ee85 100644 --- a/.nodemonignore +++ b/.nodemonignore @@ -1,3 +1,4 @@ public/* views/* +build/* Gruntfile.js \ No newline at end of file