Skip to content

Commit 3ed4a79

Browse files
committed
Added CoffeeScript loader support
1 parent bcfbbfd commit 3ed4a79

File tree

13 files changed

+232
-0
lines changed

13 files changed

+232
-0
lines changed

fixtures/js/index.coffee

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
fun = () ->
2+
document.getElementById("app").innerHTML = "<h1>Welcome to Your Coffee App</h1>"
3+
4+
fun()

index.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -590,6 +590,27 @@ const publicApi = {
590590
return this;
591591
},
592592

593+
/**
594+
* Call this if you plan on loading CoffeeScript files.
595+
*
596+
* Encore.enableCoffeeScriptLoader()
597+
*
598+
* Or, configure the coffee-loader options:
599+
*
600+
* Encore.enableCoffeeScriptLoader(function(coffeeScriptOptions) {
601+
* // http://coffeescript.org/#nodejs-usage
602+
* // coffeeScriptOptions.header = true;
603+
* });
604+
*
605+
* @param {function} callback
606+
* @return {exports}
607+
*/
608+
enableCoffeeScriptLoader(callback = () => {}) {
609+
webpackConfig.enableCoffeeScriptLoader(callback);
610+
611+
return this;
612+
},
613+
593614
/**
594615
* Call this to enable forked type checking for TypeScript loader
595616
* https://github.com/TypeStrong/ts-loader/blob/v2.3.0/README.md#faster-builds

lib/WebpackConfig.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ class WebpackConfig {
6060
this.usePreact = false;
6161
this.useVueLoader = false;
6262
this.useTypeScriptLoader = false;
63+
this.useCoffeeScriptLoader = false;
6364
this.useForkedTypeScriptTypeChecking = false;
6465
this.useWebpackNotifier = false;
6566

@@ -79,6 +80,7 @@ class WebpackConfig {
7980
this.babelConfigurationCallback = () => {};
8081
this.vueLoaderOptionsCallback = () => {};
8182
this.tsConfigurationCallback = () => {};
83+
this.coffeeScriptConfigurationCallback = () => {};
8284

8385
// Plugins options
8486
this.cleanWebpackPluginPaths = ['**/*'];
@@ -393,6 +395,16 @@ class WebpackConfig {
393395
forkedTypeScriptTypesCheckOptionsCallback;
394396
}
395397

398+
enableCoffeeScriptLoader(callback = () => {}) {
399+
this.useCoffeeScriptLoader = true;
400+
401+
if (typeof callback !== 'function') {
402+
throw new Error('Argument 1 to enableCoffeeScriptLoader() must be a callback function.');
403+
}
404+
405+
this.coffeeScriptConfigurationCallback = callback;
406+
}
407+
396408
enableVueLoader(vueLoaderOptionsCallback = () => {}) {
397409
this.useVueLoader = true;
398410

lib/config-generator.js

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ const lessLoaderUtil = require('./loaders/less');
1818
const stylusLoaderUtil = require('./loaders/stylus');
1919
const babelLoaderUtil = require('./loaders/babel');
2020
const tsLoaderUtil = require('./loaders/typescript');
21+
const coffeeScriptLoaderUtil = require('./loaders/coffee-script');
2122
const vueLoaderUtil = require('./loaders/vue');
2223
// plugins utils
2324
const extractTextPluginUtil = require('./plugins/extract-text');
@@ -209,6 +210,13 @@ class ConfigGenerator {
209210
});
210211
}
211212

213+
if (this.webpackConfig.useCoffeeScriptLoader) {
214+
rules.push({
215+
test: /\.coffee$/,
216+
use: coffeeScriptLoaderUtil.getLoaders(this.webpackConfig)
217+
});
218+
}
219+
212220
this.webpackConfig.loaders.forEach((loader) => {
213221
rules.push(loader);
214222
});

lib/features.js

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,11 @@ const features = {
5151
packages: ['typescript', 'ts-loader'],
5252
description: 'process TypeScript files'
5353
},
54+
coffeescript: {
55+
method: 'enableCoffeeScriptLoader()',
56+
packages: ['coffeescript', 'coffee-loader'],
57+
description: 'process CoffeeScript files'
58+
},
5459
forkedtypecheck: {
5560
method: 'enableForkedTypeScriptTypesChecking()',
5661
packages: ['typescript', 'ts-loader', 'fork-ts-checker-webpack-plugin'],

lib/loaders/coffee-script.js

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
* This file is part of the Symfony Webpack Encore package.
3+
*
4+
* (c) Fabien Potencier <fabien@symfony.com>
5+
*
6+
* For the full copyright and license information, please view the LICENSE
7+
* file that was distributed with this source code.
8+
*/
9+
10+
'use strict';
11+
12+
const loaderFeatures = require('../features');
13+
14+
/**
15+
* @param {WebpackConfig} webpackConfig
16+
* @return {Array} of loaders to use for coffeescript files
17+
*/
18+
module.exports = {
19+
getLoaders(webpackConfig) {
20+
loaderFeatures.ensurePackagesExist('coffeescript');
21+
22+
const options = {
23+
sourceMap: webpackConfig.useSourceMaps,
24+
transpile: {
25+
presets: ['env']
26+
}
27+
};
28+
29+
// allow options to be configured
30+
webpackConfig.coffeeScriptConfigurationCallback.apply(
31+
options,
32+
[options]
33+
);
34+
35+
return [
36+
{
37+
loader: 'coffee-loader',
38+
options: options,
39+
},
40+
];
41+
}
42+
};

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,8 @@
5555
"babel-preset-react": "^6.23.0",
5656
"chai": "^3.5.0",
5757
"chai-fs": "^1.0.0",
58+
"coffee-loader": "^0.9.0",
59+
"coffeescript": "^2.0.2",
5860
"eslint": "^3.19.0",
5961
"eslint-plugin-header": "^1.0.0",
6062
"eslint-plugin-node": "^4.2.2",

test/WebpackConfig.js

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,31 @@ describe('WebpackConfig object', () => {
609609
});
610610
});
611611

612+
describe('enableCoffeeScriptLoader', () => {
613+
it('Calling method sets it', () => {
614+
const config = createConfig();
615+
config.enableCoffeeScriptLoader();
616+
617+
expect(config.useCoffeeScriptLoader).to.be.true;
618+
});
619+
620+
it('Calling with callback', () => {
621+
const config = createConfig();
622+
const callback = () => {};
623+
config.enableCoffeeScriptLoader(callback);
624+
625+
expect(config.coffeeScriptConfigurationCallback).to.equal(callback);
626+
});
627+
628+
it('Calling with non-callback throws an error', () => {
629+
const config = createConfig();
630+
631+
expect(() => {
632+
config.enableCoffeeScriptLoader('FOO');
633+
}).to.throw('must be a callback function');
634+
});
635+
});
636+
612637
describe('enableVueLoader', () => {
613638
it('Call with no config', () => {
614639
const config = createConfig();

test/config-generator.js

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,30 @@ describe('The config-generator function', () => {
333333
});
334334
});
335335

336+
describe('enableCoffeeScriptLoader() adds the coffee-loader', () => {
337+
it('without enableCoffeeScriptLoader()', () => {
338+
const config = createConfig();
339+
config.outputPath = '/tmp/output/public-path';
340+
config.publicPath = '/public-path';
341+
config.addEntry('main', './main');
342+
const actualConfig = configGenerator(config);
343+
344+
expect(JSON.stringify(actualConfig.module.rules)).to.not.contain('coffee-loader');
345+
});
346+
347+
it('enableCoffeeScriptLoader()', () => {
348+
const config = createConfig();
349+
config.outputPath = '/tmp/output/public-path';
350+
config.publicPath = '/public-path';
351+
config.addEntry('main', './main');
352+
config.enableCoffeeScriptLoader();
353+
354+
const actualConfig = configGenerator(config);
355+
356+
expect(JSON.stringify(actualConfig.module.rules)).to.contain('coffee-loader');
357+
});
358+
});
359+
336360
describe('addLoader() adds a custom loader', () => {
337361
it('addLoader()', () => {
338362
const config = createConfig();

test/functional.js

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -831,6 +831,37 @@ module.exports = {
831831
}).to.throw('wrong `tsconfig` path in fork plugin configuration (should be a relative or absolute path)');
832832
});
833833

834+
it('When configured, CoffeeScript is compiled', (done) => {
835+
const config = createWebpackConfig('www/build', 'dev');
836+
config.setPublicPath('/build');
837+
config.addEntry('main', ['./js/index.coffee']);
838+
const testCallback = () => {};
839+
config.enableCoffeeScriptLoader(testCallback);
840+
841+
testSetup.runWebpack(config, (webpackAssert) => {
842+
webpackAssert.assertOutputFileContains(
843+
'main.js',
844+
'return document.getElementById("app").innerHTML = "<h1>Welcome to Your Coffee App</h1>"'
845+
);
846+
847+
expect(config.outputPath).to.be.a.directory().with.deep.files([
848+
'main.js',
849+
'manifest.json'
850+
]);
851+
852+
testSetup.requestTestPage(
853+
path.join(config.getContext(), 'www'),
854+
[
855+
'build/main.js'
856+
],
857+
(browser) => {
858+
browser.assert.text('#app h1', 'Welcome to Your Coffee App');
859+
done();
860+
}
861+
);
862+
});
863+
});
864+
834865
it('The output directory is cleaned between builds', (done) => {
835866
const config = createWebpackConfig('www/build', 'dev');
836867
config.setPublicPath('/build');

0 commit comments

Comments
 (0)