Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# generator-ko
# generator-ko-ts

Generates a starting point for a Knockout application.
Fork of Steven Sanderson's generator-KO for typescript. The goal is to stay insync with the parent as much as possible and only modify to support typescript.
33 changes: 28 additions & 5 deletions app/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,11 @@ var path = require('path');
var yeoman = require('yeoman-generator');
var chalk = require('chalk');

var languageChoice = {
js: 'JavaScript',
ts: 'TypeScript'
};

var KoGenerator = yeoman.generators.Base.extend({
init: function () {
this.pkg = require('../package.json');
Expand Down Expand Up @@ -49,6 +54,11 @@ var KoGenerator = yeoman.generators.Base.extend({
name: 'name',
message: 'What\'s the name of your new site?',
default: path.basename(process.cwd())
}, {
type: 'list',
name: 'codeLanguage',
message: 'What language do you want to use?',
choices: [languageChoice.js, languageChoice.ts]
}, {
type: 'confirm',
name: 'includeTests',
Expand All @@ -59,31 +69,44 @@ var KoGenerator = yeoman.generators.Base.extend({
this.prompt(prompts, function (props) {
this.longName = props.name;
this.slugName = this._.slugify(this.longName);
this.usesTypeScript = props.codeLanguage === languageChoice.ts;
this.includeTests = props.includeTests;
done();
}.bind(this));
},

templating: function () {
this._processDirectory('src', 'src');
var excludeExtension = this.usesTypeScript ? '.js' : '.ts';
this._processDirectory('src', 'src', excludeExtension);
this.template('_package.json', 'package.json');
this.template('_bower.json', 'bower.json');
this.template('_gulpfile.js', 'gulpfile.js');
this.template('_gitignore', '.gitignore');
this.copy('bowerrc', '.bowerrc');
this.copy('jsconfig.json');

if (this.includeTests) {
// Set up tests
this._processDirectory('test', 'test');
this._processDirectory('test', 'test', excludeExtension);
this.copy('bowerrc_test', 'test/.bowerrc');
this.copy('karma.conf.js');
}

// Explicitly copy the .js files used by the .ts output, since they're otherwise excluded
if (this.usesTypeScript) {
this.copy('src/app/require.config.js');
this._processDirectory('definitions', 'definitions');

if (this.includeTests) {
this.copy('test/require.config.js');
}
}
},

_processDirectory: function(source, destination) {
_processDirectory: function(source, destination, excludeExtension) {
var root = this.isPathAbsolute(source) ? source : path.join(this.sourceRoot(), source);
var files = this.expandFiles('**', { dot: true, cwd: root });
var files = this.expandFiles('**', { dot: true, cwd: root }).filter(function(filename) {
return !excludeExtension || path.extname(filename) !== excludeExtension;
});

for (var i = 0; i < files.length; i++) {
var f = files[i];
Expand Down
9 changes: 9 additions & 0 deletions app/templates/_gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,12 @@ bower_modules/

# Don't track build output
dist/
<% if(usesTypeScript) { %>
# Don't track .js/.js.map files (typically they are generated by the TypeScript compiler)
src/**/*.js
src/**/*.js.map

# ... except specific ones, which should be tracked
!src/app/require.config.js
!src/app/lib/*.js*
<% } %>
134 changes: 53 additions & 81 deletions app/templates/_gulpfile.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
// Node modules
var fs = require('fs'), vm = require('vm'), merge = require('deeply'), chalk = require('chalk'), es = require('event-stream'), path = require('path'), url = require('url');
var fs = require('fs'), vm = require('vm'), merge = require('deeply'), chalk = require('chalk'), es = require('event-stream');

// Gulp and plugins
var gulp = require('gulp'), rjs = require('gulp-requirejs-bundler'), concat = require('gulp-concat'), clean = require('gulp-clean'), filter = require('gulp-filter'),
replace = require('gulp-replace'), uglify = require('gulp-uglify'), htmlreplace = require('gulp-html-replace'),
connect = require('gulp-connect'), babelCore = require('babel-core'), babel = require('gulp-babel'), objectAssign = require('object-assign');
var gulp = require('gulp'), rjs = require('gulp-requirejs-bundler'), concat = require('gulp-concat'), clean = require('gulp-clean'),
replace = require('gulp-replace'), uglify = require('gulp-uglify'), htmlreplace = require('gulp-html-replace')
<% if(usesTypeScript) { %>, typescript = require('gulp-tsc')<% } %>, , webserver = require('gulp-webserver');

// Config
var requireJsRuntimeConfig = vm.runInNewContext(fs.readFileSync('src/app/require.config.js') + '; require;'),
var requireJsRuntimeConfig = vm.runInNewContext(fs.readFileSync('src/app/require.config.js') + '; require;');
requireJsOptimizerConfig = merge(requireJsRuntimeConfig, {
out: 'scripts.js',
baseUrl: './src',
Expand All @@ -28,49 +28,32 @@ var requireJsRuntimeConfig = vm.runInNewContext(fs.readFileSync('src/app/require
// 'bundle-name': [ 'some/module', 'another/module' ],
// 'another-bundle-name': [ 'yet-another-module' ]
}
}),
transpilationConfig = {
root: 'src',
skip: ['bower_modules/**', 'app/require.config.js'],
babelConfig: {
modules: 'amd',
sourceMaps: 'inline'
}
},
babelIgnoreRegexes = transpilationConfig.skip.map(function(item) {
return babelCore.util.regexify(item);
});

// Pushes all the source files through Babel for transpilation
gulp.task('js:babel', function() {
return gulp.src(requireJsOptimizerConfig.baseUrl + '/**')
.pipe(es.map(function(data, cb) {
if (!data.isNull()) {
babelTranspile(data.relative, function(err, res) {
if (res) {
data.contents = new Buffer(res.code);
}
cb(err, data);
});
} else {
cb(null, data);
}
<% if (usesTypeScript) { %>
// Compile all .ts files, producing .js and source map files alongside them
gulp.task('ts', function() {
return gulp.src(['src/**/*.ts'], { base: "." })
.pipe(typescript({
module: 'amd',
sourcemap: true,
outDir: '.'
}))
.pipe(gulp.dest('./temp'));
.pipe(gulp.dest('.'));
});


// Watch for changes on .ts files
gulp.task('watch-ts', function(){
gulp.watch('src/**/*.ts', function() {
gulp.start('ts');
});
});

<% } %>
// Discovers all AMD dependencies, concatenates together all required .js files, minifies them
gulp.task('js:optimize', ['js:babel'], function() {
var config = objectAssign({}, requireJsOptimizerConfig, { baseUrl: 'temp' });
return rjs(config)
gulp.task('js', <% if (usesTypeScript) { %>['ts'], <% } %>function () {
return rjs(requireJsOptimizerConfig)
.pipe(uglify({ preserveComments: 'some' }))
.pipe(gulp.dest('./dist/'));
})

// Builds the distributable .js files by calling Babel then the r.js optimizer
gulp.task('js', ['js:optimize'], function () {
// Now clean up
return gulp.src('./temp', { read: false }).pipe(clean());
.pipe(gulp.dest('./dist/'));
});

// Concatenates CSS files, rewrites relative paths to Bootstrap fonts, copies Bootstrap fonts
Expand All @@ -93,51 +76,40 @@ gulp.task('html', function() {
}))
.pipe(gulp.dest('./dist/'));
});

<% if (!usesTypeScript) { %>
// Removes all files from ./dist/
gulp.task('clean', function() {
return gulp.src('./dist/**/*', { read: false })
.pipe(clean());
});

// Starts a simple static file server that transpiles ES6 on the fly to ES5
gulp.task('serve:src', function() {
return connect.server({
root: transpilationConfig.root,
middleware: function(connect, opt) {
return [
function (req, res, next) {
var pathname = path.normalize(url.parse(req.url).pathname);
babelTranspile(pathname, function(err, result) {
if (err) {
next(err);
} else if (result) {
res.setHeader('Content-Type', 'application/javascript');
res.end(result.code);
} else {
next();
}
});
}
];
}
});
});

// After building, starts a trivial static file server
gulp.task('serve:dist', ['default'], function() {
return connect.server({ root: './dist' });
<% } else { %>
// Removes all files from ./dist/, and the .js/.js.map files compiled from .ts
gulp.task('clean', function() {
var distContents = gulp.src('./dist/**/*', { read: false }),
generatedJs = gulp.src(['src/**/*.js', 'src/**/*.js.map'<% if(includeTests) { %>, 'test/**/*.js', 'test/**/*.js.map'<% } %>], { read: false })
.pipe(es.mapSync(function(data) {
// Include only the .js/.js.map files that correspond to a .ts file
return fs.existsSync(data.path.replace(/\.js(\.map)?$/, '.ts')) ? data : undefined;
}));
return es.merge(distContents, generatedJs).pipe(clean());
});

function babelTranspile(pathname, callback) {
if (babelIgnoreRegexes.some(function (re) { return re.test(pathname); })) return callback();
if (!babelCore.canCompile(pathname)) return callback();
var src = path.join(transpilationConfig.root, pathname);
var opts = objectAssign({ sourceFileName: '/source/' + pathname }, transpilationConfig.babelConfig);
babelCore.transformFile(src, opts, callback);
}

<% } %>
gulp.task('default', ['html', 'js', 'css'], function(callback) {
callback();
console.log('\nPlaced optimized files in ' + chalk.magenta('dist/\n'));
});

// Sets up a webserver with live reload for development
gulp.task('webserver', ['ts'], function () {
<% if (usesTypeScript) { %>
gulp.start('watch-ts');
<% } %>

gulp.src('')
.pipe(webserver({
livereload : true,
directoryListing : true,
port : 8080,
open : 'http://localhost:8080/src/index.html'
}));
});
21 changes: 9 additions & 12 deletions app/templates/_package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,16 @@
"gulp-replace": "~0.2.0",
"gulp-uglify": "~0.2.1",
"gulp-html-replace": "~1.0.0",
"gulp-babel": "^5.2.1",
"gulp-connect": "^2.2.0",
"gulp-filter": "^3.0.1",
"object-assign": "^4.0.1",

<% if(usesTypeScript) { %>
"gulp-tsc": "^0.7.0",
"typescript": "1.0.1",
<% } %>
<% if(includeTests) { %>
"karma": "^0.13.10",
"karma-chrome-launcher": "^0.2.1",
"karma-jasmine": "^0.3.6",
"karma-requirejs": "^0.2.2",
"karma-requireglobal-preprocessor": "^0.0.0",
"karma-babel-preprocessor": "^5.2.2",
"jasmine-core": "^2.3.4",
"karma": "^0.12.15",
"karma-chrome-launcher": "^0.1.3",
"karma-jasmine": "^0.1.5",
"karma-requirejs": "^0.2.1",
"karma-requireglobal-preprocessor": "0.0.0",
"requirejs": "^2.1.11",
<% } %>
"deeply": "~0.1.0",
Expand Down
Loading