├── .bowerrc ├── .gitignore ├── .jshintrc ├── LICENSE ├── README.md ├── app.js ├── bower.json ├── gulp ├── common │ └── env-util.js ├── desktop │ ├── build-scripts.js │ ├── build-styles.js │ ├── build-templates.js │ └── build.js ├── develop │ ├── build-browser-sync.js │ └── build.js ├── gulp-docker.js └── mobile │ ├── build-scripts.js │ ├── build-styles.js │ ├── build-templates.js │ └── build.js ├── gulpfile.js ├── karma.conf.js ├── middleware ├── error-handling │ ├── default.js │ └── error-config.js ├── middleware-config.js └── router │ ├── desktop │ ├── default.js │ └── router-dockers.js │ ├── mobile │ ├── default.js │ └── router-dockers.js │ └── router-config.js ├── node-app ├── common │ └── loggers.js ├── config │ ├── locals.js │ └── ssl │ │ ├── cert.pem │ │ └── key.pem ├── swig │ ├── filters.js │ └── swig-config.js └── utils │ └── detector.js ├── package.json ├── public ├── images │ ├── desktop │ │ └── forkme_right.png │ ├── favicon.ico │ └── mobile │ │ └── forkme_right.png ├── scripts │ ├── desktop │ │ ├── angular-app.js │ │ ├── bootstrap.js │ │ ├── controllers │ │ │ └── default │ │ │ │ └── samples-controller.js │ │ ├── directives │ │ │ └── components │ │ │ │ └── mock-tabs.js │ │ ├── filters │ │ │ └── common │ │ │ │ └── mock-upper-case.js │ │ ├── optimize-main.js │ │ ├── optimize-require-config.js │ │ ├── require-config.js │ │ └── services │ │ │ └── default │ │ │ └── samples-service.js │ └── mobile │ │ ├── angular-app.js │ │ ├── bootstrap.js │ │ ├── optimize-main.js │ │ ├── optimize-require-config.js │ │ └── require-config.js └── styles │ ├── desktop │ ├── default │ │ ├── index.less │ │ └── samples.less │ ├── layout │ │ ├── footer.less │ │ └── header.less │ └── style.less │ └── mobile │ ├── default │ └── index.less │ ├── layout │ ├── footer.less │ └── header.less │ └── style.less ├── test └── desktop │ ├── angular-app-test.js │ ├── controllers │ └── default │ │ └── samples-controller-test.js │ ├── directives │ └── components │ │ └── mock-tabs-test.js │ ├── filters │ └── common │ │ └── mock-upper-case-test.js │ ├── services │ └── default │ │ └── samples-service-test.js │ └── test-main.js └── views ├── desktop ├── render │ ├── default │ │ ├── error.html │ │ ├── index.html │ │ ├── not-found.html │ │ └── samples.html │ ├── layout.html │ └── layout │ │ ├── footer.html │ │ └── header.html └── templates │ ├── components │ ├── mock-pane.html │ └── mock-tabs.html │ └── markdown │ └── README.html └── mobile ├── render ├── default │ ├── error.html │ ├── index.html │ └── not-found.html ├── layout.html └── layout │ ├── footer.html │ └── header.html └── templates └── markdown └── README.html /.bowerrc: -------------------------------------------------------------------------------- 1 | { 2 | "directory": "public/libs", 3 | "analytics": false, 4 | "timeout": 1200000 5 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .idea 2 | .log 3 | /node_modules 4 | /public/compiled 5 | /public/libs 6 | /report 7 | 8 | ### OSX template 9 | .DS_Store 10 | .AppleDouble 11 | .LSOverride -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "predef": [ 3 | "define", 4 | "require", 5 | "GlobalConfig", 6 | "angular", 7 | "inject" 8 | ], 9 | "bitwise": true, 10 | "curly": true, 11 | "eqeqeq": true, 12 | "forin": true, 13 | "maxerr": 1000, 14 | "undef": true, 15 | "unused": true, 16 | "eqnull": true, 17 | "loopfunc": true, 18 | "browser": true, 19 | "jasmine": true, 20 | "jquery": true, 21 | "node": true 22 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 ipluser 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## angularjs-requirejs-boilerplate 2 | A complete angularjs requirejs boilerplate for node. 3 | 4 | There are angular and test samples in the project, 5 | you can quick start your new project with angularjs-requirejs-boilerplate. 6 | 7 | ## Features 8 | ### Front-end 9 | * [angularjs](http://angularjs.org/), a JavaScript MVW Framework 10 | * [bootstrap](http://getbootstrap.com/), the most popular HTML, CSS, and JS framework for developing responsive, mobile first projects on the web 11 | * [jquery](https://jquery.org/), the Write Less, Do More, JavaScript Library 12 | * [less](http://lesscss.org/), a CSS pre-processor 13 | * [requirejs](http://requirejs.org/), a JavaScript file and module loader 14 | * etc 15 | 16 | ### Back-end 17 | * [expressjs](http://expressjs.com/), sinatra inspired web development framework for node.js 18 | * [gulp](http://gulpjs.com/), the streaming build system 19 | * [swig](http://paularmstrong.github.io/swig/), a simple, powerful, and extendable JavaScript Template Engine 20 | * etc 21 | 22 | ## Quick Start 23 | ### Install Dependencies: 24 | ```bash 25 | $ bower install 26 | $ npm install 27 | ``` 28 | 29 | ### Development 30 | Development Environment using gulp-nodemon, [browser-sync](https://www.browsersync.io/) and gulp-jshint. 31 | 1. Make sure isDevMode configuration is true in locals.js 32 | 2. Start development mode with `gulp --development` 33 | 3. Input `http://localhost:devPort` with browsers 34 | 35 | ### Production 36 | 1. Make sure isDevMode configuration is false in locals.js 37 | 2. Compile and build with `gulp --production` 38 | 3. Start the server with node or pm2 or others 39 | 4. Input `http://localhost:port` with browsers 40 | 41 | ### Configuration 42 | System configuration are stored in the locals.js file. 43 | 44 | ### Samples Page 45 | Start the server and input `http://localhost:port/samples` with browsers. 46 | 47 | ## Gulp 48 | Show task list with `gulp help`. 49 | 50 | ## Test 51 | Test using karma and jasmine, run the test with `npm test` or `karma start`. Unit and coverage test report are stored in report directory. 52 | 53 | ## Changelog 54 | ### 2.3.0 55 | - watch gulp files 56 | - the browser reload while restart nodemon
57 | 27.01.2016 58 | 59 | ### 2.2.1 60 | - fix task can not separate execution with development mode
61 | 25.01.2016 62 | 63 | ### 2.2.0 64 | - add build-templates task to optimize ngTemplates that registers AngularJS templates in the $templateCache 65 | - add error and listening event to server
66 | 17.01.2016 67 | 68 | ### 2.1.0 69 | - replace gulp-livereload with browser-sync 70 | - add gulp-help, gulp-size and others gulp components 71 | - remove less.js
72 | 10.01.2016 73 | 74 | ### 2.0.0 75 | - adjust directory and code of project 76 | - add angular samples page 77 | - add README.md preview
78 | 01.01.2016 79 | 80 | ### 1.1.1 81 | - fix mobile can not redirect 82 | - fix can not define custom router
83 | 18.11.2015 84 | 85 | ### 1.1.0 86 | - add gulp task named build-views that registers AngularJS templates in the $templateCache 87 | - add karma and size into gulpfile 88 | - replace chrome launcher with phantomjs launcher in karma 89 | - modify layout launcher and suffix of templateUrl
90 | 31.10.2015 91 | 92 | ### 1.0.0 93 | - initial release
94 | 18.10.2015 95 | 96 | ## License 97 | [MIT](https://github.com/ipluser/angularjs-requirejs-boilerplate/blob/master/LICENSE) 98 | -------------------------------------------------------------------------------- /app.js: -------------------------------------------------------------------------------- 1 | var express = require('express'), 2 | swig = require('swig'), 3 | locals = require('./node-app/config/locals'), 4 | swigConfig = require('./node-app/swig/swig-config'), 5 | middlewareConfig = require('./middleware/middleware-config'); 6 | 7 | var app = express(), 8 | port = locals.port; 9 | 10 | app.set('view engine', 'html'); 11 | app.set('views', __dirname + '/views'); 12 | app.engine('html', swig.renderFile); 13 | 14 | swigConfig(swig); 15 | middlewareConfig(app); 16 | 17 | if (locals.SSL.enableSSL) { 18 | var fs = require('fs'); 19 | 20 | var options = { 21 | key: fs.readFileSync(locals.SSL.key), 22 | cert: fs.readFileSync(locals.SSL.cert) 23 | }; 24 | 25 | server = require('https').createServer(options, app).listen(port); 26 | } else { 27 | server = require('http').createServer(app).listen(port); 28 | } 29 | 30 | if (server !== null) { 31 | server.on('error', onError); 32 | server.on('listening', onListening); 33 | } 34 | 35 | function onError(error) { 36 | if (error.syscall !== 'listen') { 37 | loggers.errLogger.error('server internal error', error); 38 | throw error; 39 | } 40 | 41 | switch (error.code) { 42 | case 'EACCES': 43 | console.error('Port ' + port + ' requires elevated privileges'); 44 | process.exit(1); 45 | break; 46 | case 'EADDRINUSE': 47 | console.error('Port ' + port + ' is already in use'); 48 | process.exit(1); 49 | break; 50 | default: 51 | loggers.errLogger.error('server internal error', error); 52 | throw error; 53 | } 54 | } 55 | 56 | function onListening() { 57 | console.log('Server listening on port' 58 | + (locals.SSL.enableSSL ? '(SSL enabled) ' : ' ') + port); 59 | } 60 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angularjs-requirejs-boilerplate", 3 | "description": "A complete angularjs requirejs boilerplate for node.", 4 | "version": "2.3.0", 5 | "authors": "Pluser ", 6 | "main": "app.js", 7 | "keywords": [ 8 | "angular", 9 | "angularjs", 10 | "requirejs", 11 | "angularjs-requirejs", 12 | "boilerplate" 13 | ], 14 | "license": "MIT", 15 | "homepage": "https://github.com/ipluser/angularjs-requirejs-boilerplate", 16 | "dependencies": { 17 | "angular": "~1.4.7", 18 | "bootstrap": "~3.3.5", 19 | "jquery": "~2.1.4", 20 | "requirejs": "~2.1.20", 21 | "angular-mocks": "~1.4.7", 22 | "github-markdown-css": "~2.1.1" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /gulp/common/env-util.js: -------------------------------------------------------------------------------- 1 | var argv = require('yargs').argv; 2 | 3 | var env = {}; 4 | 5 | env.isProduction = function () { 6 | return argv.production ? true : false; 7 | }; 8 | 9 | env.isDevelopment = function () { 10 | return argv.development ? true : false; 11 | }; 12 | 13 | env.isLiveReload = function () { 14 | return (env.isDevelopment() && argv.development !== 'static') ? true : false; 15 | }; 16 | 17 | module.exports = env; -------------------------------------------------------------------------------- /gulp/desktop/build-scripts.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp-help')(require('gulp')), 2 | gutil = require('gulp-util'), 3 | concat = require('gulp-concat'), 4 | uglify = require('gulp-uglify'), 5 | size = require('gulp-size'), 6 | gulpif = require('gulp-if'), 7 | requirejs = require('requirejs'), 8 | vp = require('vinyl-paths'), 9 | del = require('del'); 10 | 11 | var envUtil = require('../common/env-util'); 12 | 13 | var paths = { 14 | origin: 'public/scripts/desktop', 15 | compiled: 'public/compiled/desktop/scripts' 16 | }; 17 | 18 | gulp.task('desktop-build-libs-no-clean', function () { 19 | requirejs.optimize({ 20 | baseUrl: paths.origin + '/../', 21 | name: 'desktop/optimize-main', 22 | mainConfigFile: paths.origin + '/optimize-require-config.js', 23 | out: paths.compiled + '/libs.min.js', 24 | optimize: 'uglify2', 25 | removeCombined: true 26 | }, function (files) { 27 | if (!envUtil.isProduction()) { 28 | gutil.log('modules of build libs in desktop', files); 29 | } 30 | }, function (err) { 31 | gutil.log('build libs error in desktop', err); 32 | }); 33 | }); 34 | 35 | gulp.task('desktop-build-custom-scripts-no-clean', function () { 36 | return gulp.src([ 37 | paths.origin + '/**/*.js', 38 | '!' + paths.origin + '/optimize-main.js', 39 | '!' + paths.origin + '/optimize-require-config.js' 40 | ]).pipe(concat('apps.min.js').on('error', gutil.log)) 41 | .pipe(gulpif(!envUtil.isProduction(), size({title: 'size of custom scripts in desktop'}))) 42 | .pipe(uglify().on('error', gutil.log)) 43 | .pipe(gulpif(!envUtil.isProduction(), size({title: 'size of uglify custom scripts in desktop'}))) 44 | .pipe(gulp.dest(paths.compiled)); 45 | }); 46 | 47 | gulp.task('desktop-clean-scripts', function () { 48 | return gulp.src([ 49 | paths.compiled + '/libs.min.js', 50 | paths.compiled + '/apps.min.js' 51 | ], { 52 | read: false 53 | }).pipe(vp(del).on('error', gutil.log)); 54 | }); 55 | 56 | gulp.task('desktop-build-scripts-no-clean', function () { 57 | gulp.start('desktop-build-libs-no-clean', 'desktop-build-custom-scripts-no-clean'); 58 | }); 59 | 60 | gulp.task('desktop-build-scripts', ['desktop-clean-scripts'], function () { 61 | gulp.start('desktop-build-libs-no-clean', 'desktop-build-custom-scripts-no-clean'); 62 | }); -------------------------------------------------------------------------------- /gulp/desktop/build-styles.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp-help')(require('gulp')), 2 | gutil = require('gulp-util'), 3 | less = require('gulp-less'), 4 | minifycss = require('gulp-minify-css'), 5 | size = require('gulp-size'), 6 | gulpif = require('gulp-if'), 7 | plumber = require('gulp-plumber'), 8 | vp = require('vinyl-paths'), 9 | del = require('del'); 10 | 11 | var envUtil = require('../common/env-util'), 12 | browserSync = require('../develop/build-browser-sync'); 13 | 14 | var paths = { 15 | origin: 'public/styles/desktop', 16 | compiled: 'public/compiled/desktop/styles' 17 | }; 18 | 19 | gulp.task('desktop-build-styles-no-clean', function () { 20 | return gulp.src(paths.origin + '/**/*.less') 21 | .pipe(plumber()) 22 | .pipe(gulpif(!envUtil.isProduction(), size({title: 'size of less in desktop'}))) 23 | .pipe(less().on('error', gutil.log)) 24 | .pipe(gulpif(!envUtil.isProduction(), size({title: 'size of css in desktop, after less2css'}))) 25 | .pipe(minifycss().on('error', gutil.log)) 26 | .pipe(gulpif(!envUtil.isProduction(), size({title: 'size of css in desktop, after minify css'}))) 27 | .pipe(gulp.dest(paths.compiled)) 28 | .pipe(gulpif(envUtil.isLiveReload(), browserSync.stream())); 29 | }); 30 | 31 | gulp.task('desktop-clean-styles', function () { 32 | return gulp.src(paths.compiled, { 33 | read: false 34 | }).pipe(vp(del).on('error', gutil.log)); 35 | }); 36 | 37 | gulp.task('desktop-build-styles', ['desktop-clean-styles'], function () { 38 | gulp.start('desktop-build-styles-no-clean'); 39 | }); -------------------------------------------------------------------------------- /gulp/desktop/build-templates.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp-help')(require('gulp')), 2 | gutil = require('gulp-util'), 3 | templateCache = require('gulp-angular-templatecache'), 4 | size = require('gulp-size'), 5 | uglify = require('gulp-uglify'), 6 | replace = require('gulp-replace'), 7 | gulpif = require('gulp-if'), 8 | vp = require('vinyl-paths'), 9 | del = require('del'); 10 | 11 | var envUtil = require('../common/env-util'); 12 | 13 | var paths = { 14 | origin: 'views/desktop/templates', 15 | compiled: 'public/compiled/desktop/scripts' 16 | }; 17 | 18 | gulp.task('desktop-build-templates-no-clean', function () { 19 | return gulp.src([ 20 | paths.origin + '/**/*.html' 21 | ]).pipe(gulpif(!envUtil.isProduction(), size({title: 'desktop - template html - size'}))) 22 | .pipe(templateCache('templates.min.js', { 23 | root: '/desktop/templates', 24 | module: 'angularApp', 25 | standalone: false, 26 | moduleSystem: 'RequireJS' 27 | }).on('error', gutil.log)) 28 | .pipe(replace(/^define\(/, 'define(\'desktop/templates\'\,').on('error', gutil.log)) 29 | .pipe(gulpif(!envUtil.isProduction(), size({title: 'desktop - template html - size - ng-html2js'}))) 30 | .pipe(uglify().on('error', gutil.log)) 31 | .pipe(gulpif(!envUtil.isProduction(), size({title: 'desktop - template html - size - uglify js'}))) 32 | .pipe(gulp.dest(paths.compiled)); 33 | }); 34 | 35 | gulp.task('desktop-clean-templates', function () { 36 | return gulp.src([ 37 | paths.compiled + '/templates.min.js' 38 | ], { 39 | read: false 40 | }).pipe(vp(del).on('error', gutil.log)); 41 | }); 42 | 43 | gulp.task('desktop-build-templates', ['desktop-clean-templates'], function () { 44 | gulp.start('desktop-build-templates-no-clean'); 45 | }); -------------------------------------------------------------------------------- /gulp/desktop/build.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp-help')(require('gulp')); 2 | 3 | require('./build-scripts'); 4 | require('./build-styles'); 5 | require('./build-templates'); 6 | 7 | gulp.task('desktop-clean', function () { 8 | gulp.start('desktop-clean-scripts', 'desktop-clean-styles', 9 | 'desktop-clean-templates'); 10 | }); 11 | 12 | gulp.task('desktop-build-no-clean', function () { 13 | gulp.start('desktop-build-scripts-no-clean', 'desktop-build-styles-no-clean', 14 | 'desktop-build-templates-no-clean'); 15 | }); 16 | 17 | gulp.task('desktop-build', function () { 18 | gulp.start('desktop-build-scripts', 'desktop-build-styles', 19 | 'desktop-build-templates'); 20 | }); 21 | -------------------------------------------------------------------------------- /gulp/develop/build-browser-sync.js: -------------------------------------------------------------------------------- 1 | var browserSync = require("browser-sync"); 2 | 3 | var envUtil = require('../common/env-util'); 4 | 5 | if (envUtil.isLiveReload()) { 6 | var browserSyncServer = browserSync.create(), 7 | locals = require('../../node-app/config/locals'); 8 | 9 | browserSyncServer.init({ 10 | proxy: 'localhost:' + locals.port, 11 | port: locals.devPort 12 | }); 13 | 14 | module.exports = browserSyncServer; 15 | } else { 16 | module.exports = browserSync; 17 | } -------------------------------------------------------------------------------- /gulp/develop/build.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp-help')(require('gulp')), 2 | gutil = require('gulp-util'), 3 | nodemon = require('gulp-nodemon'), 4 | jshint = require('gulp-jshint'), 5 | stylish = require('jshint-stylish'), 6 | karmaServer = require('karma').Server; 7 | 8 | var envUtil = require('../common/env-util'), 9 | browserSync = require('./build-browser-sync'); 10 | 11 | var resources = { 12 | styles: 'public/styles/**/*.less', 13 | scripts: 'public/scripts/**/*.js', 14 | libs: 'public/libs/**/*.js', 15 | jshint: [ 16 | 'gulp/**/*.js', 17 | 'middleware/**/*.js', 18 | 'node-app/**/*.js', 19 | 'public/scripts/**/*.js', 20 | 'test/**/*.js' 21 | ], 22 | views: 'views/**/*.html', 23 | images: 'public/images/**/*' 24 | }; 25 | 26 | gulp.task('develop-watch', [ 27 | 'develop-watch-node', 28 | 'build-styles' 29 | ], function () { 30 | gulp.watch(resources.styles, ['build-styles']); 31 | gulp.watch(resources.scripts, ['browsersync-reload']); 32 | gulp.watch(resources.libs, ['browsersync-reload']); 33 | gulp.watch(resources.jshint, ['develop-jshint']); 34 | gulp.watch(resources.views, ['browsersync-reload']); 35 | gulp.watch(resources.images, ['browsersync-reload']); 36 | }); 37 | 38 | gulp.task('develop-watch-node', function () { 39 | nodemon({ 40 | scripts: 'app.js', 41 | env: { 42 | 'NODE_ENV': 'development' 43 | }, 44 | ext: 'js', 45 | watch: [ 46 | 'gulp', 47 | 'middleware', 48 | 'node-app', 49 | 'app.js' 50 | ] 51 | }).on('restart', function (files) { 52 | gutil.log('Node server restarted due to: ', files); 53 | setTimeout(function() { 54 | browserSync.reload(); 55 | }, 1000); 56 | }); 57 | }); 58 | 59 | gulp.task('browsersync-reload', function () { 60 | if (envUtil.isLiveReload()) { 61 | browserSync.reload(); 62 | } 63 | }); 64 | 65 | gulp.task('develop-jshint', function () { 66 | return gulp.src(resources.jshint) 67 | .pipe(jshint()) 68 | .pipe(jshint.reporter(stylish)); 69 | }); 70 | 71 | gulp.task('develop-tests', function () { 72 | new karmaServer({ 73 | configFile: process.cwd() + '/karma.conf.js' 74 | }).start(); 75 | }); -------------------------------------------------------------------------------- /gulp/gulp-docker.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp-help')(require('gulp')); 2 | 3 | var envUtil = require('./common/env-util'); 4 | 5 | require('./desktop/build.js'); 6 | require('./mobile/build.js'); 7 | 8 | if (!envUtil.isProduction()) { 9 | require('./develop/build.js'); 10 | } 11 | 12 | gulp.task('clean-scripts', function () { 13 | gulp.start('desktop-clean-scripts', 'mobile-clean-scripts'); 14 | }); 15 | 16 | gulp.task('clean-styles', function () { 17 | gulp.start('desktop-clean-styles', 'mobile-clean-styles'); 18 | }); 19 | 20 | gulp.task('clean-templates', function () { 21 | gulp.start('desktop-clean-templates', 'mobile-clean-templates'); 22 | }); 23 | 24 | gulp.task('clean', function () { 25 | gulp.start('desktop-clean', 'mobile-clean'); 26 | }); 27 | 28 | gulp.task('build-scripts-no-clean', function () { 29 | gulp.start('desktop-build-scripts-no-clean', 'mobile-build-scripts-no-clean'); 30 | }); 31 | 32 | gulp.task('build-scripts', function () { 33 | gulp.start('desktop-build-scripts', 'mobile-build-scripts'); 34 | }); 35 | 36 | gulp.task('build-styles-no-clean', function () { 37 | gulp.start('desktop-build-styles-no-clean', 'mobile-build-styles-no-clean'); 38 | }); 39 | 40 | gulp.task('build-styles', function () { 41 | gulp.start('desktop-build-styles', 'mobile-build-styles'); 42 | }); 43 | 44 | gulp.task('build-templates-no-clean', function () { 45 | gulp.start('desktop-build-templates-no-clean', 'mobile-build-templates-no-clean'); 46 | }); 47 | 48 | gulp.task('build-templates', function () { 49 | gulp.start('desktop-templates-styles', 'mobile-templates-styles'); 50 | }); 51 | 52 | gulp.task('build-no-clean', function () { 53 | gulp.start('desktop-build-no-clean', 'mobile-build-no-clean'); 54 | }); 55 | 56 | gulp.task('build', function () { 57 | gulp.start('desktop-build', 'mobile-build'); 58 | }); 59 | 60 | gulp.task('default', 'compile and build by production mode and it show more information', function () { 61 | if (envUtil.isDevelopment()) { 62 | gulp.start('develop-watch'); 63 | } else { 64 | gulp.start('desktop-build', 'mobile-build'); 65 | } 66 | }, { 67 | options: { 68 | 'production': 'compile and build in production env', 69 | 'development': 'development mode for developer' 70 | } 71 | }); -------------------------------------------------------------------------------- /gulp/mobile/build-scripts.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp-help')(require('gulp')), 2 | gutil = require('gulp-util'), 3 | concat = require('gulp-concat'), 4 | uglify = require('gulp-uglify'), 5 | size = require('gulp-size'), 6 | gulpif = require('gulp-if'), 7 | requirejs = require('requirejs'), 8 | vp = require('vinyl-paths'), 9 | del = require('del'); 10 | 11 | var envUtil = require('../common/env-util'); 12 | 13 | var paths = { 14 | origin: 'public/scripts/mobile', 15 | compiled: 'public/compiled/mobile/scripts' 16 | }; 17 | 18 | gulp.task('mobile-build-libs-no-clean', function () { 19 | requirejs.optimize({ 20 | baseUrl: paths.origin + '/../', 21 | name: 'mobile/optimize-main', 22 | mainConfigFile: paths.origin + '/optimize-require-config.js', 23 | out: paths.compiled + '/libs.min.js', 24 | optimize: 'uglify2', 25 | removeCombined: true 26 | }, function (data) { 27 | if (!envUtil.isProduction()) { 28 | gutil.log('modules of build libs in desktop', files); 29 | } 30 | }, function (err) { 31 | gutil.log('build libs error in mobile', err); 32 | }); 33 | }); 34 | 35 | gulp.task('mobile-build-custom-scripts-no-clean', function () { 36 | return gulp.src([ 37 | paths.origin + '/**/*.js', 38 | '!' + paths.origin + '/optimize-main.js', 39 | '!' + paths.origin + '/optimize-require-config.js' 40 | ]).pipe(concat('apps.min.js').on('error', gutil.log)) 41 | .pipe(gulpif(!envUtil.isProduction(), size({title: 'size of custom scripts in mobile'}))) 42 | .pipe(uglify().on('error', gutil.log)) 43 | .pipe(gulpif(!envUtil.isProduction(), size({title: 'size of uglify custom scripts in mobile'}))) 44 | .pipe(gulp.dest(paths.compiled)); 45 | }); 46 | 47 | gulp.task('mobile-clean-scripts', function () { 48 | return gulp.src([ 49 | paths.compiled + '/libs.min.js', 50 | paths.compiled + '/apps.min.js' 51 | ], { 52 | read: false 53 | }).pipe(vp(del).on('error', gutil.log)); 54 | }); 55 | 56 | gulp.task('mobile-build-scripts-no-clean', function () { 57 | gulp.start('mobile-build-libs-no-clean', 'mobile-build-custom-scripts-no-clean'); 58 | }); 59 | 60 | gulp.task('mobile-build-scripts', ['mobile-clean-scripts'], function () { 61 | gulp.start('mobile-build-libs-no-clean', 'mobile-build-custom-scripts-no-clean'); 62 | }); -------------------------------------------------------------------------------- /gulp/mobile/build-styles.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp-help')(require('gulp')), 2 | gutil = require('gulp-util'), 3 | less = require('gulp-less'), 4 | minifycss = require('gulp-minify-css'), 5 | size = require('gulp-size'), 6 | gulpif = require('gulp-if'), 7 | plumber = require('gulp-plumber'), 8 | vp = require('vinyl-paths'), 9 | del = require('del'); 10 | 11 | var envUtil = require('../common/env-util'), 12 | browserSync = require('../develop/build-browser-sync'); 13 | 14 | var paths = { 15 | origin: 'public/styles/mobile', 16 | compiled: 'public/compiled/mobile/styles' 17 | }; 18 | 19 | gulp.task('mobile-build-styles-no-clean', function () { 20 | return gulp.src(paths.origin + '/**/*.less') 21 | .pipe(plumber()) 22 | .pipe(gulpif(!envUtil.isProduction(), size({title: 'size of less in mobile'}))) 23 | .pipe(less().on('error', gutil.log)) 24 | .pipe(gulpif(!envUtil.isProduction(), size({title: 'size of css in mobile, after less2css'}))) 25 | .pipe(minifycss().on('error', gutil.log)) 26 | .pipe(gulpif(!envUtil.isProduction(), size({title: 'size of css in mobile, after minify css'}))) 27 | .pipe(gulp.dest(paths.compiled)) 28 | .pipe(gulpif(envUtil.isLiveReload(), browserSync.stream())); 29 | }); 30 | 31 | gulp.task('mobile-clean-styles', function () { 32 | return gulp.src(paths.compiled, { 33 | read: false 34 | }).pipe(vp(del).on('error', gutil.log)); 35 | }); 36 | 37 | gulp.task('mobile-build-styles', ['mobile-clean-styles'], function () { 38 | gulp.start('mobile-build-styles-no-clean'); 39 | }); -------------------------------------------------------------------------------- /gulp/mobile/build-templates.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp-help')(require('gulp')), 2 | gutil = require('gulp-util'), 3 | templateCache = require('gulp-angular-templatecache'), 4 | size = require('gulp-size'), 5 | uglify = require('gulp-uglify'), 6 | concat = require('gulp-concat'), 7 | replace = require('gulp-replace'), 8 | gulpif = require('gulp-if'), 9 | vp = require('vinyl-paths'), 10 | del = require('del'); 11 | 12 | var envUtil = require('../common/env-util'); 13 | 14 | var paths = { 15 | origin: 'views/mobile/templates', 16 | compiled: 'public/compiled/mobile/scripts' 17 | }; 18 | 19 | gulp.task('mobile-build-templates-no-clean', function () { 20 | return gulp.src([ 21 | paths.origin + '/**/*.html' 22 | ]).pipe(gulpif(!envUtil.isProduction(), size({title: 'mobile - template html - size'}))) 23 | .pipe(templateCache('templates.min.js', { 24 | root: '/mobile/templates', 25 | module: 'angularApp', 26 | standalone: false, 27 | moduleSystem: 'RequireJS' 28 | }).on('error', gutil.log)) 29 | .pipe(replace(/^define\(/, 'define(\'mobile/templates\'\,').on('error', gutil.log)) 30 | .pipe(gulpif(!envUtil.isProduction(), size({title: 'mobile - template html - size - ng-html2js'}))) 31 | .pipe(uglify().on('error', gutil.log)) 32 | .pipe(gulpif(!envUtil.isProduction(), size({title: 'mobile - template html - size - uglify js'}))) 33 | .pipe(gulp.dest(paths.compiled)); 34 | }); 35 | 36 | gulp.task('mobile-clean-templates', function () { 37 | return gulp.src([ 38 | paths.compiled + '/templates.min.js' 39 | ], { 40 | read: false 41 | }).pipe(vp(del).on('error', gutil.log)); 42 | }); 43 | 44 | gulp.task('mobile-build-templates', ['mobile-clean-templates'], function () { 45 | gulp.start('mobile-build-templates-no-clean'); 46 | }); -------------------------------------------------------------------------------- /gulp/mobile/build.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp-help')(require('gulp')); 2 | 3 | require('./build-scripts'); 4 | require('./build-styles'); 5 | require('./build-templates'); 6 | 7 | gulp.task('mobile-clean', function () { 8 | gulp.start('mobile-clean-scripts', 'mobile-clean-styles', 9 | 'mobile-clean-templates'); 10 | }); 11 | 12 | gulp.task('mobile-build-no-clean', function () { 13 | gulp.start('mobile-build-scripts-no-clean', 'mobile-build-styles-no-clean', 14 | 'mobile-build-templates-no-clean'); 15 | }); 16 | 17 | gulp.task('mobile-build', function () { 18 | gulp.start('mobile-build-scripts', 'mobile-build-styles', 19 | 'mobile-build-templates'); 20 | }); 21 | -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | require('./gulp/gulp-docker'); 2 | 3 | var gulp = require('gulp-help')(require('gulp')), 4 | markdown = require('gulp-markdown'); 5 | 6 | gulp.task('build-markdown', function () { 7 | return gulp.src('README.md') 8 | .pipe(markdown()) 9 | .pipe(gulp.dest('views/desktop/templates/markdown')) 10 | .pipe(gulp.dest('views/mobile/templates/markdown')); 11 | }); -------------------------------------------------------------------------------- /karma.conf.js: -------------------------------------------------------------------------------- 1 | module.exports = function (config) { 2 | config.set({ 3 | basePath: '', 4 | frameworks: ['jasmine', 'requirejs'], 5 | files: [ 6 | {pattern: 'public/libs/jquery/dist/jquery.js', included: false}, 7 | {pattern: 'public/libs/angular/angular.js', included: false}, 8 | {pattern: 'public/libs/angular-mocks/angular-mocks.js', included: false}, 9 | {pattern: 'public/scripts/**/*.js', included: false}, 10 | {pattern: 'views/desktop/templates/**/*.html', included: false}, 11 | {pattern: 'views/mobile/templates/**/*.html', included: false}, 12 | {pattern: 'test/**/*-test.js', included: false}, 13 | 'test/desktop/test-main.js' 14 | ], 15 | exclude: [ 16 | 'public/scripts/desktop/bootstrap.js', 17 | 'public/scripts/desktop/optimize-main.js', 18 | 'public/scripts/desktop/optimize-require-config.js', 19 | 'public/scripts/desktop/require-config.js', 20 | 'public/scripts/mobile/bootstrap.js', 21 | 'public/scripts/mobile/optimize-main.js', 22 | 'public/scripts/mobile/optimize-require-config.js', 23 | 'public/scripts/mobile/require-config.js' 24 | ], 25 | browsers: ['PhantomJS_Custom'], 26 | customLaunchers: { 27 | 'PhantomJS_Custom': { 28 | base: 'PhantomJS', 29 | options: { 30 | windowName: 'karma-phantom', 31 | settings: { 32 | webSecurityEnabled: false 33 | }, 34 | }, 35 | debug: true 36 | } 37 | }, 38 | phantomjsLauncher: { 39 | exitOnResourceError: true 40 | }, 41 | reporters: ['progress', 'html', 'coverage'], 42 | htmlReporter: { 43 | outputFile: 'report/units.html', 44 | pageTitle: 'Unit Tests', 45 | subPageTitle: 'Unit tests with karma jasmine' 46 | }, 47 | preprocessors: { 48 | 'public/scripts/**/*.js': ['coverage'], 49 | 'views/desktop/templates/**/*.html' : ['ng-html2js'], 50 | 'views/mobile/templates/**/*.html' : ['ng-html2js'] 51 | }, 52 | coverageReporter: { 53 | type : 'html', 54 | dir : 'report/coverage/' 55 | }, 56 | ngHtml2JsPreprocessor: { 57 | stripPrefix: 'views', 58 | moduleName: 'angularApp' 59 | } 60 | }); 61 | } -------------------------------------------------------------------------------- /middleware/error-handling/default.js: -------------------------------------------------------------------------------- 1 | var loggers = require('../../node-app/common/loggers'); 2 | 3 | function notFound(req, res) { 4 | if (/^[/]h5/.test(req.path)) { 5 | res.status(404).redirect('/h5/not-found'); 6 | return ; 7 | } 8 | res.status(404).redirect('/not-found'); 9 | } 10 | 11 | function internalError(err, req, res, next) { 12 | /*jshint unused: false*/ 13 | loggers.errLogger.error('http-status error:\n' + err.stack); 14 | 15 | if (/^[/]h5/.test(req.path)) { 16 | res.status(404).redirect('/h5/error'); 17 | return ; 18 | } 19 | res.status(500).redirect('/error'); 20 | } 21 | 22 | module.exports.notFound = notFound; 23 | module.exports.internalError = internalError; 24 | -------------------------------------------------------------------------------- /middleware/error-handling/error-config.js: -------------------------------------------------------------------------------- 1 | var locals = require('../../node-app/config/locals'), 2 | devErrorHandler = require('errorhandler'), 3 | defaultHandler = require('./default'); 4 | 5 | function errorConfig(app) { 6 | app.use(defaultHandler.notFound); 7 | 8 | if (locals.isDevMode) { 9 | app.use(devErrorHandler()); 10 | } else { 11 | app.use(defaultHandler.internalError); 12 | } 13 | } 14 | 15 | module.exports = errorConfig; -------------------------------------------------------------------------------- /middleware/middleware-config.js: -------------------------------------------------------------------------------- 1 | var express = require('express'), 2 | morgan = require('morgan'), 3 | favicon = require('serve-favicon'), 4 | compress = require('compression'), 5 | cookieParser = require('cookie-parser'), 6 | bodyParser = require('body-parser'); 7 | 8 | var locals = require('../node-app/config/locals'), 9 | detector = require('../node-app/utils/detector'), 10 | routerConfig = require('./router/router-config'), 11 | errorConfig = require('./error-handling/error-config'); 12 | 13 | var middlewareConfig = function (app) { 14 | if (locals.isDevMode) { 15 | app.use(morgan('dev')); 16 | } 17 | 18 | if (locals.poweredBy) { 19 | app.use('/', function (req, res, next) { 20 | res.set('X-Powered-By', locals.poweredBy); 21 | next(); 22 | }); 23 | } 24 | 25 | app.use(detectMobile); 26 | app.use(favicon(process.cwd() + '/public/images/favicon.ico')); 27 | app.use(cookieParser()); 28 | app.use(bodyParser.json()); 29 | app.use(bodyParser.urlencoded({ 30 | extended: true 31 | })); 32 | 33 | if (!locals.isDevMode) { 34 | app.use(compress()); 35 | } 36 | 37 | staticMiddleware(app, { 38 | maxAge: locals.isDevMode ? 0 : locals.cachePeriod 39 | }); 40 | routerConfig(app); 41 | errorConfig(app); 42 | }; 43 | 44 | function detectMobile(req, res, next) { 45 | if (detector.isMobile(req.get('User-Agent')) && req.url === '/') { 46 | res.redirect("/h5"); 47 | return; 48 | } 49 | next(); 50 | } 51 | 52 | function staticMiddleware(app, options) { 53 | if (!locals.isDevMode) { 54 | app.use('/static/scripts/desktop', express.static(process.cwd() + '/public/compiled/desktop/scripts', options)); 55 | app.use('/static/scripts/mobile', express.static(process.cwd() + '/public/compiled/mobile/scripts', options)); 56 | } else { 57 | app.use('/static', express.static(process.cwd() + '/public', options)); 58 | app.use('/*/templates', function (req, res, next) { 59 | res.render(req.originalUrl.substr(1), function (err, html) { 60 | if (err) { 61 | next(); 62 | } else { 63 | res.send(html); 64 | } 65 | }); 66 | }); 67 | } 68 | 69 | app.use('/static/styles/desktop', express.static(process.cwd() + '/public/compiled/desktop/styles', options)); 70 | app.use('/static/styles/mobile', express.static(process.cwd() + '/public/compiled/mobile/styles', options)); 71 | app.use('/static/libs', express.static(process.cwd() + '/public/libs', options)); 72 | app.use('/static/images', express.static(process.cwd() + '/public/images', options)); 73 | } 74 | 75 | module.exports = middlewareConfig; -------------------------------------------------------------------------------- /middleware/router/desktop/default.js: -------------------------------------------------------------------------------- 1 | var routes = { 2 | domain: '/', 3 | routers: [{ 4 | path: '/', 5 | view: 'desktop/render/default/index', 6 | data: { 7 | styles: [ 8 | 'desktop/default/index' 9 | ] 10 | } 11 | }, { 12 | path: '/samples', 13 | view: 'desktop/render/default/samples', 14 | data: { 15 | styles: [ 16 | 'desktop/default/samples' 17 | ], 18 | scripts: [ 19 | 'desktop/controllers/default/samples-controller' 20 | ] 21 | } 22 | }, { 23 | path: '/error', 24 | view: 'desktop/render/default/error' 25 | }, { 26 | path: '/not-found', 27 | view: 'desktop/render/default/not-found' 28 | }] 29 | }; 30 | 31 | module.exports = routes; 32 | 33 | -------------------------------------------------------------------------------- /middleware/router/desktop/router-dockers.js: -------------------------------------------------------------------------------- 1 | var defaultRouter = require('./default'); 2 | 3 | var docker = [ 4 | defaultRouter 5 | ]; 6 | 7 | module.exports = docker; 8 | -------------------------------------------------------------------------------- /middleware/router/mobile/default.js: -------------------------------------------------------------------------------- 1 | var routes = { 2 | domain: '/h5', 3 | routers: [{ 4 | path: '/', 5 | view: 'mobile/render/default/index', 6 | data: { 7 | styles: [ 8 | 'mobile/default/index' 9 | ] 10 | } 11 | }, { 12 | path: '/error', 13 | view: 'desktop/render/default/error' 14 | }, { 15 | path: '/not-found', 16 | view: 'desktop/render/default/not-found' 17 | }] 18 | }; 19 | 20 | module.exports = routes; 21 | 22 | -------------------------------------------------------------------------------- /middleware/router/mobile/router-dockers.js: -------------------------------------------------------------------------------- 1 | var defaultRouter = require('./default'); 2 | 3 | var docker = [ 4 | defaultRouter 5 | ]; 6 | 7 | module.exports = docker; 8 | -------------------------------------------------------------------------------- /middleware/router/router-config.js: -------------------------------------------------------------------------------- 1 | var express = require('express'), 2 | _ = require('lodash'), 3 | routerDockers = require('./desktop/router-dockers'), 4 | mobileRouterDockers = require('./mobile/router-dockers'); 5 | 6 | var routerConfig = function (app) { 7 | _.forEach(routerDockers, function (routes) { 8 | app.use(routes.domain, newRouter(routes.routers)); 9 | }); 10 | 11 | _.forEach(mobileRouterDockers, function (routes) { 12 | app.use(routes.domain, newRouter(routes.routers)); 13 | }); 14 | }; 15 | 16 | function newRouter(routersConfig) { 17 | // custom Router 18 | if (_.isFunction(routersConfig)) { 19 | return routersConfig; 20 | } 21 | 22 | var router = express.Router(); 23 | if (!_.isArray(routersConfig)) { 24 | return router; 25 | } 26 | 27 | _.forEach(routersConfig, function (config) { 28 | router.get(config.path, function (req, res) { 29 | if (config.preRender) { 30 | config.preRender(req, res, config.data); 31 | } 32 | res.render(config.view, config.data); 33 | }); 34 | }); 35 | 36 | return router; 37 | } 38 | 39 | module.exports = routerConfig; -------------------------------------------------------------------------------- /node-app/common/loggers.js: -------------------------------------------------------------------------------- 1 | var locals = require('../config/locals'), 2 | bunyan = require('bunyan'), 3 | fse = require('fs-extra'), 4 | _ = require('lodash'); 5 | 6 | var loggers = {}; 7 | 8 | var loggersConfig = [{ 9 | name: 'errLogger', 10 | streams: [{ 11 | level: 'error', 12 | path: locals.logPath + 'errLogger.log', 13 | type: 'rotating-file', 14 | period: '1d', 15 | count: 7 16 | }] 17 | }]; 18 | 19 | fse.ensureDirSync(locals.logPath); 20 | 21 | _.forEach(loggersConfig, function (config) { 22 | if (locals.isDevMode) { 23 | if (!config.streams) { 24 | config.streams = []; 25 | } 26 | 27 | config.streams.push({ 28 | stream: process.stdout 29 | }); 30 | } 31 | 32 | loggers[config.name] = bunyan.createLogger(config); 33 | }); 34 | 35 | module.exports = loggers; -------------------------------------------------------------------------------- /node-app/config/locals.js: -------------------------------------------------------------------------------- 1 | var locals = { 2 | name: 'angularjs-requirejs-boilerplate', 3 | author: 'Plus', 4 | isDevMode: false, 5 | port: 8099, 6 | devPort: 3000, 7 | poweredBy: 'ipluser', 8 | SSL: { 9 | enableSSL: false, 10 | key: './node-app/config/ssl/key.pem', 11 | cert: './node-app/config/ssl/cert.pem' 12 | }, 13 | cachePeriod: 604800000, 14 | buildNumber: new Date().getTime().toString(), 15 | logPath: '/var/log/nodejs/' 16 | }; 17 | 18 | module.exports = locals; -------------------------------------------------------------------------------- /node-app/config/ssl/cert.pem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipluser/angularjs-requirejs-boilerplate/3186dc400d4997338f628911c37beec36c7e3783/node-app/config/ssl/cert.pem -------------------------------------------------------------------------------- /node-app/config/ssl/key.pem: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipluser/angularjs-requirejs-boilerplate/3186dc400d4997338f628911c37beec36c7e3783/node-app/config/ssl/key.pem -------------------------------------------------------------------------------- /node-app/swig/filters.js: -------------------------------------------------------------------------------- 1 | var url = require('url'), 2 | _ = require('lodash'), 3 | locals = require('../config/locals'); 4 | 5 | var filters = {}; 6 | 7 | filters.buildNumber = function (input) { 8 | if (locals.isDevMode) { 9 | return input; 10 | } 11 | 12 | var obj = url.parse(input, true); 13 | var final = input; 14 | 15 | if (!_.isEmpty(obj.search)) { 16 | final += '&'; 17 | } else { 18 | final += '?'; 19 | } 20 | return final + 'ver=' + locals.buildNumber; 21 | }; 22 | 23 | function initFilters(swig) { 24 | _.forEach(filters, function (value, key) { 25 | swig.setFilter(key, value); 26 | }); 27 | } 28 | 29 | module.exports = initFilters; -------------------------------------------------------------------------------- /node-app/swig/swig-config.js: -------------------------------------------------------------------------------- 1 | var locals = require('../config/locals'), 2 | filters = require('./filters'); 3 | 4 | var swigConfig = function (swig) { 5 | swig.setDefaults({ 6 | varControls: ['{=', '=}'], 7 | cache: locals.isDevMode ? false : 'memory', 8 | locals: locals 9 | }); 10 | 11 | filters(swig); 12 | }; 13 | 14 | module.exports = swigConfig; -------------------------------------------------------------------------------- /node-app/utils/detector.js: -------------------------------------------------------------------------------- 1 | var MobileDetect = require('mobile-detect'); 2 | 3 | var Detector = {}; 4 | 5 | Detector.isMobile = function (userAgent) { 6 | var mobileDetect = new MobileDetect(userAgent); 7 | 8 | if (mobileDetect.mobile() && !mobileDetect.tablet()) { 9 | return true; 10 | } 11 | return false; 12 | }; 13 | 14 | module.exports = Detector; -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "angularjs-requirejs-boilerplate", 3 | "description": "A complete angularjs requirejs boilerplate for node.", 4 | "version": "2.3.0", 5 | "author": "Pluser ", 6 | "keywords": [ 7 | "angular", 8 | "angularjs", 9 | "require", 10 | "requirejs", 11 | "angularjs-requirejs", 12 | "boilerplate" 13 | ], 14 | "repository": { 15 | "type": "git", 16 | "url": "https://github.com/ipluser/angularjs-requirejs-boilerplate.git" 17 | }, 18 | "license": "MIT", 19 | "homepage": "https://github.com/ipluser/angularjs-requirejs-boilerplate", 20 | "dependencies": { 21 | "body-parser": "^1.14.2", 22 | "browser-sync": "^2.11.0", 23 | "bunyan": "^1.5.1", 24 | "compression": "^1.5.2", 25 | "cookie-parser": "^1.4.0", 26 | "del": "^2.0.2", 27 | "errorhandler": "^1.4.2", 28 | "express": "^4.13.3", 29 | "fs-extra": "^0.24.0", 30 | "gulp": "^3.9.0", 31 | "gulp-angular-templatecache": "^1.8.0", 32 | "gulp-concat": "^2.6.0", 33 | "gulp-help": "^1.6.1", 34 | "gulp-if": "^2.0.0", 35 | "gulp-jshint": "^1.11.2", 36 | "gulp-less": "^3.0.3", 37 | "gulp-markdown": "^1.2.0", 38 | "gulp-minify-css": "^1.2.1", 39 | "gulp-plumber": "^1.0.1", 40 | "gulp-replace": "^0.5.4", 41 | "gulp-size": "^2.0.0", 42 | "gulp-uglify": "^1.4.1", 43 | "gulp-util": "^3.0.6", 44 | "jshint-stylish": "^2.0.1", 45 | "lodash": "^3.10.1", 46 | "mobile-detect": "^1.3.0", 47 | "morgan": "^1.6.1", 48 | "requirejs": "^2.1.20", 49 | "serve-favicon": "^2.3.0", 50 | "swig": "^1.4.2", 51 | "vinyl-paths": "^2.0.0", 52 | "yargs": "^3.31.0" 53 | }, 54 | "devDependencies": { 55 | "gulp-nodemon": "^2.0.4", 56 | "jasmine-core": "^2.3.4", 57 | "karma": "^0.13.10", 58 | "karma-coverage": "^0.5.2", 59 | "karma-htmlfile-reporter": "^0.2.2", 60 | "karma-jasmine": "^0.3.6", 61 | "karma-ng-html2js-preprocessor": "^0.2.0", 62 | "karma-phantomjs-launcher": "^0.2.1", 63 | "karma-requirejs": "^0.2.2", 64 | "phantomjs": "^1.9.18" 65 | }, 66 | "scripts": { 67 | "start": "node app.js", 68 | "test": "karma start" 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /public/images/desktop/forkme_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipluser/angularjs-requirejs-boilerplate/3186dc400d4997338f628911c37beec36c7e3783/public/images/desktop/forkme_right.png -------------------------------------------------------------------------------- /public/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipluser/angularjs-requirejs-boilerplate/3186dc400d4997338f628911c37beec36c7e3783/public/images/favicon.ico -------------------------------------------------------------------------------- /public/images/mobile/forkme_right.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipluser/angularjs-requirejs-boilerplate/3186dc400d4997338f628911c37beec36c7e3783/public/images/mobile/forkme_right.png -------------------------------------------------------------------------------- /public/scripts/desktop/angular-app.js: -------------------------------------------------------------------------------- 1 | define('desktop/angular-app', [ 2 | 'angular' 3 | ], function(angular) { 4 | var angularApp = angular.module('angularApp', []); 5 | return angularApp; 6 | }); -------------------------------------------------------------------------------- /public/scripts/desktop/bootstrap.js: -------------------------------------------------------------------------------- 1 | GlobalConfig.requireScripts.unshift( 2 | 'angular', 3 | 'desktop/angular-app' 4 | ); 5 | 6 | require(GlobalConfig.requireScripts, function (angular) { 7 | angular.bootstrap(document, ['angularApp']); 8 | }); 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /public/scripts/desktop/controllers/default/samples-controller.js: -------------------------------------------------------------------------------- 1 | define('desktop/controllers/default/samples-controller', [ 2 | 'desktop/angular-app', 3 | 'desktop/filters/common/mock-upper-case', 4 | 'desktop/directives/components/mock-tabs', 5 | 'desktop/services/default/samples-service' 6 | ], function (angularApp) { 7 | angularApp.controller('SamplesCtrl', [ 8 | '$scope', 'SamplesService', function ($scope, SamplesService) { 9 | $scope.panes = SamplesService.getDesc(); 10 | } 11 | ]); 12 | }); -------------------------------------------------------------------------------- /public/scripts/desktop/directives/components/mock-tabs.js: -------------------------------------------------------------------------------- 1 | define('desktop/directives/components/mock-tabs', [ 2 | 'desktop/angular-app' 3 | ], function (angularApp) { 4 | angularApp.directive('mockTabs', function() { 5 | return { 6 | restrict: 'E', 7 | transclude: true, 8 | replace: true, 9 | scope: true, 10 | controller: ['$scope', function($scope) { 11 | var panes = $scope.panes = []; 12 | 13 | $scope.select = function(pane) { 14 | angular.forEach(panes, function(pane) { 15 | pane.selected = false; 16 | }); 17 | pane.selected = true; 18 | } 19 | 20 | this.addPane = function(pane) { 21 | if (panes.length == 0) $scope.select(pane); 22 | panes.push(pane); 23 | } 24 | }], 25 | templateUrl: '/desktop/templates/components/mock-tabs.html' 26 | }; 27 | }).directive('mockPane', function() { 28 | return { 29 | require: '^mockTabs', 30 | restrict: 'E', 31 | transclude: true, 32 | replace: true, 33 | scope: { 34 | title: '@' 35 | }, 36 | link: function(scope, element, attrs, tabsController) { 37 | tabsController.addPane(scope); 38 | }, 39 | templateUrl: '/desktop/templates/components/mock-pane.html' 40 | }; 41 | }); 42 | }); -------------------------------------------------------------------------------- /public/scripts/desktop/filters/common/mock-upper-case.js: -------------------------------------------------------------------------------- 1 | define('desktop/filters/common/mock-upper-case', [ 2 | 'desktop/angular-app' 3 | ], function (angularApp) { 4 | angularApp.filter('MockUpperCase', function () { 5 | return function (input) { 6 | if (!input) { 7 | return null; 8 | } 9 | return input.toUpperCase(); 10 | }; 11 | }); 12 | }); -------------------------------------------------------------------------------- /public/scripts/desktop/optimize-main.js: -------------------------------------------------------------------------------- 1 | define('desktop/optimize-main', [ 2 | 'angular' 3 | ], function () { 4 | }); -------------------------------------------------------------------------------- /public/scripts/desktop/optimize-require-config.js: -------------------------------------------------------------------------------- 1 | require.config({ 2 | paths: { 3 | 'jquery': '../libs/jquery/dist/jquery', 4 | 'angular': '../libs/angular/angular' 5 | }, 6 | shim: { 7 | 'angular': { 8 | deps: ['jquery'], 9 | exports: 'angular' 10 | } 11 | } 12 | }); 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /public/scripts/desktop/require-config.js: -------------------------------------------------------------------------------- 1 | require.config({ 2 | baseUrl: '/static/scripts', 3 | paths: { 4 | 'jquery': '../libs/jquery/dist/jquery', 5 | 'angular': '../libs/angular/angular' 6 | }, 7 | shim: { 8 | 'angular': { 9 | deps: ['jquery'], 10 | exports: 'angular' 11 | } 12 | }, 13 | priority: ['angular'], 14 | waitSeconds: 0 15 | }); 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /public/scripts/desktop/services/default/samples-service.js: -------------------------------------------------------------------------------- 1 | define('desktop/services/default/samples-service', [ 2 | 'desktop/angular-app' 3 | ], function (angularApp) { 4 | angularApp.factory('SamplesService', function () { 5 | var SamplesService = {}; 6 | 7 | SamplesService.getDesc = function () { 8 | return [{ 9 | title: 'Directives', 10 | content: 'Directives is a unique and powerful feature available only in Angular. ' 11 | + 'Directives let you invent new HTML syntax, specific to your application.' 12 | }, { 13 | title: 'Reusable Components', 14 | content: 'We use directives to create reusable components. ' 15 | + 'A component allows you to hide complex DOM structure, CSS, and behavior. ' 16 | + 'This lets you focus either on what the application does or how the application looks separately.' 17 | }, { 18 | title: 'Localization', 19 | content: 'An important part of serious apps is localization. ' 20 | + 'Angular\'s locale aware filters and stemming directives give you building blocks to make your application available in all locales.' 21 | }]; 22 | }; 23 | 24 | return SamplesService; 25 | }); 26 | }); -------------------------------------------------------------------------------- /public/scripts/mobile/angular-app.js: -------------------------------------------------------------------------------- 1 | define('mobile/angular-app', [ 2 | 'angular' 3 | ], function(angular) { 4 | var angularApp = angular.module('angularApp', []); 5 | return angularApp; 6 | }); -------------------------------------------------------------------------------- /public/scripts/mobile/bootstrap.js: -------------------------------------------------------------------------------- 1 | GlobalConfig.requireScripts.unshift( 2 | 'angular', 3 | 'mobile/angular-app' 4 | ); 5 | 6 | require(GlobalConfig.requireScripts, function (angular) { 7 | angular.bootstrap(document, ['angularApp']); 8 | }); 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /public/scripts/mobile/optimize-main.js: -------------------------------------------------------------------------------- 1 | define('mobile/optimize-main', [ 2 | 'angular' 3 | ], function () { 4 | }); -------------------------------------------------------------------------------- /public/scripts/mobile/optimize-require-config.js: -------------------------------------------------------------------------------- 1 | require.config({ 2 | baseUrl: '/static/scripts', 3 | paths: { 4 | 'jquery': '../libs/jquery/dist/jquery', 5 | 'angular': '../libs/angular/angular' 6 | }, 7 | shim: { 8 | 'angular': { 9 | deps: ['jquery'], 10 | exports: 'angular' 11 | } 12 | }, 13 | priority: ['angular'], 14 | waitSeconds: 0 15 | }); 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /public/scripts/mobile/require-config.js: -------------------------------------------------------------------------------- 1 | require.config({ 2 | baseUrl: '/static/scripts', 3 | paths: { 4 | 'jquery': '../libs/jquery/dist/jquery', 5 | 'angular': '../libs/angular/angular' 6 | }, 7 | shim: { 8 | 'angular': { 9 | deps: ['jquery'], 10 | exports: 'angular' 11 | } 12 | }, 13 | priority: ['angular'], 14 | waitSeconds: 0 15 | }); 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /public/styles/desktop/default/index.less: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ipluser/angularjs-requirejs-boilerplate/3186dc400d4997338f628911c37beec36c7e3783/public/styles/desktop/default/index.less -------------------------------------------------------------------------------- /public/styles/desktop/default/samples.less: -------------------------------------------------------------------------------- 1 | .sample-block { 2 | margin-bottom: 70px; 3 | 4 | > .sample-name { 5 | padding-bottom: 10px; 6 | border-bottom: 1px solid #eee; 7 | } 8 | > .sample-content { 9 | margin-top: 40px; 10 | } 11 | } 12 | .tab-pane { 13 | padding-top: 10px; 14 | 15 | > p { 16 | max-width: 500px; 17 | } 18 | } -------------------------------------------------------------------------------- /public/styles/desktop/layout/footer.less: -------------------------------------------------------------------------------- 1 | .footer-container { 2 | margin: 30px 0 20px; 3 | text-align: center; 4 | 5 | .item { 6 | margin-right: 15px; 7 | 8 | &:last-child { 9 | margin-right: 0; 10 | } 11 | } 12 | } -------------------------------------------------------------------------------- /public/styles/desktop/layout/header.less: -------------------------------------------------------------------------------- 1 | .header-container { 2 | .img-fork-me { 3 | position: absolute; 4 | top: 0; 5 | right: 0; 6 | border: 0; 7 | } 8 | } -------------------------------------------------------------------------------- /public/styles/desktop/style.less: -------------------------------------------------------------------------------- 1 | @import "./layout/header"; 2 | @import "./layout/footer"; 3 | 4 | .container { 5 | position: relative; 6 | 7 | > .content-container { 8 | margin-top: 30px; 9 | } 10 | } -------------------------------------------------------------------------------- /public/styles/mobile/default/index.less: -------------------------------------------------------------------------------- 1 | .content-container { 2 | margin-top: 30px; 3 | } -------------------------------------------------------------------------------- /public/styles/mobile/layout/footer.less: -------------------------------------------------------------------------------- 1 | .footer-container { 2 | margin: 30px 0 20px; 3 | text-align: center; 4 | 5 | .copy-right { 6 | margin-right: 15px; 7 | } 8 | } -------------------------------------------------------------------------------- /public/styles/mobile/layout/header.less: -------------------------------------------------------------------------------- 1 | @import "../../../libs/bootstrap/less/mixins/opacity"; 2 | 3 | .header-container { 4 | .img-fork-me { 5 | position: absolute; 6 | top: 0; 7 | right: 0; 8 | border: 0; 9 | .opacity(0.8); 10 | } 11 | } -------------------------------------------------------------------------------- /public/styles/mobile/style.less: -------------------------------------------------------------------------------- 1 | @import "./layout/header"; 2 | @import "./layout/footer"; 3 | 4 | .container { 5 | position: relative; 6 | } -------------------------------------------------------------------------------- /test/desktop/angular-app-test.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'desktop/angular-app' 3 | ], function (angularApp) { 4 | describe('Unit: Module', function () { 5 | it('should be registered', function () { 6 | expect(angularApp).not.toBeNull(); 7 | }); 8 | }); 9 | }); -------------------------------------------------------------------------------- /test/desktop/controllers/default/samples-controller-test.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'angularMocks', 3 | 'desktop/controllers/default/samples-controller' 4 | ], function () { 5 | describe('Unit: Samples Controller', function () { 6 | var SamplesCtrl, $scope; 7 | beforeEach(function () { 8 | module('angularApp'); 9 | inject(function (_$controller_, _$rootScope_) { 10 | $scope = _$rootScope_.$new(); 11 | SamplesCtrl = _$controller_('SamplesCtrl', { 12 | $scope: $scope 13 | }); 14 | }); 15 | }); 16 | 17 | it('should be registered', function () { 18 | expect(SamplesCtrl).toBeDefined(); 19 | }); 20 | 21 | it('should has an panes property that length equals to 3', function () { 22 | expect($scope.panes).toBeDefined(); 23 | expect($scope.panes.length).toEqual(3); 24 | }); 25 | }); 26 | }); -------------------------------------------------------------------------------- /test/desktop/directives/components/mock-tabs-test.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'angularMocks', 3 | 'desktop/directives/components/mock-tabs', 4 | 'templates/components/mock-tabs.html', 5 | 'templates/components/mock-pane.html' 6 | ], function () { 7 | describe('Unit: Mock-Tabs Directive', function () { 8 | var $compile, $rootScope; 9 | beforeEach(function () { 10 | module('angularApp'); 11 | inject(function (_$compile_, _$rootScope_) { 12 | $compile = _$compile_; 13 | $rootScope = _$rootScope_; 14 | }); 15 | }); 16 | 17 | it('should display the hello text properly', function () { 18 | var elt = $compile('' 19 | + '

Sample Content

' 20 | + '
' 21 | )($rootScope); 22 | $rootScope.$digest(); 23 | expect(elt.find('a').text()).toEqual('Sample'); 24 | }); 25 | }); 26 | }); -------------------------------------------------------------------------------- /test/desktop/filters/common/mock-upper-case-test.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'angularMocks', 3 | 'desktop/filters/common/mock-upper-case' 4 | ], function () { 5 | describe('Unit: MockUpperCase filter', function () { 6 | var MockUpperCase; 7 | beforeEach(function () { 8 | module('angularApp'); 9 | inject(function (_$filter_) { 10 | MockUpperCase = _$filter_('MockUpperCase'); 11 | }); 12 | }); 13 | 14 | it('should has a MockUpperCase filter', function () { 15 | expect(MockUpperCase).not.toBeUndefined(); 16 | }); 17 | 18 | it('should has a MockUpperCase filter that change string to upper case', function () { 19 | var result = MockUpperCase('plus'); 20 | expect(result).toEqual('PLUS'); 21 | }); 22 | 23 | it('should return null when input is null or nothing is set', function () { 24 | var result = MockUpperCase(null); 25 | expect(result).toBeNull(); 26 | 27 | result = MockUpperCase(); 28 | expect(result).toBeNull(); 29 | }); 30 | }); 31 | }); -------------------------------------------------------------------------------- /test/desktop/services/default/samples-service-test.js: -------------------------------------------------------------------------------- 1 | define([ 2 | 'angularMocks', 3 | 'desktop/services/default/samples-service' 4 | ], function () { 5 | describe('Unit: SamplesService', function () { 6 | var SamplesService; 7 | beforeEach(function () { 8 | module('angularApp'); 9 | inject(function (_SamplesService_) { 10 | SamplesService = _SamplesService_; 11 | }); 12 | }); 13 | 14 | it('should contain an SamplesService service', function () { 15 | expect(SamplesService).toBeDefined(); 16 | }); 17 | 18 | it('should get description that equal to "Hello World!"', function () { 19 | expect(SamplesService.getDesc().length).toEqual(3); 20 | }); 21 | }); 22 | }); -------------------------------------------------------------------------------- /test/desktop/test-main.js: -------------------------------------------------------------------------------- 1 | var allTestFiles = []; 2 | var TEST_REGEXP = /(\-test)\.js$/i; 3 | 4 | Object.keys(window.__karma__.files).forEach(function(file) { 5 | if (window.__karma__.files.hasOwnProperty(file)) { 6 | if (TEST_REGEXP.test(file)) { 7 | allTestFiles.push(file); 8 | } 9 | } 10 | }); 11 | 12 | require.config({ 13 | baseUrl: '/base/public/scripts', 14 | paths: { 15 | 'jquery': '../libs/jquery/dist/jquery', 16 | 'angular': '../libs/angular/angular', 17 | 'angularMocks': '../libs/angular-mocks/angular-mocks', 18 | 'templates': '../../views/desktop/templates' 19 | }, 20 | shim: { 21 | 'angular': { 22 | deps: ['jquery'], 23 | exports: 'angular' 24 | }, 25 | 'angularMocks': { 26 | deps: ['angular'], 27 | exports: 'angular.mock' 28 | }, 29 | 'templates/components/mock-tabs.html': ['angular'], 30 | 'templates/components/mock-pane.html': ['angular'] 31 | }, 32 | deps: allTestFiles, 33 | callback: window.__karma__.start 34 | }); 35 | 36 | 37 | 38 | -------------------------------------------------------------------------------- /views/desktop/render/default/error.html: -------------------------------------------------------------------------------- 1 | {% extends "../layout.html" %} 2 | {% block content %} 3 |
4 |

something error

5 |
6 | {% endblock %} -------------------------------------------------------------------------------- /views/desktop/render/default/index.html: -------------------------------------------------------------------------------- 1 | {% extends "../layout.html" %} 2 | {% block content %} 3 |
4 |
5 |
6 |
7 | {% endblock %} -------------------------------------------------------------------------------- /views/desktop/render/default/not-found.html: -------------------------------------------------------------------------------- 1 | {% extends "../layout.html" %} 2 | {% block content %} 3 |
4 |

not found

5 |
6 | {% endblock %} -------------------------------------------------------------------------------- /views/desktop/render/default/samples.html: -------------------------------------------------------------------------------- 1 | {% extends "../layout.html" %} 2 | {% block content %} 3 |
4 |
5 |

The Basics

6 |
7 | 8 | 9 |

Hello !

10 |
11 |
12 |
13 |

Create Filter

14 |
15 | 16 | 17 |

To UpperCase:

18 |
19 |
20 |
21 |

Create Components

22 |
23 | 24 | 25 |

26 |
27 |
28 |
29 |
30 |
31 | {% endblock %} -------------------------------------------------------------------------------- /views/desktop/render/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ipluser - {= title || 'angularjs-requirejs-boilerplate' =} 10 | 11 | 12 | 13 | 14 | 15 | {% if styles %} 16 | {% for style in styles %} 17 | 18 | {% endfor %} 19 | {% endif %} 20 | 21 | 22 |
23 | {% if !hideHeader %} 24 | {% include "./layout/header.html" %} 25 | {% endif %} 26 | 27 | {% block content %}{% endblock content %} 28 | 29 | {% if !hideFooter %} 30 | {% include "./layout/footer.html" %} 31 | {% endif %} 32 |
33 | 34 | 55 | 56 | 57 | {% if isDevMode %} 58 | 59 | 60 | {% else %} 61 | 62 | 63 | 64 | {% endif %} 65 | 66 | 67 | -------------------------------------------------------------------------------- /views/desktop/render/layout/footer.html: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /views/desktop/render/layout/header.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | Fork me on GitHub 4 | 5 |
-------------------------------------------------------------------------------- /views/desktop/templates/components/mock-pane.html: -------------------------------------------------------------------------------- 1 |
2 |
-------------------------------------------------------------------------------- /views/desktop/templates/components/mock-tabs.html: -------------------------------------------------------------------------------- 1 |
2 | 7 |
8 |
-------------------------------------------------------------------------------- /views/desktop/templates/markdown/README.html: -------------------------------------------------------------------------------- 1 |

angularjs-requirejs-boilerplate

2 |

A complete angularjs requirejs boilerplate for node. There are angular and test samples in the project, 3 | you can quick start your new project with angularjs-requirejs-boilerplate.

4 |

Features

5 |

Front-end

6 | 14 |

Back-end

15 | 21 |

Quick Start

22 |

Install Dependencies:

23 |
$ bower install
 24 | $ npm install
 25 | 
26 |

Development

27 |

Development Environment using gulp-nodemon, browser-sync and gulp-jshint.

28 |
    29 |
  1. Make sure isDevMode configuration is true in locals.js
  2. 30 |
  3. Start development mode with gulp --development
  4. 31 |
  5. Input http://localhost:devPort with browsers
  6. 32 |
33 |

Production

34 |
    35 |
  1. Make sure isDevMode configuration is false in locals.js
  2. 36 |
  3. Compile and build with gulp --production
  4. 37 |
  5. Start the server with node or pm2 or others
  6. 38 |
  7. Input http://localhost:port with browsers
  8. 39 |
40 |

Configuration

41 |

System configuration are stored in the locals.js file.

42 |

Samples Page

43 |

Start the server and input http://localhost:port/samples with browsers.

44 |

Gulp

45 |

Show task list with gulp help.

46 |

Test

47 |

Test using karma and jasmine, run the test with npm test or karma start. Unit and coverage test report are stored in report directory.

48 |

Changelog

49 |

2.3.0

50 | 55 |

2.2.1

56 | 60 |

2.2.0

61 | 66 |

2.1.0

67 | 73 |

2.0.0

74 | 80 |

1.1.1

81 | 86 |

1.1.0

87 | 94 |

1.0.0

95 | 99 |

License

100 |

MIT

101 | -------------------------------------------------------------------------------- /views/mobile/render/default/error.html: -------------------------------------------------------------------------------- 1 | {% extends "../layout.html" %} 2 | {% block content %} 3 |
4 |

something error

5 |
6 | {% endblock %} -------------------------------------------------------------------------------- /views/mobile/render/default/index.html: -------------------------------------------------------------------------------- 1 | {% extends "../layout.html" %} 2 | {% block content %} 3 |
4 |
5 |
6 |
7 | {% endblock %} -------------------------------------------------------------------------------- /views/mobile/render/default/not-found.html: -------------------------------------------------------------------------------- 1 | {% extends "../layout.html" %} 2 | {% block content %} 3 |
4 |

not found

5 |
6 | {% endblock %} -------------------------------------------------------------------------------- /views/mobile/render/layout.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | ipluser - {= title || 'angularjs-requirejs-boilerplate' =} 10 | 11 | 12 | 13 | 14 | 15 | {% if styles %} 16 | {% for style in styles %} 17 | 18 | {% endfor %} 19 | {% endif %} 20 | 21 | 22 |
23 | {% if !hideHeader %} 24 | {% include "./layout/header.html" %} 25 | {% endif %} 26 | 27 | {% block content %}{% endblock content %} 28 | 29 | {% if !hideFooter %} 30 | {% include "./layout/footer.html" %} 31 | {% endif %} 32 |
33 | 34 | 55 | 56 | 57 | {% if isDevMode %} 58 | 59 | 60 | {% else %} 61 | 62 | 63 | 64 | {% endif %} 65 | 66 | 67 | -------------------------------------------------------------------------------- /views/mobile/render/layout/footer.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /views/mobile/render/layout/header.html: -------------------------------------------------------------------------------- 1 |
2 | 3 | Fork me on GitHub 4 | 5 |
-------------------------------------------------------------------------------- /views/mobile/templates/markdown/README.html: -------------------------------------------------------------------------------- 1 |

angularjs-requirejs-boilerplate

2 |

A complete angularjs requirejs boilerplate for node. There are angular and test samples in the project, 3 | you can quick start your new project with angularjs-requirejs-boilerplate.

4 |

Features

5 |

Front-end

6 | 14 |

Back-end

15 | 21 |

Quick Start

22 |

Install Dependencies:

23 |
$ bower install
 24 | $ npm install
 25 | 
26 |

Development

27 |

Development Environment using gulp-nodemon, browser-sync and gulp-jshint.

28 |
    29 |
  1. Make sure isDevMode configuration is true in locals.js
  2. 30 |
  3. Start development mode with gulp --development
  4. 31 |
  5. Input http://localhost:devPort with browsers
  6. 32 |
33 |

Production

34 |
    35 |
  1. Make sure isDevMode configuration is false in locals.js
  2. 36 |
  3. Compile and build with gulp --production
  4. 37 |
  5. Start the server with node or pm2 or others
  6. 38 |
  7. Input http://localhost:port with browsers
  8. 39 |
40 |

Configuration

41 |

System configuration are stored in the locals.js file.

42 |

Samples Page

43 |

Start the server and input http://localhost:port/samples with browsers.

44 |

Gulp

45 |

Show task list with gulp help.

46 |

Test

47 |

Test using karma and jasmine, run the test with npm test or karma start. Unit and coverage test report are stored in report directory.

48 |

Changelog

49 |

2.3.0

50 | 55 |

2.2.1

56 | 60 |

2.2.0

61 | 66 |

2.1.0

67 | 73 |

2.0.0

74 | 80 |

1.1.1

81 | 86 |

1.1.0

87 | 94 |

1.0.0

95 | 99 |

License

100 |

MIT

101 | --------------------------------------------------------------------------------