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

Upgrade Babel 6 to Babel 7 (major) #4050

Merged
merged 16 commits into from
Apr 3, 2018
Merged

Conversation

timneutkens
Copy link
Member

Fixes #2654 #3356

Babel 7 does schema validation of .babelrc and doesn't support "babelrc": false.

Meaning that if you want similar behaviour you should just do

{
  "presets": ["next/babel"]
}

I'm not sure what the benefit of babelrc: false is over above 🤔

cc @arunoda

Also, this is pending a release of taskr: lukeed/taskr#305

And styled-jsx seems to work, but can be improved vercel/styled-jsx#362

@timneutkens
Copy link
Member Author

Also implemented @xtuc's suggestion here: #3428 (comment)

based on the implemented version here: babel/babel#7472

it'll be a bit faster after babel/babel#7588 lands.

The new API seems to work really well @loganfsmyth (as feedback)

const configList = buildConfigChain(options).filter(i => i.loc !== 'base')

return configList[0]
return loadPartialConfig({ babelrc: true, filename })
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd recommend against passing babelrc: true, since you pass filename that is already the default, and it's possible we may change the meaning of true still in the beta to be broader than you'd actually want.

@@ -36,18 +36,18 @@ const plugins = envPlugins[process.env.NODE_ENV] || envPlugins['development']

module.exports = (context, opts = {}) => ({
presets: [
[require.resolve('babel-preset-env'), {
[require.resolve('@babel/preset-env'), {
Copy link
Contributor

Choose a reason for hiding this comment

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

Out of curiosity, is there a specific motivation for using paths here instead of calling require() on its own?

Since you're passing absolute paths it safe to do this, but it does seem more roundabout since Babel has to process the string into a path.

@@ -1,16 +1,9 @@
import { join } from 'path'
import buildConfigChain from 'babel-core/lib/transformation/file/options/build-config-chain'
import {loadPartialConfig} from '@babel/core'

export default function findBabelConfig (dir) {
// We need to provide a location of a filename inside the `dir`.
// For the name of the file, we could be provide anything.
const filename = join(dir, 'filename.js')
Copy link
Contributor

@loganfsmyth loganfsmyth Mar 23, 2018

Choose a reason for hiding this comment

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

This is a little concerning. We've got path-based config processing now from babel/babel#7091, so by hard-coding a filename you're essentially making that feature unusable.

If this is done as a performance optimization, I'd caution against worrying too much there. Babel's config processing has a lot more caching now and should be very fast, even when loadPartialConfig is called for every single file.

Copy link
Member Author

@timneutkens timneutkens Mar 24, 2018

Choose a reason for hiding this comment

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

If this is done as a performance optimization, I'd caution against worrying too much there. Babel's config processing has a lot more caching now and should be very fast, even when loadPartialConfig is called for every single file.

Basically it's not to pre-optimize, but simply to output which path babel is using when starting the Next process, to be transparent to the user.

Also, it's used to include the next/babel preset automatically when no babelrc is available.

// That's why we need to do this.
const { options } = externalBabelConfig
mainBabelOptions.babelrc = options.babelrc !== false
mainBabelOptions.babelrc = true
} else {
mainBabelOptions.babelrc = false
}
Copy link
Contributor

Choose a reason for hiding this comment

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

I'd recommend using the createConfigItem utility on the mainBabelOptions.presets.push(require.resolve('./babel/preset')) line below this, rather than just passing the string, otherwise this will end up doing a lot more work.

@@ -33,17 +33,13 @@ function babelConfig (dir, {isServer, dev}) {
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Same as below about babel.createConfigItem for the hot loader listing above this.

// That's why we need to do this.
const { options } = externalBabelConfig
mainBabelOptions.babelrc = options.babelrc !== false
mainBabelOptions.babelrc = true
Copy link
Contributor

@loganfsmyth loganfsmyth Mar 23, 2018

Choose a reason for hiding this comment

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

If you change up this logic to just be per-filename like I'd recommend, you shouldn't need to assign this to anything. e.g.

const presetItem = createConfigItem(require.resolve('./babel/preset'));
const hotLoaderItem = createConfigItem(require.resolve('react-hot-loader/babel'));

function getBabelConfig(filename, {isServer, dev}) {
  const config = loadPartialConfig({ 
    filename,
    plugins: [
      dev && !isServer && hotLoaderItem
    ].filter(Boolean),
  });

  if (!config) return null;

  let options = config.options;
  if (config.babelrc) {
    if (!isServer) {
      // Maybe just have some extra logic to avoid printing this multiple times?
      console.log(`> Using external babel configuration`)
      console.log(`> Location: "${config.babelrc}"`)
    }
  } else {
    options.presets.push(presetItem);
  }

  return options;
}

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmmm in that case babel-loader needs to be changed to support a function that has the file path as argument and resolves to a babel config right 🤔

Copy link
Member Author

Choose a reason for hiding this comment

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

I like the idea though 👍

Copy link
Contributor

Choose a reason for hiding this comment

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

Ahh, I'd totally forgotten that this is used via babel-loader. That makes this a lot clearer.

Hmmm in that case babel-loader needs to be changed to support a function that has the file path as argument and resolves to a babel config right

Maybe that's something we should explore. I hadn't thought about it but it may well make sense.

Copy link
Contributor

Choose a reason for hiding this comment

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

Unrelated to this specific comment, I'd remove the mainBabelOptions.babelrc = true line, since searching for the config file is already the default.

Copy link
Member Author

Choose a reason for hiding this comment

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

I've removed the line 👍

Copy link
Member Author

Choose a reason for hiding this comment

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

@loganfsmyth created an issue here: babel/babel-loader#598

@loganfsmyth
Copy link
Contributor

I had more comments than I originally expected! Hope they help though :D

.babelrc Outdated
],
"env": {
"test": {
"presets": [
"es2015",
"@babel/preset-es2015",
Copy link
Contributor

Choose a reason for hiding this comment

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

Obviously an existing issue, but since you're using preset-env already, I'd be very surprised if this was necessary.

Copy link
Member Author

Choose a reason for hiding this comment

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

Good catch, we can solve it differently 👍

Copy link
Member Author

Choose a reason for hiding this comment

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

Fixed 👌

],
"env": {
"test": {
"presets": [
"es2015",
"./babel"
["./babel", {
Copy link
Contributor

Choose a reason for hiding this comment

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

So we're on the same page, I'm a little confused about the expectations you have for this vs the presets you have in the top-level presets array. As it is, this test env will just run both sets of presets. What specifically is the goal of the test env here? It'll add a few extra plugins around styling and react it looks like, but it also doubles up on a ton of the stuff you're already specifying in the top level config.

Copy link
Member Author

Choose a reason for hiding this comment

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

Right, this should probably be broken out into .babelrc in the test directory. Will do that after this PR lands. Since it's not directly related to babel 7 👍

Copy link
Contributor

@arunoda arunoda left a comment

Choose a reason for hiding this comment

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

Since babel is removing the babelrc:false support, there's no point in having it.

BTW: It'd be amazing if you could separate out lint fixes to another PR.

@loganfsmyth
Copy link
Contributor

@arunoda

Since babel is removing the babelrc:false support, there's no point in having it.

It's an option that you can programmatically pass to Babel, but it's not an option that is available in config files, even in Babel 6. It would have been a no-op where Next was using it in the .babelrc, it's just that because you were parsing the file yourselves, you could add additional custom behavior based on it. Babel 7 adds validation and now properly states that it is not expected in config files.

@timneutkens
Copy link
Member Author

timneutkens commented Mar 27, 2018

@arunoda

BTW: It'd be amazing if you could separate out lint fixes to another PR.

Unfortunately the older standard breaks because of babel 7. So I had to upgrade it. I'll try to send another PR to merge before this one 👍

@timneutkens timneutkens mentioned this pull request Mar 27, 2018
@timneutkens
Copy link
Member Author

Cherry picked the commit: #4064

@timneutkens timneutkens changed the title Refactor for Babel 7 Upgrade Babel 6 to Babel 7 (major) Apr 3, 2018
@timneutkens timneutkens merged commit 2d8c19a into vercel:canary Apr 3, 2018
@timneutkens timneutkens deleted the add/babel-7 branch April 3, 2018 07:34
@timneutkens
Copy link
Member Author

Thank you very much for all the reviews @loganfsmyth very much appreciated ❤️

@timneutkens timneutkens mentioned this pull request Apr 3, 2018
@@ -77,7 +78,7 @@
"fresh": "0.5.2",
"friendly-errors-webpack-plugin": "1.6.1",
"glob": "7.1.2",
"hoist-non-react-statics": "2.5.0",
"hoist-non-react-statics": "2.3.1",
Copy link
Contributor

Choose a reason for hiding this comment

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

🍶

@@ -1,6 +1,6 @@
{
"name": "next",
"version": "6.0.0-canary.2",
"version": "5.0.1-canary.17",
Copy link
Contributor

Choose a reason for hiding this comment

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

Was this accidentally reverted?

Copy link
Member Author

Choose a reason for hiding this comment

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

yeah fixed already

Copy link
Member Author

Choose a reason for hiding this comment

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

It's release as 6.0.0-canary.3

@lock lock bot locked as resolved and limited conversation to collaborators Apr 3, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants