Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Use new babel API's to manage babel options #6801

Merged
merged 28 commits into from Aug 16, 2018
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
24155bd
WIP: flesh out how the babel-loader might work
jquense Jul 27, 2018
446a2eb
Merge remote-tracking branch 'origin/master' into babel-api
KyleAMathews Aug 9, 2018
e814fd0
WIP
KyleAMathews Aug 9, 2018
c37459d
Merge remote-tracking branch 'origin/master' into babel-api
KyleAMathews Aug 9, 2018
8846126
Merge remote-tracking branch 'origin/master' into babel-api
KyleAMathews Aug 10, 2018
ec7bc2b
Write out babel plugin info + stage for custom babel-loader
KyleAMathews Aug 10, 2018
69afca8
cleanups
KyleAMathews Aug 10, 2018
ba147ee
Merge remote-tracking branch 'origin/master' into babel-api
KyleAMathews Aug 14, 2018
20b4855
Add missing await
KyleAMathews Aug 14, 2018
d79b0ce
Don't set babelrc to false since we check for `partialConfig.hasFiles…
KyleAMathews Aug 14, 2018
b5b69e8
Set env variable instead of writing out file
KyleAMathews Aug 14, 2018
748dc9c
Remove old file for creating config
KyleAMathews Aug 14, 2018
14922dd
Add back stage specific plugins
KyleAMathews Aug 14, 2018
196dae8
Add required plugins/presets to babel config even if there's a file-d…
KyleAMathews Aug 14, 2018
3333174
Update sample .babelrc people can copy into their site
KyleAMathews Aug 14, 2018
e1e1db5
Trim away more unused code
KyleAMathews Aug 14, 2018
bdca781
update snapshot
KyleAMathews Aug 14, 2018
7693394
Add fallback plugins for when a .babelrc isn't defined + merge in gat…
KyleAMathews Aug 15, 2018
6b27a5c
Comments
KyleAMathews Aug 15, 2018
66de295
Add back plugin
KyleAMathews Aug 15, 2018
99dedbf
Update snapshots
KyleAMathews Aug 15, 2018
9883d64
update tests
KyleAMathews Aug 16, 2018
cef9f22
Add some docs
KyleAMathews Aug 16, 2018
ac1ea8f
test helper libs
KyleAMathews Aug 16, 2018
ee0523c
Merge remote-tracking branch 'origin/master' into babel-api
KyleAMathews Aug 16, 2018
5481a14
Fix lint errors
KyleAMathews Aug 16, 2018
e223d25
Remove json5 from gatsby's package.json as it's unused now
KyleAMathews Aug 16, 2018
f75d497
mock resolve
KyleAMathews Aug 16, 2018
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
104 changes: 27 additions & 77 deletions packages/gatsby/src/internal-plugins/load-babel-config/gatsby-node.js
@@ -1,76 +1,15 @@
/* @flow */

const fs = require(`fs`)
const fs = require(`fs-extra`)
const path = require(`path`)
const json5 = require(`json5`)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

seems like we can remove json5 from package.json (this and tests you remove are only places where this is used)

const report = require(`gatsby-cli/lib/reporter`)
const { actionifyBabelrc, addDefaultPluginsPresets } = require(`./utils`)
const existsSync = require(`fs-exists-cached`).sync

const apiRunnerNode = require(`../../utils/api-runner-node`)
const testRequireError = require(`../../utils/test-require-error`).default

/**
* 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) {
const babelrcPath = path.join(directory, `.babelrc`)
if (existsSync(babelrcPath)) {
try {
const babelrc = fs.readFileSync(babelrcPath, `utf-8`)
return json5.parse(babelrc)
} catch (error) {
throw error
}
}
return null
}

/**
* Locates a .babelrc.js in the Gatsby site root directory.
* requires it and unwraps any esm default export
*/
const preferDefault = m => (m && m.default) || m
function findBabelrcJs(directory, stage) {
let babelrc = null
const babelrcPath = path.join(directory, `.babelrc.js`)
try {
babelrc = preferDefault(require(babelrcPath))
} catch (error) {
if (!testRequireError(babelrcPath, error)) {
throw error
}
}

// TODO support this
if (typeof babelrc === `function`) {
report.error(
`.babelrc.js files that export a function are not supported in Gatsby`
)
return null
}

return babelrc
}

/**
* 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) {
const packageJson = require(path.join(directory, `package.json`))
try {
// $FlowFixMe - https://github.com/facebook/flow/issues/1975
return packageJson.babel
} catch (error) {
if (testRequireError(packageJson, error)) {
return null
} else {
throw error
}
}
}
const { withBasePath } = require(`../../utils/path`)

/**
* Creates a normalized Babel config to use with babel-loader. Loads a local
Expand All @@ -80,18 +19,29 @@ exports.onCreateBabelConfig = ({ stage, store, actions }) => {
const program = store.getState().program
const { directory } = program

let babelrc =
findBabelrc(directory) ||
findBabelrcJs(directory) ||
findBabelPackage(directory)
addDefaultPluginsPresets(actions, {
stage,
browserslist: program.browserslist,
})
}

// If user doesn't have a custom babelrc, add defaults.
if (babelrc) {
actionifyBabelrc(babelrc, actions)
} else {
addDefaultPluginsPresets(actions, {
stage,
browserslist: program.browserslist,
})
}
exports.onPreBootstrap = async ({ store }) => {
const directory = store.getState().program.directory
const directoryPath = withBasePath(directory)

await apiRunnerNode(`onCreateBabelConfig`, {
stage: `develop`,
})
await apiRunnerNode(`onCreateBabelConfig`, {
stage: `develop-html`,
})
await apiRunnerNode(`onCreateBabelConfig`, {
stage: `build-javascript`,
})
await apiRunnerNode(`onCreateBabelConfig`, {
stage: `build-html`,
})
const babelrcState = store.getState().babelrc
const babelState = JSON.stringify(babelrcState.stages, null, 4)
fs.writeFile(directoryPath(`.cache/babelState.json`), babelState)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this missing an await?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes :-D

}
71 changes: 71 additions & 0 deletions packages/gatsby/src/utils/babel-loader.js
@@ -0,0 +1,71 @@
const babelLoader = require(`babel-loader`)
const path = require(`path`)
const fs = require(`fs`)

const prepareOptions = babel => {
const pluginBabelConfig = require(path.join(
process.cwd(),
`./.cache/babelState.json`
))

const stage = fs.readFileSync(
path.join(process.cwd(), `./.cache/current-stage.txt`),
`utf8`
)

// Go through babel state and create config items.
const reduxPlugins = []
const reduxPresets = []
pluginBabelConfig[stage].plugins.forEach(plugin => {
reduxPlugins.push(
babel.createConfigItem([require.resolve(plugin.name), plugin.options], {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Might be worth caching this somehow to avoid re-resolving for every single file that Gatsby compiles. Or does Node already cache that for require?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, node caches that so we should be fine.

type: `plugin`,
})
)
})
pluginBabelConfig[stage].presets.forEach(preset => {
reduxPresets.push(
babel.createConfigItem([require.resolve(preset.name), preset.options], {
type: `preset`,
})
)
})

return [reduxPresets, reduxPlugins]
}

module.exports = babelLoader.custom(babel => {
const toReturn = {
// Passed the loader options.
customOptions(options) {
return {
loader: {
cacheDirectory: true,
babelrc: false,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think you'd want to set this since you have partialConfig.hasFilesystemConfig() explicitly checked.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

sourceType: `unambiguous`,
...options,
},
}
},

// Passed Babel's 'PartialConfig' object.
config(partialConfig) {
let { options } = partialConfig

// If there is no filesystem config present add more defaults
// TODO: maybe this should be stricter, like checks if there are no plugins or presets?
if (!partialConfig.hasFilesystemConfig()) {
const [reduxPresets, reduxPlugins] = prepareOptions(babel)
options = {
...options,
plugins: reduxPlugins,
presets: reduxPresets,
}
}

return options
},
}

return toReturn
})
11 changes: 4 additions & 7 deletions packages/gatsby/src/utils/webpack-utils.js
Expand Up @@ -7,7 +7,6 @@ const UglifyPlugin = require(`uglifyjs-webpack-plugin`)
const MiniCssExtractPlugin = require(`mini-css-extract-plugin`)

const builtinPlugins = require(`./webpack-plugins`)
const { createBabelConfig } = require(`./babel-config`)
const eslintConfig = require(`./eslint-config`)

type LoaderSpec = string | { loader: string, options?: Object }
Expand Down Expand Up @@ -119,12 +118,10 @@ module.exports = async ({
}): Promise<WebpackUtilsOptions> => {
const assetRelativeRoot = `static/`
const vendorRegex = /(node_modules|bower_components)/
const supportedBrowsers = program.browserlist
const supportedBrowsers = program.browserslist

const PRODUCTION = !stage.includes(`develop`)

const babelConfig = await createBabelConfig(program, stage)

const isSSR = stage.includes(`html`)

const makeExternalOnly = (original: RuleFactory<*>) => (
Expand Down Expand Up @@ -257,10 +254,10 @@ module.exports = async ({
}
},

js: (options = babelConfig) => {
js: options => {
return {
options,
loader: require.resolve(`babel-loader`),
loader: require.resolve(`./babel-loader`),
}
},

Expand Down Expand Up @@ -297,7 +294,7 @@ module.exports = async ({
* Javascript loader via babel, excludes node_modules
*/
{
let js = options => {
let js = (options = {}) => {
return {
test: /\.jsx?$/,
exclude: vendorRegex,
Expand Down
8 changes: 7 additions & 1 deletion packages/gatsby/src/utils/webpack.config.js
@@ -1,6 +1,6 @@
require(`v8-compile-cache`)

const fs = require(`fs`)
const fs = require(`fs-extra`)
const path = require(`path`)
const dotenv = require(`dotenv`)
const FriendlyErrorsWebpackPlugin = require(`friendly-errors-webpack-plugin`)
Expand Down Expand Up @@ -28,6 +28,12 @@ module.exports = async (
) => {
const directoryPath = withBasePath(directory)

await fs.writeFile(

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the stage able to be passed through to the loaders as an argument? That seems like it would be easier.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No idea... I'll just set it on process.env actually instead of this method.

directoryPath(`.cache/current-stage.txt`),
suppliedStage,
`utf8`
)

// We combine develop & develop-html stages for purposes of generating the
// webpack config.
const stage = suppliedStage
Expand Down
8 changes: 4 additions & 4 deletions www/package.json
Expand Up @@ -7,20 +7,20 @@
"bluebird": "^3.5.1",
"email-validator": "^1.1.1",
"fuse.js": "^3.2.0",
"gatsby": "^2.0.0-beta.47",
"gatsby": "^2.0.0-beta.97",
"gatsby-image": "next",
"gatsby-plugin-canonical-urls": "next",
"gatsby-plugin-catch-links": "next",
"gatsby-plugin-create-client-paths": "^1.0.8",
"gatsby-plugin-feed": "next",
"gatsby-plugin-fullstory": "^1.0.4-5",
"gatsby-plugin-glamor": "next",
"gatsby-plugin-google-analytics": "next",
"gatsby-plugin-google-analytics": "^2.0.0-beta.5",
"gatsby-plugin-google-tagmanager": "next",
"gatsby-plugin-lodash": "next",
"gatsby-plugin-mailchimp": "^2.2.3",
"gatsby-plugin-manifest": "next",
"gatsby-plugin-netlify": "next",
"gatsby-plugin-manifest": "^2.0.2-beta.5",
"gatsby-plugin-netlify": "^2.0.0-beta.6",
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should these stay on next?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤷‍♂️ it's the same but yeah — I'll remove them to reduce PR noise

"gatsby-plugin-netlify-cache": "^0.1.0",
"gatsby-plugin-nprogress": "next",
"gatsby-plugin-offline": "^2.0.0-beta.9",
Expand Down