Skip to content

Commit

Permalink
feat(gen): added support for jade templates
Browse files Browse the repository at this point in the history
When jade flag is set, '--jade', project generates with jade templates. Additionally, any new routes and views generated will use Jade templates if jade is found in your views folder.

closes #19
  • Loading branch information
DaftMonk committed Nov 26, 2013
1 parent c6ae81c commit 24a13bf
Show file tree
Hide file tree
Showing 21 changed files with 413 additions and 37 deletions.
137 changes: 126 additions & 11 deletions app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,21 @@ var Generator = module.exports = function Generator(args, options) {
args.push('--minsafe');
}

if (typeof this.env.options.jade === 'undefined') {
this.option('jade', {
desc: 'Generate views using Jade templates'
});

// attempt to detect if user is using jade or not
// if cml arg provided, use that; else look for the existence of cs
if (!this.options.coffee &&
this.expandFiles(path.join(this.appPath, '/views/**/*.jade'), {}).length > 0) {
this.options.jade = true;
}

this.env.options.jade = this.options.jade;
}

this.hookFor('angular-fullstack:common', {
args: args
});
Expand Down Expand Up @@ -201,7 +216,13 @@ Generator.prototype.askForMongo = function askForMongo() {
};

Generator.prototype.readIndex = function readIndex() {
this.indexFile = this.engine(this.read('../../templates/common/index.html'), this);
this.jade = this.env.options.jade;

if(this.jade) {
this.indexFile = this.engine(this.read('../../templates/views/jade/index.jade'), this);
} else {
this.indexFile = this.engine(this.read('../../templates/views/html/index.html'), this);
}
};

// Waiting a more flexible solution for #138
Expand All @@ -224,15 +245,21 @@ Generator.prototype.bootstrapFiles = function bootstrapFiles() {
this.copy(source + file, 'app/styles/' + file);
}.bind(this));

this.indexFile = this.appendFiles({
var appendOptions = {
html: this.indexFile,
fileType: 'css',
optimizedPath: 'styles/main.css',
sourceFileList: files.map(function (file) {
return 'styles/' + file.replace('.scss', '.css');
}),
searchPath: ['.tmp', 'app']
});
};

if (this.jade) {
this.indexFile = appendFilesToJade(appendOptions);
} else {
this.indexFile = this.appendFiles(appendOptions);
}
};

Generator.prototype.bootstrapJS = function bootstrapJS() {
Expand All @@ -241,7 +268,7 @@ Generator.prototype.bootstrapJS = function bootstrapJS() {
}

// Wire Twitter Bootstrap plugins
this.indexFile = this.appendFiles({
var appendOptions = {
html: this.indexFile,
fileType: 'js',
optimizedPath: 'scripts/plugins.js',
Expand All @@ -260,7 +287,13 @@ Generator.prototype.bootstrapJS = function bootstrapJS() {
'bower_components/sass-bootstrap/js/popover.js'
],
searchPath: 'app'
});
};

if (this.jade) {
this.indexFile = appendFilesToJade(appendOptions);
} else {
this.indexFile = this.appendFiles(appendOptions);
}
};

Generator.prototype.extraModules = function extraModules() {
Expand All @@ -282,28 +315,110 @@ Generator.prototype.extraModules = function extraModules() {
}

if (modules.length) {
this.indexFile = this.appendFiles({
var appendOptions = {
html: this.indexFile,
fileType: 'js',
optimizedPath: 'scripts/modules.js',
sourceFileList: modules,
searchPath: 'app'
});
};

if (this.jade) {
this.indexFile = appendFilesToJade(appendOptions);
} else {
this.indexFile = this.appendFiles(appendOptions);
}
}
};

function generateJadeBlock(blockType, optimizedPath, filesBlock, searchPath, prefix) {
var blockStart, blockEnd;
var blockSearchPath = '';

if (searchPath !== undefined) {
if (util.isArray(searchPath)) {
searchPath = '{' + searchPath.join(',') + '}';
}
blockSearchPath = '(' + searchPath + ')';
}

blockStart = '\n' + prefix + '<!-- build:' + blockType + blockSearchPath + ' ' + optimizedPath + ' -->\n';
blockEnd = prefix + '<!-- endbuild -->\n' + prefix;
return blockStart + filesBlock + blockEnd;
}

function appendJade(jade, tag, blocks){
var mark = "//- build:" + tag,
position = jade.indexOf(mark);
return [jade.slice(0, position), blocks, jade.slice(position)].join('');
}

function appendFilesToJade(jadeOrOptions, fileType, optimizedPath, sourceFileList, attrs, searchPath) {
var blocks, updatedContent,
jade = jadeOrOptions,
prefix = ' ',
files = '';

if (typeof jadeOrOptions === 'object') {
jade = jadeOrOptions.html;
fileType = jadeOrOptions.fileType;
optimizedPath = jadeOrOptions.optimizedPath;
sourceFileList = jadeOrOptions.sourceFileList;
attrs = jadeOrOptions.attrs;
searchPath = jadeOrOptions.searchPath;
}

if (fileType === 'js') {
sourceFileList.forEach(function (el) {
files += prefix + '<script ' + (attrs||'') + 'src="' + el + '"></script>\n';
});
blocks = generateJadeBlock('js', optimizedPath, files, searchPath, prefix);
updatedContent = appendJade(jade, 'body', blocks);
} else if (fileType === 'css') {
sourceFileList.forEach(function (el) {
files += prefix + '<link ' + (attrs||'') + 'rel="stylesheet" href="' + el + '">\n';
});
blocks = generateJadeBlock('css', optimizedPath, files, searchPath, prefix);
updatedContent = appendJade(jade, 'head', blocks);
}
return updatedContent;
}

Generator.prototype.appJs = function appJs() {
this.indexFile = this.appendFiles({
var appendOptions = {
html: this.indexFile,
fileType: 'js',
optimizedPath: 'scripts/scripts.js',
sourceFileList: ['scripts/app.js', 'scripts/controllers/main.js'],
searchPath: ['.tmp', 'app']
});
};
if (this.jade) {
this.indexFile = appendFilesToJade(appendOptions);
} else {
this.indexFile = this.appendFiles(appendOptions);
}
};

Generator.prototype.createIndex = function createIndex() {
if (this.jade) {
this.write(path.join(this.appPath, 'views', 'index.jade'), this.indexFile);
} else {
this.write(path.join(this.appPath, 'views', 'index.html'), this.indexFile);
}
};

Generator.prototype.createIndexHtml = function createIndexHtml() {
this.write(path.join(this.appPath, 'views', 'index.html'), this.indexFile);
Generator.prototype.addJadeViews = function addHtmlJade() {
if(this.jade) {
this.copy('../../templates/views/jade/partials/main.jade', 'app/views/partials/main.jade');
this.copy('../../templates/views/jade/404.jade', 'app/views/404.jade');
}
};

Generator.prototype.addHtmlViews = function addHtmlViews() {
if(!this.jade) {
this.copy('../../templates/views/html/partials/main.html', 'app/views/partials/main.html');
this.copy('../../templates/views/html/404.html', 'app/views/404.html');
}
};

Generator.prototype.packageFiles = function () {
Expand Down
10 changes: 5 additions & 5 deletions deploy/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -66,11 +66,11 @@ Generator.prototype.herokuCreate = function herokuCreate() {
if (err) {
this.log.error(err);
} else {
console.log('stdout: ' + stdout);
console.log(chalk.green('You\'re all set! Now push to heroku with\n\t' + chalk.bold('git push heroku master') +
'\nfrom your new heroku folder'));
console.log(chalk.yellow('After app modification run\n\t' + chalk.bold('grunt heroku') +
'\nthen commit and push the heroku folder'));
console.log('stdout: ' + stdout);
console.log(chalk.green('You\'re all set! Now push to heroku with\n\t' + chalk.bold('git push heroku master') +
'\nfrom your new heroku folder'));
console.log(chalk.yellow('After app modification run\n\t' + chalk.bold('grunt heroku') +
'\nthen commit and push the heroku folder'));
}
done();
}.bind(this));
Expand Down
19 changes: 15 additions & 4 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@ Featuring:
* Express server integrated with grunt tasks
* Livereload of client and server files
* Easy deployment workflow.
* **NEW** Optional mongoDB integration
* Optional mongoDB integration
* **NEW** Support for jade templates

Based on [generator-angular](https://github.com/yeoman/generator-angular)

Expand All @@ -33,17 +34,17 @@ yo angular-fullstack [app-name]

Launch your express server in development mode.
```
grunt serv
grunt serve
```

Launch your express server in production mode, uses the minified/optimized production app folder.
```
grunt serv:dist
grunt serve:dist
```

### Livereload

`grunt server` will watch client files in `app/`, and server files inside `lib/`, restarting the Express server when a change is detected.
`grunt serve` will watch client files in `app/`, and server files inside `lib/`, restarting the Express server when a change is detected.

### Deployment

Expand Down Expand Up @@ -222,6 +223,16 @@ angular.module('myMod').config(function ($provide) {
## Options
In general, these options can be applied to any generator, though they only affect generators that produce scripts.

### Jade
For generators that output views, the `--jade` option will output Jade instead of HTML.

For example:
```bash
yo angular-fullstack --jade
```

Changes the rendering engine from EJS to Jade, and generates your views as jade files instead of HTML.

### CoffeeScript
For generators that output scripts, the `--coffee` option will output CoffeeScript instead of JavaScript.

Expand Down
2 changes: 1 addition & 1 deletion route/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ Generator.prototype.rewriteAppJs = function () {
),
needle: '.otherwise',
splicable: [
" templateUrl: 'views/partials/" + this.name + ".html'" + (coffee ? "" : "," ),
" templateUrl: 'partials/" + this.name + "'" + (coffee ? "" : "," ),
" controller: '" + this.classedName + "Ctrl'"
]
};
Expand Down
24 changes: 22 additions & 2 deletions script-base.js
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,26 @@ var Generator = module.exports = function Generator() {
sourceRoot += '-min';
}

if (typeof this.env.options.jade === 'undefined') {
this.option('jade', {
desc: 'Generate views using Jade templates'
});

// attempt to detect if user is using jade or not
// if cml arg provided, use that; else look for the existence of cs
if (!this.options.jade &&
this.expandFiles(path.join(this.env.options.appPath, '/views/**/*.jade'), {}).length > 0) {
this.options.jade = true;
}

this.env.options.jade = this.options.jade;
}

this.viewSuffix = '.html';
if (this.env.options.jade) {
this.viewSuffix = '.jade';
}

this.sourceRoot(path.join(__dirname, sourceRoot));
};

Expand Down Expand Up @@ -92,7 +112,7 @@ Generator.prototype.htmlTemplate = function (src, dest) {
Generator.prototype.addScriptToIndex = function (script) {
try {
var appPath = this.env.options.appPath;
var fullPath = path.join(appPath, 'views', 'index.html');
var fullPath = path.join(appPath, 'views', 'index' + this.viewSuffix);
angularUtils.rewriteFile({
file: fullPath,
needle: '<!-- endbuild -->',
Expand All @@ -111,4 +131,4 @@ Generator.prototype.generateSourceAndTest = function (appTemplate, testTemplate,
if (!skipAdd) {
this.addScriptToIndex(path.join(targetDirectory, this.name));
}
};
};
2 changes: 1 addition & 1 deletion templates/coffeescript-min/app.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ angular.module('<%= scriptAppName %>', [<%= angularModules %>])
.config ['$routeProvider', '$locationProvider', ($routeProvider, $locationProvider) ->
$routeProvider
.when '/',
templateUrl: 'views/main.html'
templateUrl: 'views/main'
controller: 'MainCtrl'
.otherwise
redirectTo: '/'
Expand Down
2 changes: 1 addition & 1 deletion templates/coffeescript/app.coffee
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ angular.module('<%= scriptAppName %>', [<%= angularModules %>])
.config ($routeProvider, $locationProvider) ->
$routeProvider
.when '/',
templateUrl: 'views/main.html'
templateUrl: 'views/main'
controller: 'MainCtrl'
.otherwise
redirectTo: '/'
Expand Down
16 changes: 12 additions & 4 deletions templates/common/Gruntfile.js
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ module.exports = function (grunt) {
},<% } %>
livereload: {
files: [
'<%%= yeoman.app %>/<%%= yeoman.views %>/{,*//*}*.html',
'<%%= yeoman.app %>/<%%= yeoman.views %>/{,*//*}*.{html,jade}',
'{.tmp,<%%= yeoman.app %>}/styles/{,*//*}*.css',
'{.tmp,<%%= yeoman.app %>}/scripts/{,*//*}*.js',
'<%%= yeoman.app %>/images/{,*//*}*.{png,jpg,jpeg,gif,webp,svg}',
Expand Down Expand Up @@ -230,15 +230,17 @@ module.exports = function (grunt) {
// concat, minify and revision files. Creates configurations in memory so
// additional tasks can operate on them
useminPrepare: {
html: '<%%= yeoman.app %>/<%%= yeoman.views %>/index.html',
html: ['<%%= yeoman.app %>/<%%= yeoman.views %>/index.html',
'<%%= yeoman.app %>/<%%= yeoman.views %>/index.jade'],
options: {
dest: '<%%= yeoman.dist %>'
}
},

// Performs rewrites based on rev and the useminPrepare configuration
usemin: {
html: ['<%%= yeoman.views %>/{,*/}*.html'],
html: ['<%%= yeoman.views %>/{,*/}*.html',
'<%%= yeoman.views %>/{,*/}*.jade'],
css: ['<%%= yeoman.dist %>/styles/{,*/}*.css'],
options: {
assetsDirs: ['<%%= yeoman.dist %>']
Expand Down Expand Up @@ -322,6 +324,12 @@ module.exports = function (grunt) {
'images/{,*/}*.{webp}',
'fonts/*'
]
}, {
expand: true,
dot: true,
cwd: '<%%= yeoman.app %>/<%%= yeoman.views %>',
dest: '<%%= yeoman.views %>',
src: '**/*.jade',
}, {
expand: true,
cwd: '.tmp/images',
Expand All @@ -338,7 +346,7 @@ module.exports = function (grunt) {
dest: 'heroku',
src: [
'<%%= yeoman.dist %>/**',
'<%= yeoman.views %>/**'
'<%%= yeoman.views %>/**'
]
}, {
expand: true,
Expand Down
Loading

0 comments on commit 24a13bf

Please sign in to comment.