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

Add support for .babelrc.yaml #4980

Closed
gajus opened this issue Dec 9, 2016 · 14 comments
Closed

Add support for .babelrc.yaml #4980

gajus opened this issue Dec 9, 2016 · 14 comments
Labels
i: discussion outdated A closed issue/PR that is archived due to age. Recommended to make a new issue

Comments

@gajus
Copy link

gajus commented Dec 9, 2016

This is an alternative proposal to #4892 ("Add support for .babelrc.js files").

tl;dr;

Using YAML format can achieve anywhere from 30% to 50% reduction (lines code code) of the configuration length without compromising readability.

In contrast to using JavaScript as a configuration format, using YAML format restricts complexity of the document to the use of merge and anchor features.

I am worried that adding configuration support in JavaScript format will lead to complex configurations that are hard to read. A case in point is webpack. webpack configurations have a tendency to grow in size out of proportion, include an exceeding amount of conditional checks and merging logic.

With no disrespect to the author of the following code example, consider this configuration:

In the above configuration:

In short, there is no way see whats the resulting configuration without executing the code.

I understand that webpack and Babel face different challenges.

However, it is not unreasonable to think that similar patterns will emerge in Babel if configuration in JavaScript format is supported.

However, I do see an issue of repetition in .babelrc.

Lets use this configuration as an example:

{
  "env": {
    "test": {
      // "ava" requires "transform-es2015-modules-commonjs"
      "plugins": [
        "istanbul",
        "transform-es2015-modules-commonjs",
        "transform-export-default-name",
        "transform-flow-strip-types",
        "transform-async-to-generator",
        "transform-es2015-destructuring",
        "transform-es2015-parameters",
        [
          "transform-object-rest-spread",
          {
            "useBuiltIns": true
          }
        ],
        "transform-class-properties"
      ],
      "sourceMaps": "inline"
    },
    // Used for debugging the application in modern browsers.
    "development": {
      "plugins": [
        "transform-export-default-name",
        "transform-flow-strip-types",
        "transform-es2015-destructuring",
        "transform-es2015-parameters",
        [
          "transform-object-rest-spread",
          {
            "useBuiltIns": true
          }
        ],
        "transform-class-properties"
      ]
    },
    // Used for modern browsers that support generators.
    "production-mainstream": {
      "plugins": [
        "closure-elimination",
        "transform-flow-strip-types",
        "transform-async-to-generator",
        "transform-es2015-destructuring",
        "transform-es2015-parameters",
        [
          "transform-object-rest-spread",
          {
            "useBuiltIns": true
          }
        ],
        "transform-class-properties",
        "transform-es2015-classes"
      ]
    },
    // Used for legacy browser support.
    "production-legacy": {
      "plugins": [
        "transform-flow-strip-types"
      ],
      "presets": [
        "es2015",
        "stage-0"
      ]
    }
  }
}

This is a long configuration that shares a lot in common. I cannot use plugins in the general scope because plugin order is important.

First, lets start by rewriting the above configuration using YAML:

Note:
For those not familiar with YAML, I recommend read through this cheatsheet.
https://learnxinyminutes.com/docs/yaml/

---
env:
  # "ava" requires "transform-es2015-modules-commonjs"
  test:
    plugins:
      - istanbul
      - transform-es2015-modules-commonjs
      - transform-export-default-name
      - transform-flow-strip-types
      - transform-async-to-generator
      - transform-es2015-destructuring
      - transform-es2015-parameters
      - 
        - transform-object-rest-spread
        - useBuiltIns: true
      - transform-class-properties
    sourceMaps: inline
  # Used for debugging the application in modern browsers.
  development:
    plugins:
      - transform-export-default-name
      - transform-flow-strip-types
      - transform-es2015-destructuring
      - transform-es2015-parameters
      - 
        - transform-object-rest-spread
        - useBuiltIns: true
      - transform-class-properties
   # Used for modern browsers that support generators.
  production-mainstream:
     plugins:
      - closure-elimination
      - transform-flow-strip-types
      - transform-async-to-generator
      - transform-es2015-destructuring
      - transform-es2015-parameters
      - 
        - transform-object-rest-spread
        - useBuiltIns: true
      - transform-class-properties
      - transform-es2015-classes
   # Used for legacy browser support.
  production-legacy:
     plugins:
       - transform-flow-strip-types
     presets:
       - es2015
       - stage-0

Thats already a reduction from 68 lines of code to 48 (30% reduction). However, we can do better.

YAML format supports merge key. Using merge and anchoring, we can rewrite the above configuration as:

---
aliases:
  common: &common
    - transform-flow-strip-types
    - transform-export-default-name
    - transform-es2015-destructuring
    - transform-es2015-parameters
    - 
      - transform-object-rest-spread
      - useBuiltIns: true
    - transform-class-properties
env:
  # "ava" requires "transform-es2015-modules-commonjs"
  test:
    plugins:
      - istanbul
      - transform-es2015-modules-commonjs
      - transform-async-to-generator
      - *common
    sourceMaps: inline
  # Used for debugging the application in modern browsers.
  development:
    plugins:
      - transform-export-default-name
      - *common
  # Used for modern browsers that support generators.
  production-mainstream:
    plugins:
      - closure-elimination
      - transform-async-to-generator
      - *common
      - transform-es2015-classes
  # Used for legacy browser support.
  production-legacy:
     plugins:
       - transform-flow-strip-types
     presets:
       - es2015
       - stage-0

Note:
There is a gotcha. The above example creates a list within a list. Therefore, a special rule would need to be added that flattens the configuration.

Thats a reduction from 68 lines of code to 38 (45% reduction).

The most import thing here is not reduction of lines though, but reduction of repeated content thats shared across multiple configurations.

One of the most common mistakes that I make when configuring multiple environments, is forgetting to add some configuration to one of the configs that needs to be shared across a group of configurations. Using YAML solves this issue.

In contrast to allowing JavaScript configuration files, YAML configuration files introduce a set level of complexity.

@christopher-wilson
Copy link

I would like something like this. Would it be possible to support placing everything under a babel key so that we may possible have one config file per project, instead of one per tool?

@gajus
Copy link
Author

gajus commented Dec 9, 2016

I would like something like this. Would it be possible to support placing everything under a babel key so that we may possible have one config file per project, instead of one per tool?

This option already exists https://babeljs.io/docs/usage/babelrc/#use-via-package-json

@gajus
Copy link
Author

gajus commented Dec 9, 2016

Someone commented:

Anything that accepts comments in it is better than plain old JSON. Even a .js file with module.exports = {} would be a life saver.

.babelrc is using JSON5 format. You can use comments in .babelrc file.

The reason I am mentioning this is because most people who are advocating JavaScript file as a configuration format do so because:

Mostly, I [use JavaScript configuration files] because [I] like being able to omit quotes and use familiar comment syntax, without having to learn yet another markup language, and while leaving the door open for future dynamic stuff, if I find an appropriate reason for it.

– https://www.reddit.com/r/javascript/comments/5hdpkh/would_you_like_babel_to_support_yaml/dazhau6/

@captainamerican
Copy link

If this is optional, then I don't care. I wouldn't use it, but that's me. However, forcing this requirement would be Babel 6 all over again.

@gajus
Copy link
Author

gajus commented Dec 9, 2016

If this is optional, then I don't care. I wouldn't use it, but that's me. However, forcing this requirement would be Babel 6 all over again.

This proposal is for addition of YAML syntax in addition to the existing configuration format.

Nevertheless, you/ me do need to care because we will eventually inherit projects that use one variation of the configuration format.

I do think that most projects will stick with JSON format, because it is native to JavaScript platform. However, YAML syntax enables more complex projects to use YAML when needed.

@captainamerican
Copy link

captainamerican commented Dec 9, 2016

As an option, I'm all for this and #4892. I'm not a fan of yaml even if I agree with the logic employed by the issuer for the inclusion of yaml.

@ckknight
Copy link

ckknight commented Dec 9, 2016

I'd rather not have the mental overhead of having multiple formats different projects. If YAML is supported, then half the teams I work with will end up using it and then the burden is on me (or anyone else who jumps between projects) to comprehend both formats equally well for .babelrc. It will also add to the burden of copying one plugin from one project to another. You'd have to add or remove syntax in order to convey it properly in the new format.

I'd like to stick to one standard, and JSON5 is a good one.

@gajus
Copy link
Author

gajus commented Dec 9, 2016

As an option, I'm all for this and #4892. I'm not a fan of yaml even if I agree with the logic employed by the issuer for the inclusion of yaml.

To me it all comes down to simple reasoning:

  • YAML is a data-oriented format often used for configuration files (Kubernetes, Docker, to name but a few trending examples)
  • JavaScript is a script language.

@gajus
Copy link
Author

gajus commented Dec 9, 2016

I'd rather not have the mental overhead of having multiple formats different projects. If YAML is supported, then half the teams I work with will end up using it and then the burden is on me (or anyone else who jumps between projects) to comprehend both formats equally well for .babelrc. It will also add to the burden of copying one plugin from one project to another. You'd have to add or remove syntax in order to convey it properly in the new format.

Valid considerations.

As a simple workaround, I written a small script that I have added to the build step that converts the YAML file in the earlier example to JSON file. It could be released as a separate tool.

@klardotsh
Copy link

klardotsh commented Dec 9, 2016

To me this feels like dependency creep because it's cool to support multiple file formats these days (though the code reuse aspects are definitely useful and difficult to argue against). There's a lot of problems I have with babelrc files - the inability to specify a preset and override the options of one plugin inside of said preset is one - but the file format has both never been an issue for me, and is standard across all projects. Allowing JSON JS YAML (assuming both of these issues were resolved) is more code for anyone jumping into contributing to Babel to wrap their heads around, and fragments the community a bit (see also, Gruntfiles written in, for example, CoffeeScript - anyone wanting to edit that project's build process now has to learn CoffeeScript, despite having used plain ol' JS on every Gruntfile they've come across before).

My opinion likely means a bit less as a user rather than contributor to Babel, but I eye all efforts like this with a bit of skepticism, and arguably, conservatism, in the name of KISS.

@christopher-wilson
Copy link

would like something like this. Would it be possible to support placing everything under a babel key so that we may possible have one config file per project, instead of one per tool?

This option already exists https://babeljs.io/docs/usage/babelrc/#use-via-package-json

I was actually referring to the YAML file.

@piuccio
Copy link

piuccio commented Dec 13, 2016

My concern is that YAML is less portable, you'll need a module to read it and if you want to share the configuration with other tools it'll be trickier than a simple require('.eslintrc');

@gajus
Copy link
Author

gajus commented Dec 13, 2016

https://www.npmjs.com/package/jsonscript is another option.

@hzoo
Copy link
Member

hzoo commented Feb 7, 2017

I'd rather we go with a js file instead of supporting YAML so closing in favor of #4892

We can have a distinction between dynamic configs = JS and static configs = JSON

@hzoo hzoo closed this as completed Feb 7, 2017
@lock lock bot added the outdated A closed issue/PR that is archived due to age. Recommended to make a new issue label May 5, 2018
@lock lock bot locked as resolved and limited conversation to collaborators May 5, 2018
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
i: discussion outdated A closed issue/PR that is archived due to age. Recommended to make a new issue
Projects
None yet
Development

No branches or pull requests

8 participants