From 27326ff1a404d8e52999389351edd1b217154e11 Mon Sep 17 00:00:00 2001 From: Couto Date: Sat, 28 Mar 2015 15:57:18 +0000 Subject: [PATCH 01/20] Move cache related functions to own file. --- lib/fs-cache.js | 112 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 lib/fs-cache.js diff --git a/lib/fs-cache.js b/lib/fs-cache.js new file mode 100644 index 00000000..ad5bc8da --- /dev/null +++ b/lib/fs-cache.js @@ -0,0 +1,112 @@ +/** + * + * @see https://github.com/babel/babel-loader/issues/34 + * @see https://github.com/babel/babel-loader/pull/41 + */ + +var crypto = require('crypto'), + fs = require('fs'), + os = require('os'), + path = require('path'), + zlib = require('zlib'); + +/** + * [read description] + * + * @async + * @params {String} filename + * @params {Function} callback + */ +var read = function (filename, callback) { + fs.readFile(filename, function (err, data) { + if (err) { return callback(err); } + + zlib.gunzip(data, function (err, content) { + var result = {}; + + if (err) { return callback(err); } + + try { + result = JSON.parse(content); + } catch (e) { + return callback(e); + } + + return callback(null, content); + }); + }); +}; + + +/** + * [write description] + * + * @async + * @params {String} filename + * @params {String} result + * @params {Function} callback + */ +var write = function (filename, result, callback) { + var content = JSON.stringify(result); + + zlb.gzip(content, function (err, data) { + if (err) { return callback(err); } + + fs.writeFile(filename, data, callback); + }); +}; + + +/** + * Build the filename for the cached file + * + * @params {String} source File source code + * @params {Object} options Options used + * + * @return {String} + */ +var filename = function (source, options) { + var hash = crypto.createHash('SHA1'), + contents = JSON.stringify({ + source: source, + options: options + }); + + hash.end(contents); + + return 'babel-loader-cache-' + + hash.read().toString('hex') + + '.json.gzip'; +}; + +/** + * [exports description] + * @param {[type]} directory [description] + * @param {[type]} source [description] + * @param {[type]} options [description] + * @param {[type]} transform [description] + * @param {Function} callback [description] + * @return {[type]} [description] + */ +var cache = module.exports = function (directory, source, options, transform, callback) { + var file = path.join(directory, filename(source, options)); + + read(file, function (err, result) { + var content = ''; + + if (err) { + try { + content = transform(source, options); + } catch (e) { + return callback(e); + } + + return write(file, result, function (err) { + callback(err, result); + }); + } + + return callback(null, result); + }); + +}; From 99316de9821f682d1dcea7ff53de8459eed43dfa Mon Sep 17 00:00:00 2001 From: Couto Date: Sat, 28 Mar 2015 17:43:51 +0000 Subject: [PATCH 02/20] [WIP] Move cache related functions to lib. * Create fs-cache module to handle caching * Refactor index to use new module * [WIP] Create cache test to ensure correctness --- .gitignore | 1 + index.js | 95 ++++++++---------------------------- lib/fs-cache.js | 43 +++++++++++----- package.json | 4 +- test/cache/webpack.config.js | 19 ++++++++ 5 files changed, 73 insertions(+), 89 deletions(-) create mode 100644 test/cache/webpack.config.js diff --git a/.gitignore b/.gitignore index 3c3629e6..67972574 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,2 @@ node_modules +test/output diff --git a/index.js b/index.js index 33e4bc1f..ef7302cf 100644 --- a/index.js +++ b/index.js @@ -1,16 +1,17 @@ var loaderUtils = require('loader-utils'), + pkg = require('./package.json'), babel = require('babel-core'), - crypto = require('crypto'), - fs = require('fs'), - path = require('path'), - os = require('os'), - zlib = require('zlib'), - version = require('./package').version, + cache = require('./lib/fs-cache.js'), toBoolean = function (val) { if (val === 'true') { return true; } if (val === 'false') { return false; } return val; - }; + }, + // Create an identifier for the cache function + identifier = JSON.stringify({ + loader: pkg.version, + babel: babel.version + }); module.exports = function (source, inputSourceMap) { @@ -35,18 +36,19 @@ module.exports = function (source, inputSourceMap) { cacheDirectory = options.cacheDirectory; delete options.cacheDirectory; - if (cacheDirectory === true) cacheDirectory = os.tmpdir(); - if (cacheDirectory){ - cachedTranspile(cacheDirectory, source, options, onResult); + cache({ + directory: cacheDirectory, + identifier: identifier, + source: source, + options: options, + transform: transpile, + }, function (err, result) { + callback(err, result.code, result.map); + }); } else { - onResult(null, transpile(source, options)); - } - - function onResult(err, result){ - if (err) return callback(err); - - callback(err, err ? null : result.code, err ? null : result.map); + result = transpile(source, options); + callback(null, result.code, result.map); } }; @@ -64,62 +66,3 @@ function transpile(source, options){ map: map }; } - -function cachedTranspile(cacheDirectory, source, options, callback){ - var cacheFile = path.join(cacheDirectory, buildCachePath(cacheDirectory, source, options)); - - readCache(cacheFile, function(err, result){ - if (err){ - try { - result = transpile(source, options); - } catch (e){ - return callback(e); - } - - writeCache(cacheFile, result, function(err){ - callback(err, result); - }); - } else { - callback(null, result); - } - }); -} - -function readCache(cacheFile, callback){ - fs.readFile(cacheFile, function(err, data){ - if (err) return callback(err); - - zlib.gunzip(data, function(err, content){ - if (err) return callback(err); - - try { - content = JSON.parse(content); - } catch (e){ - return callback(e); - } - - callback(null, content); - }); - }); -} - -function writeCache(cacheFile, result, callback){ - var content = JSON.stringify(result); - - zlib.gzip(content, function(err, data){ - if (err) return callback(err); - - fs.writeFile(cacheFile, data, callback); - }); -} - -function buildCachePath(dir, source, options){ - var hash = crypto.createHash('SHA1'); - hash.end(JSON.stringify({ - loaderVersion: version, - babelVersion: babel.version, - source: source, - options: options - })); - return 'babel-loader-cache-' + hash.read().toString('hex') + '.json.gzip'; -} diff --git a/lib/fs-cache.js b/lib/fs-cache.js index ad5bc8da..5efd5a14 100644 --- a/lib/fs-cache.js +++ b/lib/fs-cache.js @@ -1,9 +1,12 @@ /** + * Filesystem cache + * + * Given a file and a transform function, cache the result into files + * or retrieve the previously cached files if the given file is already known. * * @see https://github.com/babel/babel-loader/issues/34 * @see https://github.com/babel/babel-loader/pull/41 */ - var crypto = require('crypto'), fs = require('fs'), os = require('os'), @@ -65,11 +68,12 @@ var write = function (filename, result, callback) { * * @return {String} */ -var filename = function (source, options) { +var filename = function (source, identifier, options) { var hash = crypto.createHash('SHA1'), contents = JSON.stringify({ source: source, - options: options + options: options, + identifier: identifier }); hash.end(contents); @@ -80,16 +84,31 @@ var filename = function (source, options) { }; /** - * [exports description] - * @param {[type]} directory [description] - * @param {[type]} source [description] - * @param {[type]} options [description] - * @param {[type]} transform [description] - * @param {Function} callback [description] - * @return {[type]} [description] + * cache + * + * @async + * @param {Object} params + * @param {String} params.directory Directory where cached files will be stored + * @param {String} params.identifier Unique identifier to help with cache busting + * @param {String} params.source Original contents of the file to be cached + * @param {Object} params.options Options to be given to the transform function + * @param {Function} params.transform Function that will transform the original + * file and whose result will be cached + * @param {Function} callback */ -var cache = module.exports = function (directory, source, options, transform, callback) { - var file = path.join(directory, filename(source, options)); +var cache = module.exports = function (params, callback) { + // Spread params into named variables + // Forgive user whenever possible + var directory = (typeof params.directory === 'string') ? + params.directory : + os.tmpdir(), + source = params.source, + options = params.options || {}, + transform = params.transform, + identifier = params.identifier, + file = path.join(directory, filename(source, identifier, options)); + + console.log('> ', file) read(file, function (err, result) { var content = ''; diff --git a/package.json b/package.json index 0f49fec7..4906a1d4 100644 --- a/package.json +++ b/package.json @@ -11,13 +11,15 @@ "webpack": "^1.4.5" }, "devDependencies": { + "babel-loader": "./index.js", "mocha": "^2.0.1", "mocha-loader": "^0.7.0", "should": "^4.3.1", "webpack-dev-server": "^1.6.6" }, "scripts": { - "test": "webpack-dev-server --config=test/webpack.config.js" + "test": "webpack-dev-server --config=test/webpack.config.js", + "test:cache": "webpack --config test/cache/webpack.config.js" }, "repository": { "type": "git", diff --git a/test/cache/webpack.config.js b/test/cache/webpack.config.js new file mode 100644 index 00000000..7ffa5086 --- /dev/null +++ b/test/cache/webpack.config.js @@ -0,0 +1,19 @@ +var path = require('path'); + +// Just run "webpack-dev-server" +module.exports = { + context: __dirname, + entry: '../fixtures/basic.js', + output: { + path: path.resolve(__dirname, '../output'), + filename: 'bundle.cache.js' + }, + module: { + loaders: [ + { + test: '\.js', + loader: 'babel?cacheDirectory=' + path.resolve(__dirname, '../output/cache') + } + ] + } +}; From 661cafb1b0b593bbe9fc6f4113e3794cd39b7204 Mon Sep 17 00:00:00 2001 From: Couto Date: Sat, 28 Mar 2015 20:14:00 +0000 Subject: [PATCH 03/20] [WIP] Add cache idenfier as option. * Add cache test. * Fix minor mistakes. * Update dependencies. --- index.js | 16 ++--- lib/fs-cache.js | 50 +++++++------- package.json | 17 +++-- test/cache.test.js | 128 +++++++++++++++++++++++++++++++++++ test/cache/webpack.config.js | 19 ------ test/fixtures/basic.js | 4 +- test/fixtures/constant.js | 1 + test/fixtures/import.js | 7 ++ test/fixtures/test.js | 3 - 9 files changed, 181 insertions(+), 64 deletions(-) create mode 100644 test/cache.test.js delete mode 100644 test/cache/webpack.config.js create mode 100644 test/fixtures/constant.js create mode 100644 test/fixtures/import.js delete mode 100644 test/fixtures/test.js diff --git a/index.js b/index.js index ef7302cf..872cf02e 100644 --- a/index.js +++ b/index.js @@ -6,15 +6,9 @@ var loaderUtils = require('loader-utils'), if (val === 'true') { return true; } if (val === 'false') { return false; } return val; - }, - // Create an identifier for the cache function - identifier = JSON.stringify({ - loader: pkg.version, - babel: babel.version - }); + }; module.exports = function (source, inputSourceMap) { - var options = loaderUtils.parseQuery(this.query), callback = this.async(), result, cacheDirectory; @@ -34,12 +28,18 @@ module.exports = function (source, inputSourceMap) { options.filename = loaderUtils.getRemainingRequest(this); cacheDirectory = options.cacheDirectory; + cacheIdentifier = options.cacheIdentifier || JSON.stringify({ + 'babel-loader': pkg.version, + 'babel-core': babel.version + }); + delete options.cacheDirectory; + delete options.cacheIdentifier; if (cacheDirectory){ cache({ directory: cacheDirectory, - identifier: identifier, + identifier: cacheIdentifier, source: source, options: options, transform: transpile, diff --git a/lib/fs-cache.js b/lib/fs-cache.js index 5efd5a14..0cefeef0 100644 --- a/lib/fs-cache.js +++ b/lib/fs-cache.js @@ -14,7 +14,9 @@ var crypto = require('crypto'), zlib = require('zlib'); /** - * [read description] + * read + * + * Read the contents from the compressed file. * * @async * @params {String} filename @@ -42,7 +44,9 @@ var read = function (filename, callback) { /** - * [write description] + * write + * + * Write contents into a compressed file. * * @async * @params {String} filename @@ -52,7 +56,7 @@ var read = function (filename, callback) { var write = function (filename, result, callback) { var content = JSON.stringify(result); - zlb.gzip(content, function (err, data) { + zlib.gzip(content, function (err, data) { if (err) { return callback(err); } fs.writeFile(filename, data, callback); @@ -78,9 +82,7 @@ var filename = function (source, identifier, options) { hash.end(contents); - return 'babel-loader-cache-' + - hash.read().toString('hex') + - '.json.gzip'; + return hash.read().toString('hex') + '.json.gzip'; }; /** @@ -94,38 +96,34 @@ var filename = function (source, identifier, options) { * @param {Object} params.options Options to be given to the transform function * @param {Function} params.transform Function that will transform the original * file and whose result will be cached + * * @param {Function} callback */ var cache = module.exports = function (params, callback) { // Spread params into named variables // Forgive user whenever possible - var directory = (typeof params.directory === 'string') ? - params.directory : - os.tmpdir(), - source = params.source, + var source = params.source, options = params.options || {}, transform = params.transform, - identifier = params.identifier, - file = path.join(directory, filename(source, identifier, options)); + identifier = params.identifier, // @TODO ensure that 'undefined' will not break + directory = (typeof params.directory === 'string') ? + params.directory : + os.tmpdir(); - console.log('> ', file) + var file = path.join(directory, filename(source, identifier, options)); - read(file, function (err, result) { - var content = ''; - if (err) { - try { - content = transform(source, options); - } catch (e) { - return callback(e); - } + read(file, function (err, content) { + var result = {}; + + if (!err) { return callback(null, content); } - return write(file, result, function (err) { - callback(err, result); - }); - } + result = transform(source, options); + + return write(file, result, function (err) { + callback(err, result); + }); - return callback(null, result); }); }; diff --git a/package.json b/package.json index 4906a1d4..dae6cc4a 100644 --- a/package.json +++ b/package.json @@ -4,18 +4,21 @@ "description": "babel module loader for webpack", "main": "index.js", "dependencies": { - "loader-utils": "^0.2.5" + "loader-utils": "^0.2.6" }, "peerDependencies": { "babel-core": "^4.7.0", - "webpack": "^1.4.5" + "webpack": "^1.7.3" }, "devDependencies": { - "babel-loader": "./index.js", - "mocha": "^2.0.1", - "mocha-loader": "^0.7.0", - "should": "^4.3.1", - "webpack-dev-server": "^1.6.6" + "babel-core": "^4.7.16", + "expect.js": "^0.3.1", + "mkdirp": "^0.5.0", + "mocha": "^2.2.1", + "object-assign": "^2.0.0", + "rimraf": "^2.3.2", + "should": "^5.2.0", + "webpack": "^1.7.3" }, "scripts": { "test": "webpack-dev-server --config=test/webpack.config.js", diff --git a/test/cache.test.js b/test/cache.test.js new file mode 100644 index 00000000..fe1a4436 --- /dev/null +++ b/test/cache.test.js @@ -0,0 +1,128 @@ +var fs = require('fs'), + path = require('path'), + assign = require('object-assign'), + expect = require('expect.js'), + mkdirp = require('mkdirp'), + rimraf = require('rimraf'), + webpack = require('webpack'); + +describe('Filesystem Cache', function () { + + var cacheDir = path.resolve(__dirname, 'output/cache'), + outputDir = path.resolve(__dirname, './output'), + babelLoader = path.resolve(__dirname, '../'), + + globalConfig = { + entry: './test/fixtures/basic.js', + output: { + path: outputDir, + filename: '[id].cache.js' + }, + module: { + loaders: [ + { + test: /\.jsx?/, + loader: babelLoader, + exclude: /node_modules/ + } + ] + } + }; + + // Clean generated cache files before each test + // so that we can call each test with an empty state. + beforeEach(function (done) { + rimraf(outputDir, function (err) { + if (err) { return done(err); } + mkdirp(cacheDir, done); + }); + }); + + it('should output files to cache directory', function (done) { + + var config = assign({}, globalConfig, { + module: { + loaders: [{ + test: /\.jsx?/, + loader: babelLoader + '?cacheDirectory=' + cacheDir, + exclude: /node_modules/ + }] + } + }); + + webpack(config, function (err, stats) { + expect(err).to.be(null); + + fs.readdir(cacheDir, function (err, files) { + expect(err).to.be(null); + expect(files).to.not.be.empty(); + done(); + }); + }); + }); + + it('should have one file per module', function (done) { + var config = assign({}, globalConfig, { + module: { + loaders: [{ + test: /\.jsx?/, + loader: babelLoader + '?cacheDirectory=' + cacheDir, + exclude: /node_modules/ + }] + } + }); + + webpack(config, function (err, stats) { + expect(err).to.be(null); + + fs.readdir(cacheDir, function (err, files) { + expect(err).to.be(null); + expect(files).to.have.length(3); + done(); + }); + }); + + }); + + + it('should generate a new file if the identifier changes', function (done) { + + var configs = [ + assign({},globalConfig, { + module: { + loaders: [{ + test: /\.jsx?/, + loader: babelLoader + '?cacheDirectory=' + cacheDir + '&cacheIdentifier=a', + exclude: /node_modules/ + }] + } + }), + assign({},globalConfig, { + module: { + loaders: [{ + test: /\.jsx?/, + loader: babelLoader + '?cacheDirectory=' + cacheDir + '&cacheIdentifier=b', + exclude: /node_modules/ + }] + } + }), + ], + counter = configs.length; + + configs.forEach(function (config) { + webpack(config, function (err, stats) { + expect(err).to.be(null); + counter -= 1; + + if (!counter) { + fs.readdir(cacheDir, function (err, files) { + expect(err).to.be(null); + expect(files).to.have.length(6); + done(); + }); + } + }); + }); + + }); +}); diff --git a/test/cache/webpack.config.js b/test/cache/webpack.config.js deleted file mode 100644 index 7ffa5086..00000000 --- a/test/cache/webpack.config.js +++ /dev/null @@ -1,19 +0,0 @@ -var path = require('path'); - -// Just run "webpack-dev-server" -module.exports = { - context: __dirname, - entry: '../fixtures/basic.js', - output: { - path: path.resolve(__dirname, '../output'), - filename: 'bundle.cache.js' - }, - module: { - loaders: [ - { - test: '\.js', - loader: 'babel?cacheDirectory=' + path.resolve(__dirname, '../output/cache') - } - ] - } -}; diff --git a/test/fixtures/basic.js b/test/fixtures/basic.js index 9aac6e2f..3fdbb5cc 100644 --- a/test/fixtures/basic.js +++ b/test/fixtures/basic.js @@ -1,4 +1,6 @@ -import test from '../../!./test.js'; +/*jshint esnext:true*/ + +import test from './import.js'; class App { constructor(arg='test') { diff --git a/test/fixtures/constant.js b/test/fixtures/constant.js new file mode 100644 index 00000000..5aac8576 --- /dev/null +++ b/test/fixtures/constant.js @@ -0,0 +1 @@ +const LOADER = true; diff --git a/test/fixtures/import.js b/test/fixtures/import.js new file mode 100644 index 00000000..efbb72c9 --- /dev/null +++ b/test/fixtures/import.js @@ -0,0 +1,7 @@ +/*jshint esnext:true*/ + +import loader from './constant.js'; + +var test = loader; + +export default test; diff --git a/test/fixtures/test.js b/test/fixtures/test.js deleted file mode 100644 index 1b1543fa..00000000 --- a/test/fixtures/test.js +++ /dev/null @@ -1,3 +0,0 @@ -var test = 'test'; - -export default test; From 110a0fa1ffb1bca10dcc3d3e6b34aa553d912f0e Mon Sep 17 00:00:00 2001 From: Couto Date: Sat, 28 Mar 2015 21:46:27 +0000 Subject: [PATCH 04/20] Add coverage to help with testing. * Add test to check if cached files are being read. * Add example to docs --- .gitignore | 1 + lib/fs-cache.js | 18 ++++++++++++++++++ package.json | 1 + test/cache.test.js | 28 ++++++++++++++++++++++++++++ 4 files changed, 48 insertions(+) diff --git a/.gitignore b/.gitignore index 67972574..64006860 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ node_modules test/output +coverage diff --git a/lib/fs-cache.js b/lib/fs-cache.js index 0cefeef0..b3b2e79e 100644 --- a/lib/fs-cache.js +++ b/lib/fs-cache.js @@ -98,6 +98,24 @@ var filename = function (source, identifier, options) { * file and whose result will be cached * * @param {Function} callback + * + * @example + * + * cache({ + * directory: '.tmp/cache', + * identifier: 'babel-loader-cachefile', + * source: *source code from file*, + * options: { + * experimental: true, + * runtime: true + * }, + * transform: function (source, options) { + * var content = *do what you need with the source* + * return content; + * } + * }, function (err, result) { + * + * }); */ var cache = module.exports = function (params, callback) { // Spread params into named variables diff --git a/package.json b/package.json index dae6cc4a..ff4b4c92 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "devDependencies": { "babel-core": "^4.7.16", "expect.js": "^0.3.1", + "istanbul": "^0.3.11", "mkdirp": "^0.5.0", "mocha": "^2.2.1", "object-assign": "^2.0.0", diff --git a/test/cache.test.js b/test/cache.test.js index fe1a4436..e68e86f3 100644 --- a/test/cache.test.js +++ b/test/cache.test.js @@ -61,6 +61,34 @@ describe('Filesystem Cache', function () { }); }); + it('should read from cache directory if cached file exists', function (done) { + var config = assign({}, globalConfig, { + module: { + loaders: [{ + test: /\.jsx?/, + loader: babelLoader + '?cacheDirectory=' + cacheDir, + exclude: /node_modules/ + }] + } + }); + + // @TODO Find a way to know if the file as correctly read + // without relying on istanbul for coverage. + webpack(config, function (err, stats) { + expect(err).to.be(null); + + webpack(config, function (err, stats) { + expect(err).to.be(null); + fs.readdir(cacheDir, function (err, files) { + expect(err).to.be(null); + expect(files).to.not.be.empty(); + done(); + }); + }); + }); + + }); + it('should have one file per module', function (done) { var config = assign({}, globalConfig, { module: { From b98133fefe1aaa4713a72447f3f61277807f4735 Mon Sep 17 00:00:00 2001 From: Couto Date: Sat, 28 Mar 2015 21:53:24 +0000 Subject: [PATCH 05/20] Update depedencies. Add files to .gitignore --- .gitignore | 2 ++ package.json | 19 ++++++++++++------- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/.gitignore b/.gitignore index 3c3629e6..64006860 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ node_modules +test/output +coverage diff --git a/package.json b/package.json index 0f49fec7..96c6f5cf 100644 --- a/package.json +++ b/package.json @@ -4,20 +4,25 @@ "description": "babel module loader for webpack", "main": "index.js", "dependencies": { - "loader-utils": "^0.2.5" + "loader-utils": "^0.2.6" }, "peerDependencies": { "babel-core": "^4.7.0", - "webpack": "^1.4.5" + "webpack": "^1.7.3" }, "devDependencies": { - "mocha": "^2.0.1", - "mocha-loader": "^0.7.0", - "should": "^4.3.1", - "webpack-dev-server": "^1.6.6" + "babel-core": "^4.7.16", + "expect.js": "^0.3.1", + "istanbul": "^0.3.11", + "mkdirp": "^0.5.0", + "mocha": "^2.2.1", + "object-assign": "^2.0.0", + "rimraf": "^2.3.2", + "should": "^5.2.0", + "webpack": "^1.7.3" }, "scripts": { - "test": "webpack-dev-server --config=test/webpack.config.js" + "test": "istanbul cover ./node_modules/.bin/_mocha -- test/*.test.js" }, "repository": { "type": "git", From fff86e144a95154960f7dd7c3cfb611008447543 Mon Sep 17 00:00:00 2001 From: Couto Date: Sat, 28 Mar 2015 21:54:09 +0000 Subject: [PATCH 06/20] Remove parsing of booleans. --- index.js | 13 +------------ 1 file changed, 1 insertion(+), 12 deletions(-) diff --git a/index.js b/index.js index 33e4bc1f..9e361dc9 100644 --- a/index.js +++ b/index.js @@ -5,12 +5,7 @@ var loaderUtils = require('loader-utils'), path = require('path'), os = require('os'), zlib = require('zlib'), - version = require('./package').version, - toBoolean = function (val) { - if (val === 'true') { return true; } - if (val === 'false') { return false; } - return val; - }; + version = require('./package').version; module.exports = function (source, inputSourceMap) { @@ -22,12 +17,6 @@ module.exports = function (source, inputSourceMap) { this.cacheable(); } - // Convert 'true'/'false' to true/false - options = Object.keys(options).reduce(function (accumulator, key) { - accumulator[key] = toBoolean(options[key]); - return accumulator; - }, {}); - options.sourceMap = this.sourceMap; options.inputSourceMap = inputSourceMap; options.filename = loaderUtils.getRemainingRequest(this); From c6928d16a66d35188363eeed43e5adb0f4f1b479 Mon Sep 17 00:00:00 2001 From: Couto Date: Sat, 28 Mar 2015 22:47:23 +0000 Subject: [PATCH 07/20] Closes #46. Add support for babel global options. * Add tests to ensure priority. --- index.js | 31 +++++---- test/fixtures/basic.js | 2 +- test/fixtures/experimental.js | 18 +++++ test/options.test.js | 120 ++++++++++++++++++++++++++++++++++ 4 files changed, 154 insertions(+), 17 deletions(-) create mode 100644 test/fixtures/experimental.js create mode 100644 test/options.test.js diff --git a/index.js b/index.js index 9e361dc9..93b42637 100644 --- a/index.js +++ b/index.js @@ -1,33 +1,32 @@ -var loaderUtils = require('loader-utils'), - babel = require('babel-core'), - crypto = require('crypto'), +var crypto = require('crypto'), fs = require('fs'), - path = require('path'), os = require('os'), + path = require('path'), zlib = require('zlib'), + assign = require('object-assign'), + babel = require('babel-core'), + loaderUtils = require('loader-utils'), version = require('./package').version; module.exports = function (source, inputSourceMap) { - var options = loaderUtils.parseQuery(this.query), + var queryOptions = loaderUtils.parseQuery(this.query), callback = this.async(), - result, cacheDirectory; + options = assign({}, this.options.babel, queryOptions, { + sourceMap: this.sourceMap, + inputSourceMap: inputSourceMap, + filename: loaderUtils.getRemainingRequest(this), + }), + result; if (this.cacheable) { this.cacheable(); } - options.sourceMap = this.sourceMap; - options.inputSourceMap = inputSourceMap; - options.filename = loaderUtils.getRemainingRequest(this); - - cacheDirectory = options.cacheDirectory; - delete options.cacheDirectory; - - if (cacheDirectory === true) cacheDirectory = os.tmpdir(); + if (options.cacheDirectory === true) options.cacheDirectory = os.tmpdir(); - if (cacheDirectory){ - cachedTranspile(cacheDirectory, source, options, onResult); + if (options.cacheDirectory){ + cachedTranspile(options.cacheDirectory, source, options, onResult); } else { onResult(null, transpile(source, options)); } diff --git a/test/fixtures/basic.js b/test/fixtures/basic.js index 9aac6e2f..a806bfdb 100644 --- a/test/fixtures/basic.js +++ b/test/fixtures/basic.js @@ -1,4 +1,4 @@ -import test from '../../!./test.js'; +import test from './test.js'; class App { constructor(arg='test') { diff --git a/test/fixtures/experimental.js b/test/fixtures/experimental.js new file mode 100644 index 00000000..15d9d76c --- /dev/null +++ b/test/fixtures/experimental.js @@ -0,0 +1,18 @@ +/*jshint esnext:true*/ + +let { x, y, ...z } = { x: 1, y: 2, a: 3, b: 4 }; +let n = { x, y, ...z }; + +// Array comprehensions +var results = [ + for(c of customers) + if (c.city == "Seattle") + { name: c.name, age: c.age } +] + +// Generator comprehensions +var results = ( + for(c of customers) + if (c.city == "Seattle") + { name: c.name, age: c.age } +) diff --git a/test/options.test.js b/test/options.test.js new file mode 100644 index 00000000..776f399d --- /dev/null +++ b/test/options.test.js @@ -0,0 +1,120 @@ +var fs = require('fs'), + path = require('path'), + assign = require('object-assign'), + expect = require('expect.js'), + mkdirp = require('mkdirp'), + rimraf = require('rimraf'), + webpack = require('webpack'); + +describe('Options', function () { + + var outputDir = path.resolve(__dirname, './output'), + babelLoader = path.resolve(__dirname, '../'), + + globalConfig = { + entry: './test/fixtures/basic.js', + output: { + path: outputDir, + filename: '[id].options.js' + }, + module: { + loaders: [ + { + test: /\.jsx?/, + loader: babelLoader, + exclude: /node_modules/ + } + ] + } + }; + + // Clean generated cache files before each test + // so that we can call each test with an empty state. + beforeEach(function (done) { + rimraf(outputDir, function (err) { + if (err) { return done(err); } + mkdirp(outputDir, done); + }); + }); + + it('should interpret options given to the loader', function (done) { + + var config = assign({}, globalConfig, { + entry: './test/fixtures/experimental.js', + module: { + loaders: [{ + test: /\.jsx?/, + loader: babelLoader + '?experimental', + exclude: /node_modules/ + }] + } + }); + + webpack(config, function (err, stats) { + expect(err).to.be(null); + + fs.readdir(outputDir, function (err, files) { + expect(err).to.be(null); + expect(files).to.not.be.empty(); + + done(); + }); + }); + }); + + it('should interpret options given globally', function (done) { + + var config = assign({}, globalConfig, { + entry: './test/fixtures/experimental.js', + babel: { + experimental: true + }, + module: { + loaders: [{ + test: /\.jsx?/, + loader: babelLoader, + exclude: /node_modules/ + }] + } + }); + + webpack(config, function (err, stats) { + expect(err).to.be(null); + + fs.readdir(outputDir, function (err, files) { + expect(err).to.be(null); + expect(files).to.not.be.empty(); + + done(); + }); + }); + }); + + it('should give priority to loader options', function (done) { + var config = assign({}, globalConfig, { + entry: './test/fixtures/experimental.js', + babel: { + experimental: false + }, + module: { + loaders: [{ + test: /\.jsx?/, + loader: babelLoader + '?experimental', + exclude: /node_modules/ + }] + } + }); + + webpack(config, function (err, stats) { + expect(err).to.be(null); + + fs.readdir(outputDir, function (err, files) { + expect(err).to.be(null); + expect(files).to.not.be.empty(); + + done(); + }); + }); + }); + +}); From ffaae61346386d9e541b52954f56f5f0ed87ec35 Mon Sep 17 00:00:00 2001 From: Couto Date: Sat, 28 Mar 2015 23:44:05 +0000 Subject: [PATCH 08/20] [WIP] Start work with sourcemaps. * Let webpack devtool define the output. * Add test for source-maps. --- index.js | 19 ++++++++--- test/sourcemaps.test.js | 76 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 90 insertions(+), 5 deletions(-) create mode 100644 test/sourcemaps.test.js diff --git a/index.js b/index.js index 93b42637..3137d115 100644 --- a/index.js +++ b/index.js @@ -13,22 +13,29 @@ module.exports = function (source, inputSourceMap) { var queryOptions = loaderUtils.parseQuery(this.query), callback = this.async(), options = assign({}, this.options.babel, queryOptions, { - sourceMap: this.sourceMap, inputSourceMap: inputSourceMap, filename: loaderUtils.getRemainingRequest(this), }), result; - if (this.cacheable) { - this.cacheable(); + + this.cacheable(); + + + if (!options.sourceMap) { + options.sourceMap = this.sourceMap; } if (options.cacheDirectory === true) options.cacheDirectory = os.tmpdir(); if (options.cacheDirectory){ - cachedTranspile(options.cacheDirectory, source, options, onResult); + cachedTranspile(options.cacheDirectory, source, options, function (err, result) { + if (err) { throw err; } + callback(null, result.code, result.map); + }); } else { - onResult(null, transpile(source, options)); + result = transpile(source, options); + callback(null, result.code, result.map); } function onResult(err, result){ @@ -39,10 +46,12 @@ module.exports = function (source, inputSourceMap) { }; function transpile(source, options){ + var result = babel.transform(source, options); var code = result.code; var map = result.map; + if (map) { map.sourcesContent = [source]; } diff --git a/test/sourcemaps.test.js b/test/sourcemaps.test.js new file mode 100644 index 00000000..f6f44a06 --- /dev/null +++ b/test/sourcemaps.test.js @@ -0,0 +1,76 @@ +var fs = require('fs'), + path = require('path'), + assign = require('object-assign'), + expect = require('expect.js'), + mkdirp = require('mkdirp'), + rimraf = require('rimraf'), + webpack = require('webpack'); + +describe('Sourcemaps', function () { + + var outputDir = path.resolve(__dirname, './output'), + babelLoader = path.resolve(__dirname, '../'), + + globalConfig = { + entry: './test/fixtures/basic.js', + output: { + path: outputDir, + filename: '[id].options.js' + }, + module: { + loaders: [ + { + test: /\.jsx?/, + loader: babelLoader, + exclude: /node_modules/ + } + ] + } + }; + + // Clean generated cache files before each test + // so that we can call each test with an empty state. + beforeEach(function (done) { + rimraf(outputDir, function (err) { + if (err) { return done(err); } + mkdirp(outputDir, done); + }); + }); + + it('should output webpack\'s sourcemap', function (done) { + + var config = assign({}, globalConfig, { + devtool: 'source-map', + entry: './test/fixtures/basic.js', + module: { + loaders: [{ + test: /\.jsx?/, + loader: babelLoader, + exclude: /node_modules/ + }] + } + }); + + webpack(config, function (err, stats) { + expect(err).to.be(null); + + fs.readdir(outputDir, function (err, files) { + expect(err).to.be(null); + + var map = files.filter(function (file) { + return (file.indexOf('.map') !== -1); + }); + + expect(map).to.not.be.empty(); + + fs.readFile(path.resolve(outputDir, map[0]), function (err, data) { + expect(err).to.be(null); + expect(data.toString().indexOf('webpack:///')).to.not.equal(-1); + done(); + }); + + }); + }); + }); + +}); From 6d41ed412dcfcc796164400cbe1b79fccf9a7d3c Mon Sep 17 00:00:00 2001 From: Couto Date: Sun, 29 Mar 2015 19:58:32 +0100 Subject: [PATCH 09/20] Fix merge from develop. --- index.js | 35 +++++++++-------------------- test/{basic.test.js => basic.js} | 0 test/cache.test.js | 4 ++-- test/options.test.js | 2 +- test/sourcemaps.test.js | 38 +++++++++++++++++++++++++++++++- 5 files changed, 51 insertions(+), 28 deletions(-) rename test/{basic.test.js => basic.js} (100%) diff --git a/index.js b/index.js index 8c330745..a3371689 100644 --- a/index.js +++ b/index.js @@ -1,45 +1,32 @@ -var loaderUtils = require('loader-utils'), - pkg = require('./package.json'), +var assign = require('object-assign'), babel = require('babel-core'), cache = require('./lib/fs-cache.js'), - toBoolean = function (val) { - if (val === 'true') { return true; } - if (val === 'false') { return false; } - return val; - }; + loaderUtils = require('loader-utils'), + pkg = require('./package.json'); module.exports = function (source, inputSourceMap) { - var options = loaderUtils.parseQuery(this.query), + var queryOptions = loaderUtils.parseQuery(this.query), callback = this.async(), - options = assign({}, this.options.babel, queryOptions, { + options = assign({ inputSourceMap: inputSourceMap, filename: loaderUtils.getRemainingRequest(this), - }), + cacheIdentifier: JSON.stringify({ + 'babel-loader': pkg.version, + 'babel-core': babel.version + }) + }, this.options.babel, queryOptions), result; this.cacheable(); - if (!options.sourceMap) { options.sourceMap = this.sourceMap; } - // Convert 'true'/'false' to true/false - options = Object.keys(options).reduce(function (accumulator, key) { - accumulator[key] = toBoolean(options[key]); - return accumulator; - }, {}); - - options.sourceMap = this.sourceMap; - options.inputSourceMap = inputSourceMap; - options.filename = loaderUtils.getRemainingRequest(this); cacheDirectory = options.cacheDirectory; - cacheIdentifier = options.cacheIdentifier || JSON.stringify({ - 'babel-loader': pkg.version, - 'babel-core': babel.version - }); + cacheIdentifier = options.cacheIdentifier; delete options.cacheDirectory; delete options.cacheIdentifier; diff --git a/test/basic.test.js b/test/basic.js similarity index 100% rename from test/basic.test.js rename to test/basic.js diff --git a/test/cache.test.js b/test/cache.test.js index e68e86f3..0d4d494a 100644 --- a/test/cache.test.js +++ b/test/cache.test.js @@ -8,8 +8,8 @@ var fs = require('fs'), describe('Filesystem Cache', function () { - var cacheDir = path.resolve(__dirname, 'output/cache'), - outputDir = path.resolve(__dirname, './output'), + var cacheDir = path.resolve(__dirname, 'output/cache/cachefiles'), + outputDir = path.resolve(__dirname, './output/cache/'), babelLoader = path.resolve(__dirname, '../'), globalConfig = { diff --git a/test/options.test.js b/test/options.test.js index 776f399d..1ad69f9a 100644 --- a/test/options.test.js +++ b/test/options.test.js @@ -8,7 +8,7 @@ var fs = require('fs'), describe('Options', function () { - var outputDir = path.resolve(__dirname, './output'), + var outputDir = path.resolve(__dirname, './output/options'), babelLoader = path.resolve(__dirname, '../'), globalConfig = { diff --git a/test/sourcemaps.test.js b/test/sourcemaps.test.js index f6f44a06..7c2b4209 100644 --- a/test/sourcemaps.test.js +++ b/test/sourcemaps.test.js @@ -8,7 +8,7 @@ var fs = require('fs'), describe('Sourcemaps', function () { - var outputDir = path.resolve(__dirname, './output'), + var outputDir = path.resolve(__dirname, './output/sourcemaps'), babelLoader = path.resolve(__dirname, '../'), globalConfig = { @@ -73,4 +73,40 @@ describe('Sourcemaps', function () { }); }); + it('should output webpack\'s sourcemap', function (done) { + + var config = assign({}, globalConfig, { + devtool: 'source-map', + entry: './test/fixtures/basic.js', + module: { + loaders: [{ + test: /\.jsx?/, + loader: babelLoader, + exclude: /node_modules/ + }] + } + }); + + webpack(config, function (err, stats) { + expect(err).to.be(null); + + fs.readdir(outputDir, function (err, files) { + expect(err).to.be(null); + + var map = files.filter(function (file) { + return (file.indexOf('.map') !== -1); + }); + + expect(map).to.not.be.empty(); + + fs.readFile(path.resolve(outputDir, map[0]), function (err, data) { + expect(err).to.be(null); + expect(data.toString().indexOf('webpack:///')).to.not.equal(-1); + done(); + }); + + }); + }); + }); + }); From 9957d18e16ac99ecc7fa86578dda00092c4bc69a Mon Sep 17 00:00:00 2001 From: Couto Date: Mon, 30 Mar 2015 00:44:14 +0100 Subject: [PATCH 10/20] [WIP] Add test to output babel sourcemap --- index.js | 4 ++-- test/sourcemaps.test.js | 9 ++++++--- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/index.js b/index.js index a3371689..f75bd4bd 100644 --- a/index.js +++ b/index.js @@ -5,8 +5,8 @@ var assign = require('object-assign'), pkg = require('./package.json'); module.exports = function (source, inputSourceMap) { - var queryOptions = loaderUtils.parseQuery(this.query), - callback = this.async(), + var callback = this.async(), + queryOptions = loaderUtils.parseQuery(this.query), options = assign({ inputSourceMap: inputSourceMap, filename: loaderUtils.getRemainingRequest(this), diff --git a/test/sourcemaps.test.js b/test/sourcemaps.test.js index 7c2b4209..2a010037 100644 --- a/test/sourcemaps.test.js +++ b/test/sourcemaps.test.js @@ -73,11 +73,14 @@ describe('Sourcemaps', function () { }); }); - it('should output webpack\'s sourcemap', function (done) { + it.only('should output babel\'s sourcemap', function (done) { var config = assign({}, globalConfig, { - devtool: 'source-map', entry: './test/fixtures/basic.js', + babel: { + sourceMap: 'inline', + sourceMapName: './output/sourcemaps/babel.map' + }, module: { loaders: [{ test: /\.jsx?/, @@ -101,7 +104,7 @@ describe('Sourcemaps', function () { fs.readFile(path.resolve(outputDir, map[0]), function (err, data) { expect(err).to.be(null); - expect(data.toString().indexOf('webpack:///')).to.not.equal(-1); + expect(data.toString().indexOf('webpack:///')).to.equal(-1); done(); }); From 786e4b99ee136acddf8c9ea05890c4ae350e16b7 Mon Sep 17 00:00:00 2001 From: Couto Date: Fri, 3 Apr 2015 15:57:46 +0100 Subject: [PATCH 11/20] Update dependencies. --- package.json | 5 ++--- test/basic.js | 11 ----------- test/sourcemaps.test.js | 4 ++-- 3 files changed, 4 insertions(+), 16 deletions(-) delete mode 100644 test/basic.js diff --git a/package.json b/package.json index 0b59f89f..da694572 100644 --- a/package.json +++ b/package.json @@ -11,14 +11,13 @@ "webpack": "*" }, "devDependencies": { - "babel-core": "^4.7.16", + "babel-core": "^5.0.6", "expect.js": "^0.3.1", - "istanbul": "^0.3.11", + "istanbul": "^0.3.13", "mkdirp": "^0.5.0", "mocha": "^2.2.1", "object-assign": "^2.0.0", "rimraf": "^2.3.2", - "should": "^5.2.0", "webpack": "^1.7.3" }, "scripts": { diff --git a/test/basic.js b/test/basic.js deleted file mode 100644 index f845065f..00000000 --- a/test/basic.js +++ /dev/null @@ -1,11 +0,0 @@ -var should = require('should'); - -describe('basic', function () { - it('should compile a es6 module', function () { - var App = require('../!./fixtures/basic.js').default, - result = new App().result; - - result.should.be.type('string'); - result.should.equal('testtest'); - }); -}); diff --git a/test/sourcemaps.test.js b/test/sourcemaps.test.js index 2a010037..85a9a530 100644 --- a/test/sourcemaps.test.js +++ b/test/sourcemaps.test.js @@ -73,12 +73,12 @@ describe('Sourcemaps', function () { }); }); - it.only('should output babel\'s sourcemap', function (done) { + it.skip('should output babel\'s sourcemap', function (done) { var config = assign({}, globalConfig, { entry: './test/fixtures/basic.js', babel: { - sourceMap: 'inline', + sourceMap: true, sourceMapName: './output/sourcemaps/babel.map' }, module: { From d898529dcaf5371ab306c209c43b21e75f8b044f Mon Sep 17 00:00:00 2001 From: Couto Date: Fri, 3 Apr 2015 16:31:19 +0100 Subject: [PATCH 12/20] Update test options to support babel 5 --- package.json | 2 +- test/options.test.js | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package.json b/package.json index 354f8ef6..02e367d8 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,7 @@ "main": "index.js", "dependencies": { "babel-core": "^5.0.0", + "object-assign": "^2.0.0", "loader-utils": "^0.2.6" }, "peerDependencies": { @@ -17,7 +18,6 @@ "istanbul": "^0.3.13", "mkdirp": "^0.5.0", "mocha": "^2.2.1", - "object-assign": "^2.0.0", "rimraf": "^2.3.2", "webpack": "^1.7.3" }, diff --git a/test/options.test.js b/test/options.test.js index 1ad69f9a..97e5c292 100644 --- a/test/options.test.js +++ b/test/options.test.js @@ -44,7 +44,7 @@ describe('Options', function () { module: { loaders: [{ test: /\.jsx?/, - loader: babelLoader + '?experimental', + loader: babelLoader + '?stage=0', exclude: /node_modules/ }] } @@ -67,7 +67,7 @@ describe('Options', function () { var config = assign({}, globalConfig, { entry: './test/fixtures/experimental.js', babel: { - experimental: true + stage: 0 }, module: { loaders: [{ @@ -94,12 +94,12 @@ describe('Options', function () { var config = assign({}, globalConfig, { entry: './test/fixtures/experimental.js', babel: { - experimental: false + stage: 4 }, module: { loaders: [{ test: /\.jsx?/, - loader: babelLoader + '?experimental', + loader: babelLoader + '?stage=0', exclude: /node_modules/ }] } From 3fdbf8e98a8e4b59b9b8227db4fb104e5ea1cfa3 Mon Sep 17 00:00:00 2001 From: Couto Date: Fri, 3 Apr 2015 18:21:24 +0100 Subject: [PATCH 13/20] Fix CS. Update README.md. --- .editorconfig | 14 +++++ .jscsrc | 7 +++ CONTRIBUTING.md | 17 ++++++ LICENSE | 22 +++++++ README.md | 136 ++++++++++++++++++++++++++------------------ index.js | 123 ++++++++++++++++++++-------------------- lib/fs-cache.js | 148 +++++++++++++++++++++++------------------------- 7 files changed, 273 insertions(+), 194 deletions(-) create mode 100644 .editorconfig create mode 100644 .jscsrc create mode 100644 CONTRIBUTING.md create mode 100644 LICENSE diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 00000000..02a1ffbc --- /dev/null +++ b/.editorconfig @@ -0,0 +1,14 @@ +# top-most EditorConfig file +root = true + +# Unix-style newlines with a newline ending every file +[*] +charset = utf-8 +end_of_line = lf +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.jscsrc b/.jscsrc new file mode 100644 index 00000000..cb0fd846 --- /dev/null +++ b/.jscsrc @@ -0,0 +1,7 @@ +{ + "preset": "node-style-guide", + "fileExtensions": [ ".js", "jscs" ], + "excludeFiles": [ + "node_modules/**" + ] +} diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 00000000..9bffa971 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,17 @@ +# Contributing + + 1. Fork it! + 2. Create your feature branch: `git checkout -b my-new-feature` + 3. Commit your changes: `git commit -am 'Add some feature'` + 4. Push to the branch: `git push origin my-new-feature` + 5. Submit a pull request :D + +# Code Standards + + I'm not too strict with coding styles. + + While personally I'm using the [node-style-guide](https://github.com/felixge/node-style-guide), as long you don't to something too weird or fancy, that's probably ok. + + If, however, you want to ensure that you're following the node style guide, you can use [JSCS](https://github.com/jscs-dev/node-jscs). The rules are already set on the [.jscsrc](https://github.com/babel/babel-loader/blob/master/.jscsrc) file and there's most likely some [package](http://jscs.info/overview.html#friendly-packages) to your editor already. + + Documentation, wether in the state of JavaDoc or simple line comments are always welcome. diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..29e3021e --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2014-2015 Luís Couto + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 6105f17b..98c5b8c6 100644 --- a/README.md +++ b/README.md @@ -1,90 +1,116 @@ # babel-loader + > Babel is a compiler for writing next generation JavaScript. -> Turn ES6 code into vanilla ES5 with no runtime required using [babel](https://github.com/babel/babel); + This package allows the use babel with [webpack](https://github.com/webpack/webpack) -## Install + __Notes:__ Issues with the output should be reported on the babel [issue tracker](https://github.com/babel/babel/issues); +## Installation + You should install [webpack]() and [babel-core]() to use this loader +```bash +npm install babel-core --save ``` -$ npm install --save-dev babel-loader +```bash +npm install webpack babel-loader --save-dev ``` -## Usage +__Note:__ [npm](https://npmjs.com) will deprecate [peerDependencies](https://github.com/npm/npm/issues/6565) on the next major release, so required dependencies like babel-core and webpack will have to be installed manually. -```javascript -import Animal from 'babel!./Animal.js'; +## Usage + Within your webpack configuration object, you'll need to add the babel-loader to the list of modules, like so: -class Person extends Animal { - constructor(arg='default') { - this.eat = 'Happy Meal'; - } + ```javascript +module: { + loaders: [ + { + test: /\.jsx?$/, + exclude: /(node_modules|bower_components)/, + loader: 'babel' + } + ] } + ``` -export default Person; -``` +### Options -```javascript -var Person = require('babel!./Person.js').default; -new Person(); -``` +See the `babel` [options](http://babeljs.io/docs/usage/options/). -Or within the webpack config: +You can pass options to the loader by writting them as a [query string](https://github.com/webpack/loader-utils): -```javascript + ```javascript module: { - loaders: [ - { test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'} - ] + loaders: [ + { + test: /\.jsx?$/, + exclude: /(node_modules|bower_components)/, + loader: 'babel?optional[]=runtime&stage=0' + } + ] } -``` + ``` -and then import normally: + or in a less used format, you can set an object in the webpack config. -```javascript -import Person from './Person.js'; -``` + ```javascript +babel: { + optional: ['runtime'], + stage: 0 +}, +module: { + loaders: [ + { + test: /\.jsx?$/, + exclude: /(node_modules|bower_components)/, + loader: 'babel' + } + ] +} + ``` -## Troubleshooting + __Note:__ options given directly to the loader take precedence in relation to the *global* object. -#### babel-loader is slow! + This loader also supports the following loader-specific option: -Make sure you are transforming as few files as possible. Because you are probably -matching `/\.js$/`, you might be transforming the `node_modules` folder or other unwanted -source. See the `exclude` option in the `loaders` config as documented above. + * `cacheDirectory`: When set, the given directory will be used to cache the results of the loader. Future webpack builds will attempt to read from the cache to avoid needing to run the potentially expensive Babel recompilation process on each run. A value of `true` will cause the loader to use the default OS temporary file directory. -#### babel is injecting helpers into each file and bloating my code! + * `cacheIdentifier`: When set, it will add the given identifier to the cached files. This can be used to force cache busting if the identifier changes. By default the identifier is made by using the babel-core's version and the babel-loader's version. -babel uses very small helpers for common functions such as `_extend`. By default -this will be added to every file that requires it. -You can instead require the babel runtime as a separate module to avoid the duplication. + __Note:__ The `sourceMap` option is ignored, instead sourceMaps are automatically enabled when webpack is configured to use them (via the `devtool` config option). -The following configuration disables automatic per-file runtime injection in babel, instead -requiring `babel-runtime` and making all helper references use it. +## Troubleshooting -See the [docs](https://babeljs.io/docs/usage/runtime) for more information. +### babel-loader is slow! -**NOTE:** You must run `npm install babel-runtime --save` to include this in your project. + Make sure you are transforming as few files as possible. Because you are probably + matching `/\.js$/`, you might be transforming the `node_modules` folder or other unwanted + source. -```javascript -loaders: [ - // the optional 'runtime' transformer tells babel to require the runtime instead of inlining it. - { test: /\.jsx?$/, exclude: /node_modules/, loader: 'babel-loader?optional=runtime' } -] -``` + See the `exclude` option in the `loaders` config as documented above. -## Options +### babel is injecting helpers into each file and bloating my code! -See the `babel` [options](http://babeljs.io/docs/usage/options/) + babel uses very small helpers for common functions such as `_extend`. By default + this will be added to every file that requires it. -This loader also supports the following loader-specific option: + You can instead require the babel runtime as a separate module to avoid the duplication. -* `cacheDirectory`: When set, the given directory will be used to cache the results of the loader. - Future webpack builds will attempt to read from the cache to avoid needing to run the potentially - expensive Babel recompilation process on each run. A value of `true` will cause the loader to - use the default OS temporary file directory. + The following configuration disables automatic per-file runtime injection in babel, instead + requiring `babel-runtime` and making all helper references use it. -Note: The `sourceMap` option is ignored, instead sourceMaps are automatically enabled when webpack is configured to use them (via the `devtool` config option). + See the [docs](https://babeljs.io/docs/usage/runtime) for more information. -## License + **NOTE:** You must run `npm install babel-runtime --save` to include this in your project. -MIT © Luis Couto +```javascript +loaders: [ + // the optional 'runtime' transformer tells babel to require the runtime + // instead of inlining it. + { + test: /\.jsx?$/, + exclude: /(node_modules|bower_components)/, + loader: 'babel-loader?optional[]=runtime' + } +] +``` +## [License](http://couto.mit-license.org/) diff --git a/index.js b/index.js index f75bd4bd..e12a1b2b 100644 --- a/index.js +++ b/index.js @@ -1,65 +1,62 @@ -var assign = require('object-assign'), - babel = require('babel-core'), - cache = require('./lib/fs-cache.js'), - loaderUtils = require('loader-utils'), - pkg = require('./package.json'); - -module.exports = function (source, inputSourceMap) { - var callback = this.async(), - queryOptions = loaderUtils.parseQuery(this.query), - options = assign({ - inputSourceMap: inputSourceMap, - filename: loaderUtils.getRemainingRequest(this), - cacheIdentifier: JSON.stringify({ - 'babel-loader': pkg.version, - 'babel-core': babel.version - }) - }, this.options.babel, queryOptions), - result; - - - this.cacheable(); - - if (!options.sourceMap) { - options.sourceMap = this.sourceMap; - } - - - cacheDirectory = options.cacheDirectory; - cacheIdentifier = options.cacheIdentifier; - - delete options.cacheDirectory; - delete options.cacheIdentifier; - - if (cacheDirectory){ - cache({ - directory: cacheDirectory, - identifier: cacheIdentifier, - source: source, - options: options, - transform: transpile, - }, function (err, result) { - callback(err, result.code, result.map); - }); - } else { - result = transpile(source, options); - callback(null, result.code, result.map); - } +var assign = require('object-assign'); +var babel = require('babel-core'); +var cache = require('./lib/fs-cache.js'); +var loaderUtils = require('loader-utils'); +var pkg = require('./package.json'); + +var transpile = function(source, options) { + var result = babel.transform(source, options); + var code = result.code; + var map = result.map; + + if (map) { + map.sourcesContent = [source]; + } + + return { + code: code, + map: map, + }; }; -function transpile(source, options){ - - var result = babel.transform(source, options); - - var code = result.code; - var map = result.map; - - if (map) { - map.sourcesContent = [source]; - } - - return { - code: code, - map: map - }; -} +module.exports = function(source, inputSourceMap) { + var callback = this.async(); + + // Join the different options sources into a final options object + var options = assign({ + inputSourceMap: inputSourceMap, + filename: loaderUtils.getRemainingRequest(this), + cacheIdentifier: JSON.stringify({ + 'babel-loader': pkg.version, + 'babel-core': babel.version, + }), + }, this.options.babel, loaderUtils.parseQuery(this.query)); + var result; + + this.cacheable(); + + if (!options.sourceMap) { + options.sourceMap = this.sourceMap; + } + + cacheDirectory = options.cacheDirectory; + cacheIdentifier = options.cacheIdentifier; + + delete options.cacheDirectory; + delete options.cacheIdentifier; + + if (cacheDirectory) { + cache({ + directory: cacheDirectory, + identifier: cacheIdentifier, + source: source, + options: options, + transform: transpile, + }, function(err, result) { + callback(err, result.code, result.map); + }); + } else { + result = transpile(source, options); + callback(null, result.code, result.map); + } +}; diff --git a/lib/fs-cache.js b/lib/fs-cache.js index b3b2e79e..011f6611 100644 --- a/lib/fs-cache.js +++ b/lib/fs-cache.js @@ -7,11 +7,11 @@ * @see https://github.com/babel/babel-loader/issues/34 * @see https://github.com/babel/babel-loader/pull/41 */ -var crypto = require('crypto'), - fs = require('fs'), - os = require('os'), - path = require('path'), - zlib = require('zlib'); +var crypto = require('crypto'); +var fs = require('fs'); +var os = require('os'); +var path = require('path'); +var zlib = require('zlib'); /** * read @@ -22,24 +22,24 @@ var crypto = require('crypto'), * @params {String} filename * @params {Function} callback */ -var read = function (filename, callback) { - fs.readFile(filename, function (err, data) { - if (err) { return callback(err); } +var read = function(filename, callback) { + fs.readFile(filename, function(err, data) { + if (err) { return callback(err); } - zlib.gunzip(data, function (err, content) { - var result = {}; + zlib.gunzip(data, function(err, content) { + var result = {}; - if (err) { return callback(err); } + if (err) { return callback(err); } - try { - result = JSON.parse(content); - } catch (e) { - return callback(e); - } + try { + result = JSON.parse(content); + } catch (e) { + return callback(e); + } - return callback(null, content); - }); + return callback(null, content); }); + }); }; @@ -53,14 +53,14 @@ var read = function (filename, callback) { * @params {String} result * @params {Function} callback */ -var write = function (filename, result, callback) { - var content = JSON.stringify(result); +var write = function(filename, result, callback) { + var content = JSON.stringify(result); - zlib.gzip(content, function (err, data) { - if (err) { return callback(err); } + zlib.gzip(content, function(err, data) { + if (err) { return callback(err); } - fs.writeFile(filename, data, callback); - }); + fs.writeFile(filename, data, callback); + }); }; @@ -72,17 +72,17 @@ var write = function (filename, result, callback) { * * @return {String} */ -var filename = function (source, identifier, options) { - var hash = crypto.createHash('SHA1'), - contents = JSON.stringify({ - source: source, - options: options, - identifier: identifier - }); +var filename = function(source, identifier, options) { + var hash = crypto.createHash('SHA1'); + var contents = JSON.stringify({ + source: source, + options: options, + identifier: identifier, + }); - hash.end(contents); + hash.end(contents); - return hash.read().toString('hex') + '.json.gzip'; + return hash.read().toString('hex') + '.json.gzip'; }; /** @@ -92,56 +92,52 @@ var filename = function (source, identifier, options) { * @param {Object} params * @param {String} params.directory Directory where cached files will be stored * @param {String} params.identifier Unique identifier to help with cache busting - * @param {String} params.source Original contents of the file to be cached - * @param {Object} params.options Options to be given to the transform function + * @param {String} params.source Original contents of the file to be cached + * @param {Object} params.options Options to be given to the transform function * @param {Function} params.transform Function that will transform the original - * file and whose result will be cached + * file and whose result will be cached * * @param {Function} callback * * @example * - * cache({ - * directory: '.tmp/cache', - * identifier: 'babel-loader-cachefile', - * source: *source code from file*, - * options: { - * experimental: true, - * runtime: true - * }, - * transform: function (source, options) { - * var content = *do what you need with the source* - * return content; - * } - * }, function (err, result) { + * cache({ + * directory: '.tmp/cache', + * identifier: 'babel-loader-cachefile', + * source: *source code from file*, + * options: { + * experimental: true, + * runtime: true + * }, + * transform: function(source, options) { + * var content = *do what you need with the source* + * return content; + * } + * }, function(err, result) { * - * }); + * }); */ -var cache = module.exports = function (params, callback) { - // Spread params into named variables - // Forgive user whenever possible - var source = params.source, - options = params.options || {}, - transform = params.transform, - identifier = params.identifier, // @TODO ensure that 'undefined' will not break - directory = (typeof params.directory === 'string') ? - params.directory : - os.tmpdir(); - - var file = path.join(directory, filename(source, identifier, options)); - - - read(file, function (err, content) { - var result = {}; - - if (!err) { return callback(null, content); } - - result = transform(source, options); - - return write(file, result, function (err) { - callback(err, result); - }); - +var cache = module.exports = function(params, callback) { + // Spread params into named variables + // Forgive user whenever possible + var source = params.source; + var options = params.options || {}; + var transform = params.transform; + var identifier = params.identifier; + var directory = (typeof params.directory === 'string') ? + params.directory : + os.tmpdir(); + var file = path.join(directory, filename(source, identifier, options)); + + read(file, function(err, content) { + var result = {}; + + if (!err) { return callback(null, content); } + + result = transform(source, options); + + return write(file, result, function(err) { + callback(err, result); }); - + }); }; From 4bde21916b58ead999e569d3e9d94f4672347a9a Mon Sep 17 00:00:00 2001 From: Couto Date: Fri, 3 Apr 2015 19:11:21 +0100 Subject: [PATCH 14/20] CS. Remove peerDependencies completely. --- index.js | 18 +-- package.json | 8 +- test/all.js | 1 - test/cache.test.js | 287 +++++++++++++++++++++------------------- test/options.test.js | 226 +++++++++++++++---------------- test/sourcemaps.test.js | 198 +++++++++++++-------------- test/webpack.config.js | 5 - 7 files changed, 375 insertions(+), 368 deletions(-) delete mode 100644 test/all.js delete mode 100644 test/webpack.config.js diff --git a/index.js b/index.js index e12a1b2b..3e7dd55d 100644 --- a/index.js +++ b/index.js @@ -21,21 +21,21 @@ var transpile = function(source, options) { module.exports = function(source, inputSourceMap) { var callback = this.async(); - - // Join the different options sources into a final options object - var options = assign({ + var result = {}; + // Handle options + var defaultOptions = { inputSourceMap: inputSourceMap, filename: loaderUtils.getRemainingRequest(this), cacheIdentifier: JSON.stringify({ 'babel-loader': pkg.version, 'babel-core': babel.version, }), - }, this.options.babel, loaderUtils.parseQuery(this.query)); - var result; - - this.cacheable(); + }; + var globalOptions = this.options.babel; + var loaderOptions = loaderUtils.parseQuery(this.query); + var options = assign({}, defaultOptions, globalOptions, loaderOptions); - if (!options.sourceMap) { + if (options.sourceMap === undefined) { options.sourceMap = this.sourceMap; } @@ -45,6 +45,8 @@ module.exports = function(source, inputSourceMap) { delete options.cacheDirectory; delete options.cacheIdentifier; + this.cacheable(); + if (cacheDirectory) { cache({ directory: cacheDirectory, diff --git a/package.json b/package.json index 02e367d8..3d9f476f 100644 --- a/package.json +++ b/package.json @@ -1,17 +1,13 @@ { "name": "babel-loader", - "version": "5.0.0", + "version": "5.1.0", "description": "babel module loader for webpack", "main": "index.js", "dependencies": { - "babel-core": "^5.0.0", + "babel-core": "5.0.0", "object-assign": "^2.0.0", "loader-utils": "^0.2.6" }, - "peerDependencies": { - "babel-core": "*", - "webpack": "*" - }, "devDependencies": { "babel-core": "^5.0.6", "expect.js": "^0.3.1", diff --git a/test/all.js b/test/all.js deleted file mode 100644 index 1301f3ae..00000000 --- a/test/all.js +++ /dev/null @@ -1 +0,0 @@ -require('./basic.test.js'); diff --git a/test/cache.test.js b/test/cache.test.js index 0d4d494a..91ef8555 100644 --- a/test/cache.test.js +++ b/test/cache.test.js @@ -1,156 +1,165 @@ -var fs = require('fs'), - path = require('path'), - assign = require('object-assign'), - expect = require('expect.js'), - mkdirp = require('mkdirp'), - rimraf = require('rimraf'), - webpack = require('webpack'); - -describe('Filesystem Cache', function () { - - var cacheDir = path.resolve(__dirname, 'output/cache/cachefiles'), - outputDir = path.resolve(__dirname, './output/cache/'), - babelLoader = path.resolve(__dirname, '../'), - - globalConfig = { - entry: './test/fixtures/basic.js', - output: { - path: outputDir, - filename: '[id].cache.js' - }, - module: { - loaders: [ - { - test: /\.jsx?/, - loader: babelLoader, - exclude: /node_modules/ - } - ] - } - }; - - // Clean generated cache files before each test - // so that we can call each test with an empty state. - beforeEach(function (done) { - rimraf(outputDir, function (err) { - if (err) { return done(err); } - mkdirp(cacheDir, done); - }); +var fs = require('fs'); +var path = require('path'); +var assign = require('object-assign'); +var expect = require('expect.js'); +var mkdirp = require('mkdirp'); +var rimraf = require('rimraf'); +var webpack = require('webpack'); + +describe('Filesystem Cache', function() { + + var cacheDir = path.resolve(__dirname, 'output/cache/cachefiles'); + var outputDir = path.resolve(__dirname, './output/cache/'); + var babelLoader = path.resolve(__dirname, '../'); + var globalConfig = { + entry: './test/fixtures/basic.js', + output: { + path: outputDir, + filename: '[id].cache.js', + }, + module: { + loaders: [ + { + test: /\.jsx?/, + loader: babelLoader, + exclude: /node_modules/, + }, + ], + }, + }; + + // Clean generated cache files before each test + // so that we can call each test with an empty state. + beforeEach(function(done) { + rimraf(outputDir, function(err) { + if (err) { return done(err); } + mkdirp(cacheDir, done); + }); + }); + + it('should output files to cache directory', function(done) { + + var config = assign({}, globalConfig, { + module: { + loaders: [ + { + test: /\.jsx?/, + loader: babelLoader + '?cacheDirectory=' + cacheDir, + exclude: /node_modules/, + }, + ], + }, }); - it('should output files to cache directory', function (done) { - - var config = assign({}, globalConfig, { - module: { - loaders: [{ - test: /\.jsx?/, - loader: babelLoader + '?cacheDirectory=' + cacheDir, - exclude: /node_modules/ - }] - } - }); + webpack(config, function(err, stats) { + expect(err).to.be(null); - webpack(config, function (err, stats) { - expect(err).to.be(null); + fs.readdir(cacheDir, function(err, files) { + expect(err).to.be(null); + expect(files).to.not.be.empty(); + done(); + }); + }); + }); + + it('should read from cache directory if cached file exists', function(done) { + var config = assign({}, globalConfig, { + module: { + loaders: [ + { + test: /\.jsx?/, + loader: babelLoader + '?cacheDirectory=' + cacheDir, + exclude: /node_modules/, + }, + ], + }, + }); - fs.readdir(cacheDir, function (err, files) { - expect(err).to.be(null); - expect(files).to.not.be.empty(); - done(); - }); + // @TODO Find a way to know if the file as correctly read without relying on + // Istanbul for coverage. + webpack(config, function(err, stats) { + expect(err).to.be(null); + + webpack(config, function(err, stats) { + expect(err).to.be(null); + fs.readdir(cacheDir, function(err, files) { + expect(err).to.be(null); + expect(files).to.not.be.empty(); + done(); }); + }); }); - it('should read from cache directory if cached file exists', function (done) { - var config = assign({}, globalConfig, { - module: { - loaders: [{ - test: /\.jsx?/, - loader: babelLoader + '?cacheDirectory=' + cacheDir, - exclude: /node_modules/ - }] - } - }); + }); + + it('should have one file per module', function(done) { + var config = assign({}, globalConfig, { + module: { + loaders: [ + { + test: /\.jsx?/, + loader: babelLoader + '?cacheDirectory=' + cacheDir, + exclude: /node_modules/, + }, + ], + }, + }); - // @TODO Find a way to know if the file as correctly read - // without relying on istanbul for coverage. - webpack(config, function (err, stats) { - expect(err).to.be(null); - - webpack(config, function (err, stats) { - expect(err).to.be(null); - fs.readdir(cacheDir, function (err, files) { - expect(err).to.be(null); - expect(files).to.not.be.empty(); - done(); - }); - }); - }); + webpack(config, function(err, stats) { + expect(err).to.be(null); + fs.readdir(cacheDir, function(err, files) { + expect(err).to.be(null); + expect(files).to.have.length(3); + done(); + }); }); - it('should have one file per module', function (done) { - var config = assign({}, globalConfig, { - module: { - loaders: [{ - test: /\.jsx?/, - loader: babelLoader + '?cacheDirectory=' + cacheDir, - exclude: /node_modules/ - }] - } - }); + }); - webpack(config, function (err, stats) { - expect(err).to.be(null); - fs.readdir(cacheDir, function (err, files) { - expect(err).to.be(null); - expect(files).to.have.length(3); - done(); - }); - }); + it('should generate a new file if the identifier changes', function(done) { + var configs = [ + assign({}, globalConfig, { + module: { + loaders: [ + { + test: /\.jsx?/, + loader: babelLoader + '?cacheDirectory=' + cacheDir + '&cacheIdentifier=a', + exclude: /node_modules/, + }, + ], + }, + }), + assign({}, globalConfig, { + module: { + loaders: [ + { + test: /\.jsx?/, + loader: babelLoader + '?cacheDirectory=' + cacheDir + '&cacheIdentifier=b', + exclude: /node_modules/, + }, + ], + }, + }), + ]; + var counter = configs.length; + + configs.forEach(function(config) { + webpack(config, function(err, stats) { + expect(err).to.be(null); + counter -= 1; + + if (!counter) { + fs.readdir(cacheDir, function(err, files) { + expect(err).to.be(null); + expect(files).to.have.length(6); + done(); + }); + } + }); }); - - it('should generate a new file if the identifier changes', function (done) { - - var configs = [ - assign({},globalConfig, { - module: { - loaders: [{ - test: /\.jsx?/, - loader: babelLoader + '?cacheDirectory=' + cacheDir + '&cacheIdentifier=a', - exclude: /node_modules/ - }] - } - }), - assign({},globalConfig, { - module: { - loaders: [{ - test: /\.jsx?/, - loader: babelLoader + '?cacheDirectory=' + cacheDir + '&cacheIdentifier=b', - exclude: /node_modules/ - }] - } - }), - ], - counter = configs.length; - - configs.forEach(function (config) { - webpack(config, function (err, stats) { - expect(err).to.be(null); - counter -= 1; - - if (!counter) { - fs.readdir(cacheDir, function (err, files) { - expect(err).to.be(null); - expect(files).to.have.length(6); - done(); - }); - } - }); - }); - - }); + }); }); diff --git a/test/options.test.js b/test/options.test.js index 97e5c292..255a5cb6 100644 --- a/test/options.test.js +++ b/test/options.test.js @@ -1,120 +1,124 @@ -var fs = require('fs'), - path = require('path'), - assign = require('object-assign'), - expect = require('expect.js'), - mkdirp = require('mkdirp'), - rimraf = require('rimraf'), - webpack = require('webpack'); - -describe('Options', function () { - - var outputDir = path.resolve(__dirname, './output/options'), - babelLoader = path.resolve(__dirname, '../'), - - globalConfig = { - entry: './test/fixtures/basic.js', - output: { - path: outputDir, - filename: '[id].options.js' - }, - module: { - loaders: [ - { - test: /\.jsx?/, - loader: babelLoader, - exclude: /node_modules/ - } - ] - } - }; - - // Clean generated cache files before each test - // so that we can call each test with an empty state. - beforeEach(function (done) { - rimraf(outputDir, function (err) { - if (err) { return done(err); } - mkdirp(outputDir, done); - }); +var fs = require('fs'); +var path = require('path'); +var assign = require('object-assign'); +var expect = require('expect.js'); +var mkdirp = require('mkdirp'); +var rimraf = require('rimraf'); +var webpack = require('webpack'); + +describe('Options', function() { + + var outputDir = path.resolve(__dirname, './output/options'); + var babelLoader = path.resolve(__dirname, '../'); + var globalConfig = { + entry: './test/fixtures/basic.js', + output: { + path: outputDir, + filename: '[id].options.js', + }, + module: { + loaders: [ + { + test: /\.jsx?/, + loader: babelLoader, + exclude: /node_modules/, + }, + ], + }, + }; + + // Clean generated cache files before each test + // so that we can call each test with an empty state. + beforeEach(function(done) { + rimraf(outputDir, function(err) { + if (err) { return done(err); } + mkdirp(outputDir, done); }); + }); + + it('should interpret options given to the loader', function(done) { + var config = assign({}, globalConfig, { + entry: './test/fixtures/experimental.js', + module: { + loaders: [ + { + test: /\.jsx?/, + loader: babelLoader + '?stage=0', + exclude: /node_modules/, + }, + ], + }, + }); + + webpack(config, function(err, stats) { + expect(err).to.be(null); + + fs.readdir(outputDir, function(err, files) { + expect(err).to.be(null); + expect(files).to.not.be.empty(); - it('should interpret options given to the loader', function (done) { - - var config = assign({}, globalConfig, { - entry: './test/fixtures/experimental.js', - module: { - loaders: [{ - test: /\.jsx?/, - loader: babelLoader + '?stage=0', - exclude: /node_modules/ - }] - } - }); - - webpack(config, function (err, stats) { - expect(err).to.be(null); - - fs.readdir(outputDir, function (err, files) { - expect(err).to.be(null); - expect(files).to.not.be.empty(); - - done(); - }); - }); + done(); + }); }); + }); + + it('should interpret options given globally', function(done) { + + var config = assign({}, globalConfig, { + entry: './test/fixtures/experimental.js', + babel: { + stage: 0, + }, + module: { + loaders: [ + { + test: /\.jsx?/, + loader: babelLoader, + exclude: /node_modules/, + }, + ], + }, + }); + + webpack(config, function(err, stats) { + expect(err).to.be(null); - it('should interpret options given globally', function (done) { - - var config = assign({}, globalConfig, { - entry: './test/fixtures/experimental.js', - babel: { - stage: 0 - }, - module: { - loaders: [{ - test: /\.jsx?/, - loader: babelLoader, - exclude: /node_modules/ - }] - } - }); - - webpack(config, function (err, stats) { - expect(err).to.be(null); - - fs.readdir(outputDir, function (err, files) { - expect(err).to.be(null); - expect(files).to.not.be.empty(); - - done(); - }); - }); + fs.readdir(outputDir, function(err, files) { + expect(err).to.be(null); + expect(files).to.not.be.empty(); + + done(); + }); + }); + }); + + it('should give priority to loader options', function(done) { + var config = assign({}, globalConfig, { + entry: './test/fixtures/experimental.js', + babel: { + stage: 4, + }, + module: { + loaders: [ + { + test: /\.jsx?/, + loader: babelLoader + '?stage=0', + exclude: /node_modules/, + }, + ], + }, }); - it('should give priority to loader options', function (done) { - var config = assign({}, globalConfig, { - entry: './test/fixtures/experimental.js', - babel: { - stage: 4 - }, - module: { - loaders: [{ - test: /\.jsx?/, - loader: babelLoader + '?stage=0', - exclude: /node_modules/ - }] - } - }); - - webpack(config, function (err, stats) { - expect(err).to.be(null); - - fs.readdir(outputDir, function (err, files) { - expect(err).to.be(null); - expect(files).to.not.be.empty(); - - done(); - }); - }); + webpack(config, function(err, stats) { + expect(err).to.be(null); + + fs.readdir(outputDir, function(err, files) { + expect(err).to.be(null); + expect(files).to.not.be.empty(); + + done(); + }); }); + }); }); diff --git a/test/sourcemaps.test.js b/test/sourcemaps.test.js index 85a9a530..a7f693ab 100644 --- a/test/sourcemaps.test.js +++ b/test/sourcemaps.test.js @@ -1,115 +1,117 @@ -var fs = require('fs'), - path = require('path'), - assign = require('object-assign'), - expect = require('expect.js'), - mkdirp = require('mkdirp'), - rimraf = require('rimraf'), - webpack = require('webpack'); - -describe('Sourcemaps', function () { - - var outputDir = path.resolve(__dirname, './output/sourcemaps'), - babelLoader = path.resolve(__dirname, '../'), - - globalConfig = { - entry: './test/fixtures/basic.js', - output: { - path: outputDir, - filename: '[id].options.js' - }, - module: { - loaders: [ - { - test: /\.jsx?/, - loader: babelLoader, - exclude: /node_modules/ - } - ] - } - }; - - // Clean generated cache files before each test - // so that we can call each test with an empty state. - beforeEach(function (done) { - rimraf(outputDir, function (err) { - if (err) { return done(err); } - mkdirp(outputDir, done); - }); +var fs = require('fs'); +var path = require('path'); +var assign = require('object-assign'); +var expect = require('expect.js'); +var mkdirp = require('mkdirp'); +var rimraf = require('rimraf'); +var webpack = require('webpack'); + +describe('Sourcemaps', function() { + + var outputDir = path.resolve(__dirname, './output/sourcemaps'); + var babelLoader = path.resolve(__dirname, '../'); + var globalConfig = { + entry: './test/fixtures/basic.js', + output: { + path: outputDir, + filename: '[id].options.js', + }, + module: { + loaders: [ + { + test: /\.jsx?/, + loader: babelLoader, + exclude: /node_modules/, + }, + ], + }, + }; + + // Clean generated cache files before each test + // so that we can call each test with an empty state. + beforeEach(function(done) { + rimraf(outputDir, function(err) { + if (err) { return done(err); } + mkdirp(outputDir, done); + }); + }); + + it('should output webpack\'s sourcemap', function(done) { + + var config = assign({}, globalConfig, { + devtool: 'source-map', + entry: './test/fixtures/basic.js', + module: { + loaders: [ + { + test: /\.jsx?/, + loader: babelLoader, + exclude: /node_modules/, + }, + ], + }, }); - it('should output webpack\'s sourcemap', function (done) { - - var config = assign({}, globalConfig, { - devtool: 'source-map', - entry: './test/fixtures/basic.js', - module: { - loaders: [{ - test: /\.jsx?/, - loader: babelLoader, - exclude: /node_modules/ - }] - } - }); - - webpack(config, function (err, stats) { - expect(err).to.be(null); - - fs.readdir(outputDir, function (err, files) { - expect(err).to.be(null); - - var map = files.filter(function (file) { - return (file.indexOf('.map') !== -1); - }); - - expect(map).to.not.be.empty(); + webpack(config, function(err, stats) { + expect(err).to.be(null); - fs.readFile(path.resolve(outputDir, map[0]), function (err, data) { - expect(err).to.be(null); - expect(data.toString().indexOf('webpack:///')).to.not.equal(-1); - done(); - }); + fs.readdir(outputDir, function(err, files) { + expect(err).to.be(null); - }); + var map = files.filter(function(file) { + return (file.indexOf('.map') !== -1); }); - }); - it.skip('should output babel\'s sourcemap', function (done) { - - var config = assign({}, globalConfig, { - entry: './test/fixtures/basic.js', - babel: { - sourceMap: true, - sourceMapName: './output/sourcemaps/babel.map' - }, - module: { - loaders: [{ - test: /\.jsx?/, - loader: babelLoader, - exclude: /node_modules/ - }] - } + expect(map).to.not.be.empty(); + + fs.readFile(path.resolve(outputDir, map[0]), function(err, data) { + expect(err).to.be(null); + expect(data.toString().indexOf('webpack:///')).to.not.equal(-1); + done(); }); - webpack(config, function (err, stats) { - expect(err).to.be(null); + }); + }); + }); + + it.skip('should output babel\'s sourcemap', function(done) { + + var config = assign({}, globalConfig, { + entry: './test/fixtures/basic.js', + babel: { + sourceMap: true, + sourceMapName: './output/sourcemaps/babel.map', + }, + module: { + loaders: [ + { + test: /\.jsx?/, + loader: babelLoader, + exclude: /node_modules/, + }, + ], + }, + }); - fs.readdir(outputDir, function (err, files) { - expect(err).to.be(null); + webpack(config, function(err, stats) { + expect(err).to.be(null); - var map = files.filter(function (file) { - return (file.indexOf('.map') !== -1); - }); + fs.readdir(outputDir, function(err, files) { + expect(err).to.be(null); - expect(map).to.not.be.empty(); + var map = files.filter(function(file) { + return (file.indexOf('.map') !== -1); + }); - fs.readFile(path.resolve(outputDir, map[0]), function (err, data) { - expect(err).to.be(null); - expect(data.toString().indexOf('webpack:///')).to.equal(-1); - done(); - }); + expect(map).to.not.be.empty(); - }); + fs.readFile(path.resolve(outputDir, map[0]), function(err, data) { + expect(err).to.be(null); + expect(data.toString().indexOf('webpack:///')).to.equal(-1); + done(); }); + }); }); + }); }); diff --git a/test/webpack.config.js b/test/webpack.config.js deleted file mode 100644 index c5f0e628..00000000 --- a/test/webpack.config.js +++ /dev/null @@ -1,5 +0,0 @@ -// Just run "webpack-dev-server" -module.exports = { - context: __dirname, - entry: "mocha-loader!./all.js" -}; From efa60df13a288997bd2325f4f027bbf389d4bd48 Mon Sep 17 00:00:00 2001 From: Couto Date: Fri, 3 Apr 2015 19:12:09 +0100 Subject: [PATCH 15/20] Fix package.json version --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 3d9f476f..ef16b2a4 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "babel-loader", - "version": "5.1.0", + "version": "5.0.0", "description": "babel module loader for webpack", "main": "index.js", "dependencies": { From 27a6cbc21aaf5b414d170ea31459b5c340d67a9d Mon Sep 17 00:00:00 2001 From: Couto Date: Fri, 3 Apr 2015 19:15:22 +0100 Subject: [PATCH 16/20] Update README.md --- README.md | 39 ++++++++++++++++++--------------------- 1 file changed, 18 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index 98c5b8c6..3f572d3c 100644 --- a/README.md +++ b/README.md @@ -6,12 +6,9 @@ __Notes:__ Issues with the output should be reported on the babel [issue tracker](https://github.com/babel/babel/issues); ## Installation - You should install [webpack]() and [babel-core]() to use this loader -```bash -npm install babel-core --save -``` + ```bash -npm install webpack babel-loader --save-dev +npm install babel-loader --save-dev ``` __Note:__ [npm](https://npmjs.com) will deprecate [peerDependencies](https://github.com/npm/npm/issues/6565) on the next major release, so required dependencies like babel-core and webpack will have to be installed manually. @@ -53,17 +50,17 @@ module: { ```javascript babel: { - optional: ['runtime'], - stage: 0 + optional: ['runtime'], + stage: 0 }, module: { - loaders: [ - { - test: /\.jsx?$/, - exclude: /(node_modules|bower_components)/, - loader: 'babel' - } - ] + loaders: [ + { + test: /\.jsx?$/, + exclude: /(node_modules|bower_components)/, + loader: 'babel' + } + ] } ``` @@ -104,13 +101,13 @@ module: { ```javascript loaders: [ - // the optional 'runtime' transformer tells babel to require the runtime - // instead of inlining it. - { - test: /\.jsx?$/, - exclude: /(node_modules|bower_components)/, - loader: 'babel-loader?optional[]=runtime' - } + // the optional 'runtime' transformer tells babel to require the runtime + // instead of inlining it. + { + test: /\.jsx?$/, + exclude: /(node_modules|bower_components)/, + loader: 'babel-loader?optional[]=runtime' + } ] ``` ## [License](http://couto.mit-license.org/) From 50db11fb8a4336a702a6bb8e0b474a55cb67330a Mon Sep 17 00:00:00 2001 From: Alberto Leal Date: Wed, 6 May 2015 09:46:26 -0400 Subject: [PATCH 17/20] Update README.md Closes https://github.com/babel/babel-loader/issues/23 --- README.md | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/README.md b/README.md index 6105f17b..ef748512 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,52 @@ loaders: [ ] ``` +#### custom polyfills (e.g. Promise library) + +Since Babel includes a polyfill that includes a custom [regenerator runtime](https://github.com/facebook/regenerator/blob/master/runtime.js) and [core.js](https://github.com/zloirock/core-js), the following usual shimming method using `webpack.ProvidePlugin` will not work: + +```javascript +// ... + new webpack.ProvidePlugin({ + 'Promise': 'bluebird' + }), +// ... +``` + +The following approach will not work either: + +```javascript +require('babel-runtime/core-js/promise').default = require('bluebird'); + +var promise = new Promise; +``` + +which outputs to (using `runtime`): + +```javascript +'use strict'; + +var _Promise = require('babel-runtime/core-js/promise')['default']; + +require('babel-runtime/core-js/promise')['default'] = require('bluebird'); + +var promise = new _Promise(); +``` + +The previous `Promise` library is referenced and used before it is overridden. + +One approach is to have a "bootstrap" step in your application that would first override the default globals before your application: + +```javascript +// bootstrap.js + +require('babel-runtime/core-js/promise').default = require('bluebird'); + +// ... + +require('./app'); +``` + ## Options See the `babel` [options](http://babeljs.io/docs/usage/options/) From 7c73e86d285d49e774d0bf33165f2e5a7d7f6365 Mon Sep 17 00:00:00 2001 From: Jay Jaeho Lee Date: Fri, 15 May 2015 14:56:27 +0900 Subject: [PATCH 18/20] Version bump --- package.json | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index ef16b2a4..21cbf2fe 100644 --- a/package.json +++ b/package.json @@ -1,13 +1,17 @@ { "name": "babel-loader", - "version": "5.0.0", + "version": "5.1.0", "description": "babel module loader for webpack", "main": "index.js", "dependencies": { - "babel-core": "5.0.0", + "babel-core": "^5.4.0", "object-assign": "^2.0.0", "loader-utils": "^0.2.6" }, + "peerDependencies": { + "babel-core": "*", + "webpack": "*" + }, "devDependencies": { "babel-core": "^5.0.6", "expect.js": "^0.3.1", From 22de433dcfc1b36ae43490ea73ae6f6ea02c5a1e Mon Sep 17 00:00:00 2001 From: Couto Date: Fri, 15 May 2015 08:29:56 +0100 Subject: [PATCH 19/20] Update dependencies. --- package.json | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/package.json b/package.json index 21cbf2fe..3d197c25 100644 --- a/package.json +++ b/package.json @@ -6,20 +6,20 @@ "dependencies": { "babel-core": "^5.4.0", "object-assign": "^2.0.0", - "loader-utils": "^0.2.6" + "loader-utils": "^0.2.7" }, "peerDependencies": { "babel-core": "*", "webpack": "*" }, "devDependencies": { - "babel-core": "^5.0.6", + "babel-core": "^5.4.2", "expect.js": "^0.3.1", - "istanbul": "^0.3.13", - "mkdirp": "^0.5.0", - "mocha": "^2.2.1", - "rimraf": "^2.3.2", - "webpack": "^1.7.3" + "istanbul": "^0.3.14", + "mkdirp": "^0.5.1", + "mocha": "^2.2.5", + "rimraf": "^2.3.3", + "webpack": "^1.9.5" }, "scripts": { "test": "istanbul cover ./node_modules/.bin/_mocha -- test/*.test.js" From 57566a71a94cc27757e5a334441a98fcde802cd6 Mon Sep 17 00:00:00 2001 From: Couto Date: Fri, 15 May 2015 08:43:19 +0100 Subject: [PATCH 20/20] Update README.md --- README.md | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 1d263e9c..4ac3b578 100644 --- a/README.md +++ b/README.md @@ -46,26 +46,24 @@ module: { } ``` - or in a less used format, you can set an object in the webpack config. + or by using the query property: ```javascript -babel: { - optional: ['runtime'], - stage: 0 -}, module: { loaders: [ { test: /\.jsx?$/, exclude: /(node_modules|bower_components)/, - loader: 'babel' + loader: 'babel', + query: { + optional: ['runtime'], + stage: 0 + } } ] } ``` - __Note:__ options given directly to the loader take precedence in relation to the *global* object. - This loader also supports the following loader-specific option: * `cacheDirectory`: When set, the given directory will be used to cache the results of the loader. Future webpack builds will attempt to read from the cache to avoid needing to run the potentially expensive Babel recompilation process on each run. A value of `true` will cause the loader to use the default OS temporary file directory.