Skip to content

Instantly share code, notes, and snippets.

@grimen
Last active December 19, 2015 10:39
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save grimen/5941799 to your computer and use it in GitHub Desktop.
Save grimen/5941799 to your computer and use it in GitHub Desktop.
HTML5/S3/Grunt/Make/Pow project setup.
{
"directory": "app/components"
}
#!/usr/bin/env ruby
# See `Gemfile`
require 'pow_proxy'
run PowProxy.new
PORT=9990
AWS_S3_KEY=
AWS_S3_SECRET=
#!/usr/bin/env bash
echo "[.powenv]: PORT: $PORT"
echo "[.powenv]: project path: $(pwd)"
# Detect ".env" file path.
if [ -z $ENV_FILE ]
then ENV_FILE="./.env"
fi
echo "[.powenv]: project .env: $ENV_FILE"
# Load ".env" file.
if [ -f $ENV_FILE ]
then source $ENV_FILE
fi
# Detect unique project file to generate default PORT based on.
for project_id_file in ".powder" "./package.json"
do
if [ -f "$project_id_file" ]
then
PROJECT_ID_FILE=$project_id_file
break
fi
done
echo "[.powenv]: project .env PORT: $PORT"
# Generate default PORT for this project.
if [ -f $PROJECT_ID_FILE ]
then
PROJECT_MD5=`cat $PROJECT_ID_FILE | echo -n | md5sum | cut -f1 -d" "`
PROJECT_NUMBER=`echo $(( 0x${PROJECT_MD5%% *} )) | cut -f2 -d"-"` &>/dev/null
PROJECT_PORT_RANGE_FROM=3000
PROJECT_PORT_RANGE_TO=9999
PROJECT_PORT_DEFAULT=`expr $PROJECT_PORT_RANGE_FROM + $PROJECT_NUMBER % $PROJECT_PORT_RANGE_TO`
PROJECT_PORT_FORCE=0
if [ $PROJECT_PORT_FORCE -gt 0 ]
then
echo "[.powenv]: override PORT: $PORT => $PROJECT_PORT_DEFAULT"
PORT=$PROJECT_PORT_DEFAULT
else
if [ -z $PORT ]
then
echo "[.powenv]: undefined PORT: $PORT => $PROJECT_PORT_DEFAULT"
PORT=$PROJECT_PORT_DEFAULT
else
echo "[.powenv]: defined PORT: $PORT"
fi
fi
fi
# Pow environment.
export POW_PROXY_HOST=localhost
export POW_PROXY_PORT=$PORT
# Log
echo "[.powenv]: PROJECT_PORT_DEFAULT: $PROJECT_PORT_DEFAULT"
echo "[.powenv]: POW_PROXY_HOST: $POW_PROXY_HOST"
echo "[.powenv]: POW_PROXY_PORT: $POW_PROXY_PORT"
#!/usr/bin/env bash
if [ -f "$rvm_path/scripts/rvm" ] && [ -f ".rvmrc" ]; then
source "$rvm_path/scripts/rvm"
source ".rvmrc"
fi
#!/usr/bin/env bash
rvm use 1.9.3
<!DOCTYPE html>
<html lang="en" ng-app>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1"/>
<title>App ∙ Merchii</title>
<link rel="shortcut icon" href="favicon.ico" />
<!-- build:css styles/index.css -->
<link rel="stylesheet" type="text/css" href="styles/main.css">
<link rel="stylesheet" type="text/css" href="styles/app.css">
<!-- endbuild -->
<!-- build:js scripts/init.min.js -->
<script type="text/javascript" src="components/modernizr/modernizr.js"></script>
<script type="text/javascript" src="components/requirejs/require.js"></script>
<!-- endbuild -->
<!-- build:js scripts/index.min.js -->
<script type="text/javascript" src="scripts/main.js"></script>
<!-- endbuild -->
</head>
<body>
<div ng-view></div>
</body>
</html>
'use strict';
// Examples:
// - https://github.com/tnajdek/angular-requirejs-seed
require.config({
baseUrl: 'scripts',
paths: {
'es5-shim': '../components/es5-shim/es5-shim',
'json3': '../components/json3/lib/json3',
'jquery': '../components/jquery/jquery',
'async': '../components/async/lib/async',
'sugar': '../components/sugar/release/sugar-full.development',
'sugar-core': '../components/sugar/lib/core',
'sugar-array': '../components/sugar/lib/array',
'sugar-date': '../components/sugar/lib/date',
'sugar-date_ranges': '../components/sugar/lib/date_ranges',
'sugar-function': '../components/sugar/lib/function',
'sugar-number': '../components/sugar/lib/number',
'sugar-object': '../components/sugar/lib/object',
'sugar-regexp': '../components/sugar/lib/regexp',
'sugar-string': '../components/sugar/lib/string',
'angular': '../components/angular/angular',
'angular-resource': '../components/angular-resource/angular-resource',
'angular-cookies': '../components/angular-cookies/angular-cookies',
'angular-sanitize': '../components/angular-sanitize/angular-sanitize',
'angular-mocks': '../components/angular-mocks/angular-mocks',
'angular-scenario': '../components/angular-scenario/angular-scenario',
'foundation': '../components/foundation/js/foundation/foundation',
'foundation-alerts': '../components/foundation/js/foundation/foundation.alerts',
'foundation-clearing': '../components/foundation/js/foundation/foundation.clearing',
'foundation-cookie': '../components/foundation/js/foundation/foundation.cookie',
'foundation-dropdown': '../components/foundation/js/foundation/foundation.dropdown',
'foundation-forms': '../components/foundation/js/foundation/foundation.forms',
'foundation-joyride': '../components/foundation/js/foundation/foundation.joyride',
'foundation-magellan': '../components/foundation/js/foundation/foundation.magellan',
'foundation-orbit': '../components/foundation/js/foundation/foundation.orbit',
'foundation-placeholder': '../components/foundation/js/foundation/foundation.placeholder',
'foundation-reveal': '../components/foundation/js/foundation/foundation.reveal',
'foundation-section': '../components/foundation/js/foundation/foundation.section',
'foundation-tooltips': '../components/foundation/js/foundation/foundation.tooltips',
'foundation-topbar': '../components/foundation/js/foundation/foundation.topbar'
},
shim: {
'jquery': { deps: [], exports: '$' },
'async': { deps: [], exports: 'async' },
'sugar-core': { deps: [] },
'sugar-array': { deps: ['sugar-core'] },
'sugar-date': { deps: ['sugar-core'] },
'sugar-date_ranges': { deps: ['sugar-core'] },
'sugar-function': { deps: ['sugar-core'] },
'sugar-number': { deps: ['sugar-core'] },
'sugar-object': { deps: ['sugar-core'] },
'sugar-regexp': { deps: ['sugar-core'] },
'sugar-string': { deps: ['sugar-core'] },
'angular': { deps: ['jquery'], exports: 'angular' },
'angular-resource': { deps: ['angular'], exports: 'angular.resource' },
'angular-cookies': { deps: ['angular'], exports: 'angular.cookies' },
'angular-sanitize': { deps: ['angular'], exports: 'angular.sanitize' },
'angular-mocks': { deps: ['angular'], exports: 'angular.mocks' },
'angular-scenario': { deps: ['angular'], exports: 'angular.scenario' },
'foundation': { deps: ['jquery'], exports: 'Foundation' },
'foundation-alerts': { deps: ['foundation'] },
'foundation-clearing': { deps: ['foundation'] },
'foundation-cookie': { deps: ['foundation'] },
'foundation-dropdown': { deps: ['foundation'] },
'foundation-forms': { deps: ['foundation'] },
'foundation-joyride': { deps: ['foundation'] },
'foundation-magellan': { deps: ['foundation'] },
'foundation-orbit': { deps: ['foundation'] },
'foundation-placeholder': { deps: ['foundation'] },
'foundation-reveal': { deps: ['foundation'] },
'foundation-section': { deps: ['foundation'] },
'foundation-tooltips': { deps: ['foundation'] },
'foundation-topbar': { deps: ['foundation'] }
},
priority: ['angular']
});
define('main', [
'es5-shim',
'json3',
'jquery',
'angular',
'async',
'foundation',
'./app',
'./controllers/example'
]);
// NOTE: Loading shims first to avoid bloating exports.
require([
'es5-shim',
'json3',
'sugar'
], function() {
require([
'jquery',
'angular',
'async',
'foundation'
], function ($, angular, async, Foundation) {
require(['app'], function (app) {
$(document).foundation();
});
});
});
{
"name": "merchii-studio-app-boilerplate",
"version": "0.1.0",
"dependencies": {
"jquery": "latest",
"json3": "latest",
"es5-shim": "latest",
"angular": "latest",
"angular-resource": "latest",
"angular-cookies": "latest",
"angular-sanitize": "latest",
"foundation": "latest",
"requirejs": "latest",
"modernizr": "latest",
"async": "latest",
"sugar": "latest"
},
"devDependencies": {
"angular-mocks": "latest",
"angular-scenario": "latest"
}
}
#!/usr/bin/env ruby
source 'https://rubygems.org'
# https://github.com/Rodreegez/powder
gem 'powder'
# See: https://github.com/spagalloco/pow_proxy
gem 'pow_proxy'
'use strict';
module.exports = function (grunt) {
// Load Grunt tasks (in `package.json`).
require('matchdep').filterDev('grunt-*').forEach(grunt.loadNpmTasks);
// Load project ENV (in `.env`)
require('fs').readFileSync(__dirname + '/.env', 'utf8').match(/([\w+]+)\s*\=\s*(.*)/gmi).forEach(function(line) {
var key_value = line.split(/\s*\=\s*/);
process.env[key_value[0]] = key_value[1];
});
// Grunt config.
var config = {
app: 'app',
tmp: '.tmp',
dist: 'dist',
development: {
options: {
variables: {
'env': 'development',
'bucket': 'studio-app-template.merchii.dev',
'port': parseInt(process.env.PORT, 10)
}
}
},
production: {
options: {
variables: {
'env': 'production',
'bucket': 'studio-app-template.merchii.com'
}
}
}
};
// Helper: Mount path `connect` middleware.
var mountFolder = function (connect, dir) {
return connect.static(require('path').resolve(dir));
};
// Detect app path.
try {
config.app = require('./bower.json').appPath || config.app;
} catch (e) {}
// Grunt init.
grunt.initConfig({
pkg: '<json:package.json>',
component: '<json:bower.json>',
config: config,
livereload: {
port: config.development.options.variables.port + 100
},
connect: {
options: {
port: config.development.options.variables.port,
hostname: 'localhost'
},
test: {
options: {
middleware: function (connect) {
return [
mountFolder(connect, config.tmp),
mountFolder(connect, config.test)
];
}
}
},
development: {
options: {
middleware: function (connect) {
return [
mountFolder(connect, config.tmp),
mountFolder(connect, config.app)
];
}
}
},
livereload: {
options: {
middleware: function (connect) {
return [
require('grunt-contrib-livereload/lib/utils').livereloadSnippet,
mountFolder(connect, config.tmp),
mountFolder(connect, config.app)
];
}
}
},
dist: {
options: {
middleware: function (connect) {
return [
mountFolder(connect, config.dist)
];
}
}
}
},
open: {
server: {
url: 'http://localhost:<%= connect.options.port %>/index.html'
}
},
clean: {
tmp: {
files: [{
dot: true,
src: [
'.sass-cache',
'<%= config.tmp %>'
]
}]
},
dist: {
files: [{
dot: true,
src: [
'.sass-cache',
'<%= config.tmp %>',
'<%= config.dist %>/*',
'!<%= config.dist %>/.git*'
]
}]
},
server: {
files: [{
dot: true,
src: [
'.sass-cache'
]
}]
}
},
compass: {
options: {
sassDir: '<%= config.app %>/styles',
cssDir: '<%= config.tmp %>/styles',
imagesDir: '<%= config.app %>/images',
javascriptsDir: '<%= config.app %>/scripts',
fontsDir: '<%= config.app %>/fonts',
importPath: [
'<%= config.app %>/components/foundation/scss',
'<%= config.app %>/styles'
],
relativeAssets: false
},
tmp: {
options: {
debugInfo: false
}
},
dist: {
options: {
debugInfo: false
}
},
server: {
options: {
debugInfo: true
}
}
},
copy: {
tmp: {
files: [
{
expand: true,
dot: true,
cwd: '<%= config.app %>',
dest: '<%= config.tmp %>',
src: [
'*.{ico,png,txt,html}',
'images/**/*.{gif,webp,svg}',
'fonts/**/*.{svg,eot,ttf,woff}',
'scripts/**/*.js',
'views/**/*.html',
'components/**/*.{js,css}',
'!components/*/{,*/}{build,Gruntfile}.js',
'!components/*/{doc,docs,test,tests,vendor}/*'
]
}
]
},
dist: {
files: [
{
expand: true,
dot: true,
cwd: '<%= config.tmp %>',
dest: '<%= config.dist %>',
src: [
'*.{ico,png,txt,html}',
'images/**/*.{gif,webp,svg}',
'fonts/**/*.{svg,eot,ttf,woff}',
'views/**/*.html',
'components/**/*.{js,css}',
'!components/*/{,*/}{build,Gruntfile}.js',
'!components/*/{doc,docs,test,tests,vendor}/*'
]
}
]
}
},
replace: {
tmp: {
options: {
variables: {
'env': '<%= grunt.config.get("env") %>',
'timestamp': '<%= new Date().getTime() %>'
},
prefix: '@@'
},
files: [
{
expand: true,
cwd: '<%= config.tmp %>',
src: [
'**/*.html',
'styles/**/*.css',
'scripts/**/*.js'
],
dest: '<%= config.tmp %>'
}
]
}
},
uglify: {
dist: {
files: {
'<%= config.dist %>/scripts/init.min.js': [
'<%= config.tmp %>/components/modernizr/modernizr.js',
'<%= config.tmp %>/components/requirejs/require.js'
],
'<%= config.dist %>/scripts/index.min.js': [
'<%= config.tmp %>/scripts/index.js'
]
}
}
},
cssmin: {
dist: {
files: {
'<%= config.dist %>/styles/index.css': [
'<%= config.tmp %>/styles/main.css',
'<%= config.tmp %>/styles/app.css'
]
}
}
},
imagemin: {
dist: {
files: [{
expand: true,
cwd: '<%= config.tmp %>/images',
src: '{,*/}*.{png,jpg,jpeg}',
dest: '<%= config.dist %>/images'
}]
}
},
htmlmin: {
dist: {
options: {
removeCommentsFromCDATA: true,
collapseWhitespace: false,
collapseBooleanAttributes: true,
removeAttributeQuotes: true,
removeRedundantAttributes: false,
useShortDoctype: true,
removeEmptyAttributes: false,
removeOptionalTags: false
},
files: [{
expand: true,
cwd: '<%= config.tmp %>',
src: [
'*.html',
'views/*.html',
'views/**/*.html'
],
dest: '<%= config.dist %>'
}]
}
},
ngmin: {
dist: {
files: [{
expand: true,
cwd: '<%= config.tmp %>/scripts',
src: '**/*.js',
dest: '<%= config.dist %>/scripts'
}]
}
},
rev: {
dist: {
files: {
src: [
'<%= config.dist %>/scripts/{,*/}*.js',
'<%= config.dist %>/styles/{,*/}*.css',
'<%= config.dist %>/images/{,*/}*.{png,jpg,jpeg,gif,webp}',
'<%= config.dist %>/fonts/{,*/}*.{svg,eot,ttf,woff}',
'<%= config.dist %>/views/{,*/}*.{html}',
'<%= config.dist %>/components/*/*.min.{js,css}'
]
}
}
},
useminPrepare: {
options: {
dest: '<%= config.dist %>'
},
html: [
'<%= config.app %>/*.html',
'<%= config.app %>/views/**/*.html'
]
},
usemin: {
options: {
dirs: [
'<%= config.dist %>'
]
},
html: [
'<%= config.dist %>/{,*/}*.html',
'<%= config.dist %>/views/**/*.html'
],
css: [
'<%= config.dist %>/styles/{,*/}*.css'
]
},
compress: {
main: {
options: {
mode: 'gzip',
pretty: true,
level: 9
},
expand: true,
cwd: '<%= config.dist %>/',
src: [
'**/*.html',
'styles/**/*.css',
'scripts/**/*.js'
],
dest: '<%= config.dist %>'
}
},
requirejs: {
tmp: {
options: {
baseUrl: '<%= config.app %>/scripts',
mainConfigFile: '<%= config.app %>/scripts/main.js',
out: '<%= config.tmp %>/scripts/index.js',
include: 'main',
optimize: 'none',
generateSourceMaps: false,
preserveLicenseComments: false
}
}
},
watch: {
copy: {
files: [
'<%= config.app %>/**/*.html',
'<%= config.app %>/styles/**/*.css',
'<%= config.app %>/scripts/**/*.js'
],
tasks: ['copy:tmp']
},
compass: {
files: [
'<%= config.app %>/styles/{,*/}*.{scss,sass}'
],
tasks: ['compass:tmp']
},
livereload: {
files: [
'<%= config.tmp %>/**/*.html',
'<%= config.tmp %>/styles/**/*.css',
'<%= config.tmp %>/scripts/**/*.js'
],
tasks: ['replace:tmp', 'livereload']
}
},
s3: {
options: {
key: process.env.AWS_S3_KEY,
secret: process.env.AWS_S3_SECRET,
access: 'public-read',
region: 'eu-west-1',
maxOperations: 20
},
delete_files: [
{
src: '**/*'
}
],
upload_files: [
{
// root
src: '<%= config.dist %>/*',
dest: ''
},
{
// /images
src: '<%= config.dist %>/images/*',
dest: 'images/'
},
{
// /fonts
src: '<%= config.app %>/fonts/*.{svg,eot,ttf,woff}',
dest: 'fonts/'
},
{
// /styles
src: '<%= config.dist %>/styles/*.css',
dest: 'styles/'
},
{
// /scripts
src: '<%= config.dist %>/scripts/*.js',
dest: 'scripts/'
},
{
// /views
src: '<%= config.dist %>/views/*.html',
dest: 'views/'
}
],
development: {
options: {
bucket: '<%= config.development.options.variables.bucket %>',
encodePaths: true
},
upload: '<%= s3.upload_files %>'
},
production: {
options: {
bucket: '<%= config.production.options.variables.bucket %>',
encodePaths: true
},
upload: '<%= s3.upload_files %>'
}
}
});
grunt.renameTask('regarde', 'watch');
grunt.registerTask('copy:server', ['copy:tmp']);
grunt.registerTask('replace:server', ['replace:tmp']);
grunt.registerTask('livereload:server', ['livereload-start']);
grunt.registerTask('connect:server', ['livereload:server', 'connect:livereload']);
// task: server
grunt.registerTask('server:development', function (target) {
if (target === 'dist') {
return grunt.task.run(['build', 'connect:dist:keepalive']);
}
grunt.task.run([
'config:development',
'clean:server',
'compass:server',
'copy:server',
'replace:server',
'connect:server',
'watch',
// 'open'
]);
});
// task: build
grunt.registerTask('build:development', [
'config:development',
'clean',
'compass:tmp',
'copy:tmp',
'requirejs:tmp',
'replace:tmp',
'useminPrepare',
'copy:dist',
'ngmin:dist',
'uglify:dist',
'htmlmin:dist',
'cssmin:dist',
'imagemin:dist',
'rev:dist',
'usemin',
// 'clean:tmp'
]);
grunt.registerTask('build:production', [
'config:development',
'clean',
'compass:tmp',
'copy:tmp',
'requirejs:tmp',
'replace:tmp',
'useminPrepare',
'copy:dist',
'ngmin:dist',
'uglify:dist',
'htmlmin:dist',
'cssmin:dist',
'imagemin:dist',
'rev:dist',
'usemin',
// 'clean:tmp'
]);
// task: release
grunt.registerTask('release:development', ['build:development', 's3:development']);
grunt.registerTask('release:production', ['build:production', 's3:production']);
// ---
// alias: server
grunt.registerTask('server:dev', ['server:development']);
grunt.registerTask('server', ['server:dev']);
// alias: build
grunt.registerTask('build:dev', ['build:development']);
grunt.registerTask('build:prod', ['build:production']);
grunt.registerTask('build', ['build:dev']);
// alias: release
grunt.registerTask('release:dev', ['release:development']);
grunt.registerTask('release:prod', ['release:production']);
grunt.registerTask('release', ['release:dev']);
grunt.registerTask('default', ['build']);
};
install:
make clean \
&& npm install \
&& ./node_modules/bower/bin/bower install \
&& gem install bundler \
&& bundle install \
&& powder link
update:
npm update \
&& ./node_modules/bower/bin/bower update
&& bundle update
clean:
rm -rf ./node_modules \
&& rm -rf ./app/components \
&& rm -rf ./.tmp \
&& rm -rf ./.sass-cache \
&& rm -rf ./dist
server:
grunt server
build:
grunt build
open:
powder open
static:
make pow-static
proxy:
make pow-proxy
pow-static:
if [ -e ./public ]; then rm -f ./public; fi \
&& if [ ! -d ./dist ]; then mkdir ./dist; fi \
&& ln -sf ./dist ./public \
&& if [ ! -f ./public/index.html ]; then echo "$(PWD)/public/index.html" > ./public/index.html; fi \
&& if [ -e ./config.ru ]; then rm -f ./config.ru; fi \
&& tree -LC 1 \
&& powder restart
pow-proxy:
if [ -e ./public ]; then rm -f ./public; fi \
&& if [ -f ./config.ru ]; then rm -f ./config.ru; fi \
&& if [ ! -e ./config.ru ]; then ln -sf ./.config.ru ./config.ru; fi \
&& tree -LC 1 \
&& powder restart
.PHONY: install
{
"name": "merchii-studio-app-boilerplate",
"private": true,
"version": "0.1.0",
"engines": {
"node": ">= 0.10.0"
},
"dependencies": {},
"devDependencies": {
"bower": "latest",
"grunt": "latest",
"grunt-contrib-copy": "latest",
"grunt-contrib-concat": "latest",
"grunt-contrib-uglify": "latest",
"grunt-contrib-compass": "latest",
"grunt-contrib-cssmin": "latest",
"grunt-contrib-connect": "latest",
"grunt-contrib-clean": "latest",
"grunt-contrib-htmlmin": "latest",
"grunt-contrib-imagemin": "latest",
"grunt-contrib-livereload": "latest",
"grunt-contrib-compress": "latest",
"grunt-contrib-requirejs": "latest",
"grunt-usemin": "latest",
"grunt-ngmin": "latest",
"grunt-regarde": "latest",
"grunt-rev": "latest",
"grunt-open": "latest",
"grunt-replace": "latest",
"grunt-config": "latest",
"grunt-s3": "latest",
"matchdep": "latest"
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment