With this setup you can freely mix .js
and .coffee
files in your app/scripts
directory, and everything will just work.
We strongly suggest to scaffold your app with Babel (the default behavior), that way it's easier to add CoffeeScript support using the existing infrastructure.
1. Install dependencies the gulp-coffee plugin
Current setup includes coding in JavaScript, compiling with Babel, and linting with ESLint. We're instead going to code in CoffeeScript and lint with CoffeeLint:
$ npm install --save-dev gulp-coffee
The task previously only compiled .js
files with Babel. We need to modify it to also compile .coffee
files with CoffeeScript. This can be achieved very easily using gulp-if:
gulp.task('scripts', () => {
- return gulp.src('app/scripts/**/*.js')
+ return gulp.src('app/scripts/**/*.{js,coffee}')
.pipe($.plumber())
.pipe($.sourcemaps.init())
- .pipe($.babel())
+ .pipe($.if('.js', $.babel(), $.coffee()))
.pipe($.sourcemaps.write('.'))
.pipe(gulp.dest('.tmp/scripts'))
.pipe(reload({stream: true}));
});
We need to tell gulp to recompile .coffee
files on change, like we're already doing for .js
files:
gulp.task('serve', () => {
runSequence(['clean', 'wiredep'], ['styles', 'scripts', 'fonts'], () => {
...
gulp.watch('app/styles/**/*.scss', ['styles']);
- gulp.watch('app/scripts/**/*.js', ['scripts']);
+ gulp.watch('app/scripts/**/*.{js,coffee}', ['scripts']);
gulp.watch('app/fonts/**/*', ['fonts']);
gulp.watch('bower.json', ['wiredep', 'fonts']);
});
});
This task compiles .coffee
files located in test/spec
into the .tmp/spec
directory and reloads the browser.
gulp.task('scripts:test', () => {
return gulp.src('test/spec/**/*.coffee')
.pipe($.plumber())
.pipe($.coffee())
.pipe(gulp.dest('.tmp/spec'))
.pipe(reload({stream: true}));
});
gulp.task('serve:test', ['scripts', 'scripts:test'], () => {
// ...
});
We should modify this task so that compiled .js
files are served and that changes to .coffee
files trigger recompilation of tests:
gulp.task('serve:test', ['scripts', 'scripts:test'], () => {
browserSync({
notify: false,
port: 9000,
ui: false,
server: {
- baseDir: ['test'],
+ baseDir: ['.tmp', 'test'],
routes: {
'/bower_components': 'bower_components'
}
}
});
gulp.watch('app/scripts/**/*.js', ['scripts']);
+ gulp.watch('test/spec/**/*.coffee', ['scripts:test']);
gulp.watch(['test/spec/**/*.js', 'test/index.html']).on('change', reload);
gulp.watch('test/spec/**/*.js', ['lint:test']);
});
ESLint only supports JavaScript. In case you'd like to lint .coffee
files too, we can set that up using CoffeeLint.
4.1 Install the gulp-coffeelint plugin and lazypipe
$ npm install --save-dev gulp-coffeelint lazypipe
We want to lint .js
files with ESLint and .coffee
with CoffeeLint. This is not as trivial as compiling with Babel and CoffeeScript that we set up earlier because, based on the extension, we need to execute multiple actions, not just one.
For this task we will use lazypipe to set up channels for ESLint and CoffeeLint:
const lazypipe = require('lazypipe');
// ...
const eslintChannel = lazypipe()
.pipe($.eslint, { fix: true })
.pipe(reload, {stream: true, once: true})
.pipe($.eslint.format)
.pipe($.if, !browserSync.active, $.eslint.failAfterError());
const coffeelintChannel = lazypipe()
.pipe($.coffeelint)
.pipe($.coffeelint.reporter)
.pipe($.if, !browserSync.active, $.coffeelint.reporter('fail'))
Note: We should not call plugins when defining lazypipe channels! We should just pass the reference and arguments as needed, like this:
.pipe($.eslint, { fix: true })
not this:
.pipe($.eslint({ fix: true }))
Now we should use those channels based on the file extension:
function lint(files, options) {
return gulp.src(files)
- .pipe($.eslint({ fix: true }))
- .pipe(reload({stream: true, once: true}))
- .pipe($.eslint.format())
- .pipe($.if(!browserSync.active, $.eslint.failAfterError()));
+ .pipe($.if('*.js', eslintChannel(), coffeelintChannel()));
}
gulp.task('lint', () => {
- return lint('app/scripts/**/*.js')
+ return lint('app/scripts/**/*.{js,coffee}')
.pipe(gulp.dest('app/scripts'));
});
gulp.task('lint:test', () => {
- return lint('test/spec/**/*.js')
+ return lint('test/spec/**/*.{js,coffee}')
.pipe(gulp.dest('test/spec'));
});
-
Put your
.coffee
files inapp/scripts
andtest/spec
, and include them in your HTML as if they're.js
files (e.g.app/scripts/foo.coffee
=><script src="scripts/foo.js"></script>
). -
It's fine to have a mixture of
.js
and.coffee
files in yourapp/scripts
directory, just make sure they don't have the same basename. If you have bothfoo.js
andfoo.coffee
, one will overwrite the other when compiled.