Skip to content

Commit 6540c51

Browse files
committed
Initial commit, v0.1.0
1 parent 04c8a8e commit 6540c51

21 files changed

Lines changed: 664 additions & 0 deletions

.bowerrc

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"directory": "vendor",
3+
"json": "bower.json"
4+
}

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
._.DS_Store
2+
.sass-cache/
3+
dist/
4+
node_modules/
5+
vendor/

.jshintrc

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
{
2+
// ECMAScript 5
3+
"es5" : false, // Allow ECMAScript 5 syntax.
4+
"strict" : true, // Require `use strict` pragma in every file.
5+
"globalstrict" : true, // Allow global "use strict" (also enables 'strict').
6+
7+
"immed" : true,
8+
"sub" : true,
9+
"devel" : true,
10+
"forin" : true,
11+
"curly" : true,
12+
"browser" : true,
13+
"loopfunc" : true,
14+
"trailing" : true,
15+
"eqeqeq" : true,
16+
"indent" : 4,
17+
"newcap" : true,
18+
"noarg" : true,
19+
"node" : true,
20+
"noempty" : true,
21+
"undef" : true,
22+
"white" : false,
23+
"predef": [
24+
"google",
25+
"angular",
26+
"_"
27+
]
28+
}

README.md

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
Why ng-devstack?
2+
================
3+
This project has been inspired by another great concept <a href="http://joshdmiller.github.io/ng-boilerplate/">ngBoilerplate</a>, allowing to create modern web applications in AngularJS. It follows all the best practices introduced in ngBoilerplate such as component/feature-oriented directory structure, intelligent build system, etc. However, I decided to improve it a little bit and create my own boilerplate since I missed some basic features like applying changes in real-time on adding new files to project, images optimization, remove redundant code on compiling output HTML, plus ngBoilerplate hasn't been updated for months. Now this all has been made possible. Please welcome ng-devstack!
4+
5+
Features
6+
========
7+
* integration with gulp
8+
* dependency management with Bower
9+
* feature-oriented directory structure
10+
* Livereload fully handled server-side with NodeJS/Express (without installing additional extensions for browsers)
11+
* real-time applying changes to website on adding new files (no need to relaunch Watch task)
12+
* caching AngularJS templates to avoid additional server requests
13+
* pre-minifying AngularJS files
14+
* support for SASS (including Twitter Bootstrap official port to SASS)
15+
* support for JSHint
16+
* minify JS/CSS/HTML
17+
* remove logging (console.log(), etc.) from compiled JS code
18+
* images optimization on build (see Additional Info for details)
19+
* html5Mode support (see Additional Info for details)
20+
* integration with AngularUI Router & AngularUI Bootstrap
21+
22+
Requirements
23+
============
24+
* Ruby
25+
* NodeJS
26+
27+
Installation
28+
============
29+
1. Install SASS:
30+
31+
gem install sass
32+
33+
2. Install gulp globally, which is giving access to gulp's CLI:
34+
35+
npm install gulp -g
36+
37+
3. Install gulp locally to the project with other required plugins:
38+
39+
npm install
40+
41+
4. Install dependencies:
42+
43+
bower install
44+
45+
Usage
46+
=====
47+
To build the application simply type:
48+
49+
gulp build
50+
51+
For development purposes, run watch task to build and start localhost with liverload:
52+
53+
gulp watch
54+
55+
Deploy the production version by running 'gulp compile', or more simple:
56+
57+
gulp
58+
59+
TODO
60+
=====
61+
- add authorization service
62+
- add E2E testing (Karma/Protractor)
63+
- add source maps support for SASS & JS
64+
- improve images/SVG optimization
65+
- update gulp configuration
66+
- add more comments to gulpfile
67+
- improve README.md

bower.json

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
{
2+
"name": "ng-devstack",
3+
"version": "0.1.0",
4+
"devDependencies": {
5+
"angular": "~1.2.12",
6+
"angular-bootstrap": "~0.10.0",
7+
"angular-mocks": "~1.2.12",
8+
"angular-ui-router": "0.2.7",
9+
"angular-ui-utils": "~0.1.1",
10+
"bootstrap-sass-official": "latest"
11+
},
12+
"dependencies": {}
13+
}

gulpfile.js

Lines changed: 254 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,254 @@
1+
/* jshint strict: false */
2+
3+
var gulp = require('gulp'),
4+
plugins = require('gulp-load-plugins')(),
5+
server = require('tiny-lr')();
6+
7+
var config = {
8+
app : 'src',
9+
build : 'build',
10+
dist : 'dist'
11+
};
12+
13+
var paths = {
14+
scripts : ['src/app/**', 'src/common/**', '!src/app/**/*.html', '!src/common/**/*.html', '!src/app/**/*.scss', '!src/common/**/*.scss'],
15+
templates : ['src/app/**', 'src/common/**', '!src/app/**/*.js', '!src/common/**/*.js', '!src/app/**/*.scss', '!src/common/**/*.scss'],
16+
sass : ['src/app/**', 'src/common/**', 'src/sass/**', '!src/app/**/*.js', '!src/common/**/*.js', '!src/app/**/*.html', '!src/common/**/*.html'],
17+
assets : 'src/assets/**',
18+
html : 'src/index.html'
19+
};
20+
21+
var vendor_files = {
22+
js: [
23+
'vendor/angular/angular.js',
24+
'vendor/angular-ui-router/release/angular-ui-router.js',
25+
'vendor/angular-bootstrap/ui-bootstrap-tpls.js'
26+
],
27+
css: [],
28+
assets: [
29+
'vendor/bootstrap-sass-official/vendor/assets/fonts/**/*'
30+
]
31+
};
32+
33+
var inject = {
34+
css : (vendor_files.css).concat(config.build + '/assets/*.css'),
35+
js : (vendor_files.js).concat([config.build + '/app/**/*.js', config.build + '/common/**/*.js'])
36+
};
37+
38+
39+
/*
40+
Subtasks: Watch
41+
*/
42+
gulp.task('watch', ['sass', 'lint', 'html2js', 'vendor_js', 'img', 'vendor_assets', 'inject'], function () {
43+
require('./server.js')(server);
44+
45+
gulp.watch(paths.sass, function (event) {
46+
var files = [config.app + '/sass/main.scss', config.app + '/common/**/*.scss', config.app + '/app/**/*.scss'];
47+
return fnSass(files).pipe(plugins.livereload(server));
48+
});
49+
50+
gulp.watch(paths.templates, function (event) {
51+
return fnHtml2Js(paths.templates).pipe(plugins.livereload(server));
52+
});
53+
54+
gulp.watch(paths.scripts, function (event) {
55+
return fnLint(event.path).pipe(plugins.livereload(server));
56+
});
57+
58+
gulp.watch(paths.assets, function (event) {
59+
return fnImg(event.path).pipe(plugins.livereload(server));
60+
});
61+
62+
gulp.watch(paths.html, function (event) {
63+
return fnInject(event.path).pipe(plugins.livereload(server));
64+
});
65+
});
66+
67+
68+
/*
69+
Subtasks: Clean up
70+
*/
71+
gulp.task('clean', function () {
72+
return gulp.src([config.build, config.dist], { read: false })
73+
.pipe(plugins.rimraf());
74+
});
75+
76+
77+
/*
78+
Subtasks: Compile SASS, Autoprefix and minify
79+
*/
80+
var fnSass = function (path) {
81+
return gulp.src(path)
82+
.pipe(plugins.plumber())
83+
.pipe(plugins.filesize()) // .pipe(plugins.size({ showFiles: true }))
84+
.pipe(plugins.concat('main.scss'))
85+
.pipe(plugins.rubySass({ style: 'expanded' }))
86+
.pipe(plugins.autoprefixer('last 2 version', 'safari 5', 'ie 8', 'ie 9', 'opera 12.1', 'ios 6', 'android 4'))
87+
.pipe(plugins.filesize()) // .pipe(plugins.size({ showFiles: true }))
88+
.pipe(gulp.dest(config.build + '/assets'));
89+
};
90+
gulp.task('sass', function () {
91+
var files = [config.app + '/sass/main.scss', config.app + '/common/**/*.scss', config.app + '/app/**/*.scss'];
92+
return fnSass(files);
93+
});
94+
95+
gulp.task('styles', ['sass'], function () {
96+
return gulp.src(config.build + '/assets/*.css')
97+
.pipe(plugins.bytediff.start())
98+
.pipe(plugins.minifyCss({ keepSpecialComments: 0 }))
99+
.pipe(plugins.rename({ suffix: '.min' }))
100+
.pipe(plugins.bytediff.stop())
101+
.pipe(gulp.dest(config.dist + '/assets'));
102+
});
103+
104+
105+
/*
106+
Subtasks: JSHint, concat, and minify JavaScript
107+
*/
108+
var fnLint = function (path) {
109+
return gulp.src(path, { base: 'src' })
110+
.pipe(plugins.plumber())
111+
.pipe(plugins.jshint('.jshintrc'))
112+
.pipe(plugins.jshint.reporter('default'))
113+
.pipe(gulp.dest(config.build));
114+
};
115+
gulp.task('lint', function () {
116+
return fnLint(paths.scripts);
117+
});
118+
119+
120+
/*
121+
Subtask Cache AngularJS templates
122+
*/
123+
var fnHtml2Js = function (path) {
124+
return gulp.src(path)
125+
.pipe(plugins.minifyHtml({
126+
empty: true,
127+
spare: true,
128+
quotes: true
129+
}))
130+
.pipe(plugins.ngHtml2js({
131+
moduleName: 'templates'
132+
}))
133+
.pipe(plugins.concat('app-templates.js'))
134+
.pipe(gulp.dest(config.build + '/app'));
135+
};
136+
gulp.task('html2js', function () {
137+
return fnHtml2Js(paths.templates);
138+
});
139+
140+
141+
/*
142+
Subtask: Copy vendor JS files to /build/
143+
*/
144+
gulp.task('vendor_js', function () {
145+
if (!vendor_files.js.length) {
146+
return;
147+
}
148+
return gulp.src(vendor_files.js, { base: '.' })
149+
.pipe(gulp.dest(config.build));
150+
});
151+
152+
gulp.task('scripts', ['lint', 'html2js', 'vendor_js'], function () {
153+
var arr = vendor_files.js.concat(paths.scripts);
154+
return gulp.src(arr)
155+
.pipe(plugins.concat('main.js'))
156+
.pipe(plugins.bytediff.start())
157+
.pipe(plugins.ngmin())
158+
.pipe(plugins.uglify())
159+
.pipe(plugins.removelogs())
160+
.pipe(plugins.rename({ suffix: '.min' }))
161+
.pipe(plugins.bytediff.stop())
162+
.pipe(gulp.dest(config.dist + '/assets'));
163+
});
164+
165+
166+
/*
167+
Subtask: Copy vendor assets to /build/
168+
*/
169+
gulp.task('vendor_assets', function () {
170+
if (!vendor_files.assets.length) {
171+
return;
172+
}
173+
return gulp.src(vendor_files.assets)
174+
.pipe(gulp.dest(config.build + '/assets'));
175+
});
176+
177+
178+
/*
179+
Subtasks: Compress Images & copy assets
180+
*/
181+
var fnImg = function (path) {
182+
return gulp.src(path)
183+
.pipe(gulp.dest(config.build + '/assets'));
184+
};
185+
gulp.task('img', function () {
186+
return fnImg(paths.assets);
187+
});
188+
189+
gulp.task('assets', ['img', 'vendor_assets'], function () {
190+
return gulp.src(paths.assets)
191+
.pipe(plugins.plumber())
192+
// .pipe(plugins.bytediff.start())
193+
.pipe(plugins.newer(config.dist + '/assets'))
194+
// .pipe(plugins.imagemin({ optimizationLevel: 5, progressive: true, interlaced: true }))
195+
// .pipe(plugins.bytediff.stop())
196+
.pipe(gulp.dest(config.dist + '/assets'));
197+
});
198+
199+
200+
/*
201+
Subtask: Inject CSS & JS to index.html source
202+
*/
203+
var fnInject = function (path) {
204+
return gulp.src(inject.css.concat(inject.js), { read: false })
205+
.pipe(plugins.inject(path, {
206+
addRootSlash: false,
207+
ignorePath: ['/', 'build/']
208+
}))
209+
.pipe(gulp.dest(config.build));
210+
};
211+
gulp.task('inject', ['sass', 'lint', 'html2js'], function () {
212+
return fnInject(config.app + '/index.html');
213+
});
214+
215+
216+
/*
217+
Subtask: Replace non-optimized HTML blocks
218+
*/
219+
gulp.task('html-replace', ['inject'], function () {
220+
return gulp.src(config.build + '/index.html')
221+
.pipe(plugins.htmlReplace({
222+
css: 'assets/main.min.css',
223+
js: 'assets/main.min.js'
224+
}))
225+
.pipe(gulp.dest(config.dist));
226+
});
227+
228+
/*
229+
Subtasks: Compile and minify HTML
230+
*/
231+
gulp.task('html', ['html-replace'], function () {
232+
return gulp.src(config.dist + '/index.html')
233+
.pipe(plugins.plumber())
234+
.pipe(plugins.minifyHtml({ quotes: true }))
235+
.pipe(gulp.dest(config.dist));
236+
});
237+
238+
239+
240+
241+
/*
242+
The default task
243+
*/
244+
gulp.task('build', ['clean'], function () {
245+
gulp.start('sass', 'lint', 'html2js', 'vendor_js', 'img', 'vendor_assets', 'inject');
246+
});
247+
248+
gulp.task('compile', ['build'], function () {
249+
gulp.start('styles', 'scripts', 'assets', 'html-replace', 'html');
250+
});
251+
252+
gulp.task('default', function () {
253+
gulp.start('compile');
254+
});

0 commit comments

Comments
 (0)