-
Notifications
You must be signed in to change notification settings - Fork 10.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #279 from benstepp/bs-babel
Support user provided babel configs Conflicts: lib/utils/webpack.config.js package.json
- Loading branch information
Showing
12 changed files
with
228 additions
and
34 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,4 @@ | ||
{ | ||
"presets": ['react', 'es2015', 'stage-0'], | ||
"plugins": [ | ||
'transform-object-rest-spread' | ||
] | ||
"plugins": [] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
import resolve from 'babel-core/lib/helpers/resolve' | ||
import fs from 'fs' | ||
import path from 'path' | ||
import json5 from 'json5' | ||
import startsWith from 'lodash/startsWith' | ||
import invariant from 'invariant' | ||
|
||
const DEFAULT_BABEL_CONFIG = { | ||
presets: ['react', 'es2015', 'stage-0'], | ||
plugins: ['add-module-exports', 'transform-object-assign'], | ||
} | ||
|
||
/** | ||
* Uses babel-core helpers to resolve the plugin given it's name. It | ||
* resolves plugins in the following order: | ||
* | ||
* 1. Adding babel-type prefix and checking user's local modules | ||
* 2. Adding babel-type prefix and checking Gatsby's modules | ||
* 3. Checking users's modules without prefix | ||
* 4. Checking Gatsby's modules without prefix | ||
* | ||
*/ | ||
function resolvePlugin (pluginName, directory, type) { | ||
const gatsbyPath = path.resolve('..', '..') | ||
const plugin = resolve(`babel-${type}-${pluginName}`, directory) || | ||
resolve(`babel-${type}-${pluginName}`, gatsbyPath) || | ||
resolve(pluginName, directory) || | ||
resolve(pluginName, gatsbyPath) | ||
|
||
const name = startsWith(pluginName, 'babel') ? pluginName : `babel-${type}-${pluginName}` | ||
const pluginInvariantMessage = ` | ||
You are trying to use a Babel plugin which Gatsby cannot find. You | ||
can install it using "npm install --save ${name}". | ||
You can use any of the Gatsby provided plugins without installing them: | ||
- babel-plugin-add-module-exports | ||
- babel-plugin-transform-object-assign | ||
- babel-preset-es2015 | ||
- babel-preset-react | ||
- babel-preset-stage-0 | ||
` | ||
|
||
invariant(plugin !== null, pluginInvariantMessage) | ||
return plugin | ||
} | ||
|
||
/** | ||
* Normalizes a Babel config object to include only absolute paths. | ||
* This way babel-loader will correctly resolve Babel plugins | ||
* regardless of where they are located. | ||
*/ | ||
function normalizeConfig (config, directory) { | ||
const normalizedConfig = { | ||
presets: [], | ||
plugins: [], | ||
} | ||
|
||
const presets = config.presets || [] | ||
presets.forEach(preset => { | ||
normalizedConfig.presets.push(resolvePlugin(preset, directory, 'preset')) | ||
}) | ||
|
||
const plugins = config.plugins || [] | ||
plugins.forEach(plugin => { | ||
normalizedConfig.plugins.push(resolvePlugin(plugin, directory, 'plugin')) | ||
}) | ||
|
||
return normalizedConfig | ||
} | ||
|
||
/** | ||
* Locates a .babelrc in the Gatsby site root directory. Parses it using | ||
* json5 (what Babel uses). It throws an error if the users's .babelrc is | ||
* not parseable. | ||
*/ | ||
function findBabelrc (directory) { | ||
try { | ||
const babelrc = fs.readFileSync(path.join(directory, '.babelrc'), 'utf-8') | ||
return json5.parse(babelrc) | ||
} catch (error) { | ||
if (error.code === 'ENOENT') { | ||
return null | ||
} else { | ||
throw error | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Reads the user's package.json and returns the "babel" section. It will | ||
* return undefined when the "babel" section does not exist. | ||
*/ | ||
function findBabelPackage (directory) { | ||
try { | ||
const packageJson = require(path.join(directory, 'package.json')) | ||
return packageJson.babel | ||
} catch (error) { | ||
if (error.code === 'MODULE_NOT_FOUND') { | ||
return null | ||
} else { | ||
throw error | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Returns a normalized Babel config to use with babel-loader. All of | ||
* the paths will be absolute so that Babel behaves as expected. | ||
*/ | ||
export default function babelConfig (program, stage) { | ||
const { directory } = program | ||
|
||
const babelrc = findBabelrc(directory) || | ||
findBabelPackage(directory) || | ||
DEFAULT_BABEL_CONFIG | ||
|
||
if (stage === 'develop') { | ||
babelrc.presets.unshift('react-hmre') | ||
} | ||
|
||
return normalizeConfig(babelrc, directory) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
{ | ||
"babel": { | ||
"presets": ["react", "es2015", "stage-0"] | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
{ | ||
presets: ['react'] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
{ | ||
plugins: [ | ||
"transform-decorators-legacy", | ||
"transform-async-to-generator", | ||
"transform-es2015-modules-commonjs", | ||
"transform-export-extensions", | ||
] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
{ | ||
"presets": ['react', 'es2015', 'stage-0'] | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,60 @@ | ||
import test from 'ava' | ||
import path from 'path' | ||
import includes from 'lodash/includes' | ||
import babelConfig from '../../lib/utils/babel-config' | ||
|
||
function programStub (fixture) { | ||
const directory = path.resolve('..', 'fixtures', fixture) | ||
return { directory } | ||
} | ||
|
||
test('it returns a default babel config for babel-loader query', t => { | ||
const program = programStub('site-without-babelrc') | ||
const config = babelConfig(program) | ||
|
||
t.true(typeof config === 'object') | ||
t.truthy(config.presets.length) | ||
t.truthy(config.plugins.length) | ||
}) | ||
|
||
test('all plugins are absolute paths to avoid babel lookups', t => { | ||
const program = programStub('site-without-babelrc') | ||
const config = babelConfig(program) | ||
|
||
config.presets.forEach(preset => t.true(path.resolve(preset) === preset)) | ||
config.plugins.forEach(plugin => t.true(path.resolve(plugin) === plugin)) | ||
}) | ||
|
||
test('fixture can resolve plugins in gatsby directory (crawling up)', t => { | ||
const program = programStub('site-with-valid-babelrc') | ||
|
||
const config = babelConfig(program) | ||
t.truthy(config.presets.length) | ||
}) | ||
|
||
test('throws error when babelrc is not parseable', t => { | ||
const program = programStub('site-with-invalid-babelrc') | ||
|
||
t.throws(() => babelConfig(program)) | ||
}) | ||
|
||
test('can read babel from packagejson', t => { | ||
const program = programStub('site-with-valid-babelpackage') | ||
|
||
const config = babelConfig(program) | ||
t.truthy(config.presets.length) | ||
}) | ||
|
||
test('when in development has hmre', t => { | ||
const program = programStub('site-without-babelrc') | ||
const config = babelConfig(program, 'develop') | ||
|
||
// regex matches: babel followed by any amount of hyphen or word characters | ||
const presetNames = config.presets.map(p => p.match(/babel[-|\w]+/)[0]) | ||
t.true(includes(presetNames, 'babel-preset-react-hmre')) | ||
}) | ||
|
||
test('throws when a plugin is not available', t => { | ||
const program = programStub('site-with-unresolvable-babelrc') | ||
t.throws(() => babelConfig(program)) | ||
}) |