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

RFC: Print Babel Configuration #10617

Open
JLHwung opened this issue Oct 30, 2019 · 5 comments

Comments

@JLHwung
Copy link
Contributor

@JLHwung JLHwung commented Oct 30, 2019

Introduction

This document aims to address the requirement of printing babel configuration. The concept of configuration and environment information is clarified. Two new config items are introduced.

There have been multiple issues requesting this feature (#2960, #6856, #10538), of which we shall agree on the popularity and value.

There are two PRs (#4806, #7201) implementing this feature. Both of them were stale due to inactivity or lack of consensus. The scope of #4806 and #7201 are slightly different: the former prints the resolved configuration while the latter prints the config items plugins and presets. Note that both of them prints babel plugin versions, which should be part of environment information.

Before we propose a solution, we should first clarify the concept of babel configuration and environment information.

Concept

Babel Configuration is a specific file content and/or user-supplied JavaScript object. Here is an example list: 1) contents of .babelrc, 2) contens of babel field in package.json and 3) the opt argument of babel.transform(code, opt). @babel/core will process this configuration lists and merge them into a resolved configuration.

Environment Information is an umbrella term includes but is not limited to: versions of the OS, node, npm; versions of babel and its plugins/presets; versions of monorepo tools lerna, yarn workspace. A list of environment information is required in Babel's bug template to convey the context of this issue.

Scope

Printing Environment Information is orthogonal to Babel and thus should not be implemented in @babel/cli. We have proposed a babel preset for envinfo and we expect it will soon be installed to issue templates.

In this document we will only address printing babel configs.

Solution

Add a new config item: showConfig: boolean. Its default value is false.

This boolean option is an opt-in switch to output configs. The alternative environment variable is considered to use only when @babel/core is a transitive dependency or the configuration is not controlled by end user.

Add a new config item: showConfigForPath: string. If it is not specified and BABEL_SHOW_CONFIG_FOR_PATH environment variable exists, set showConfigForPath to be its value. If this value is not nullish, it will imply that showConfig is true. When showConfig is specified, its default value is assigned from the filename transform option.

This option is used to eliminate the ambiguity of configuration chain when multiple babel configurations exist in different paths. Instead of printing all configurations which may be irrelevant, only applicable config with respect to showConfigForPath will be printed.

A new @babel/cli options --show-config is added. Note that --show-config-for-path is redundant as it can be inferred from the path argument.

When multiple paths are passed in @babel/cli, only the first one will be respected.

Procedure

When loading configuration:

if `showConfig` is `true`, compare `options.filename` with `showConfigForPath`:
  if it does not match, continue;
  else 
   a) serialize the applicable configuration descriptor
   b) print to stdout
   c) terminate the process with code 1

The last step ensures that

  • the configuration would not be overwhelmed by other logs
  • debug feedback is faster than running through the whole process.

Usage

Using @babel/cli

babel src/foo.js --show-config --plugins=@babel/proposal-class-properties,@babel/transform-class

Example output:

// cli config
{
  "plugins": [
    "@babel/proposal-class-properties",
    "@babel/transform-class"
  ],
  "showConfig": true
}

// babel config ./src/.babelrc
{
  "plugins": [
    "lodash"
  ]
}

// babel config ./babel.config.cjs (serialized)
{
  "presets": [
    ["@babel/preset-env", { useBuiltIns: true }]
  ],
  "overrides": [
    { "test": "./src/foo.js", "compact": true }
  ]
}

// babel config ./package.json#babel
{
  "babelrcRoots": [
    ".",
    "./src/*"
  ]
}

Using webpack and babel-loader

BABEL_SHOW_CONFIG_FOR_PATH="./src/app.jsx" webpack --config webpack.config.js

Example output:

// user supplied config (serialized)
{
  "sourceMaps": "inline"
}

// babel config ./babel.config.cjs
{
  "presets": ["@babel/react"]
}

Using create-react-app

BABEL_SHOW_CONFIG_FOR_PATH="./src/app.jsx" react-scripts build

Example output:

// user supplied config (serialized)
{
  ... babel configuration injected by CRA
}

// babel config ./src/.babelrc.js (serialized)
{
  "plugins": [
    "lodash"
  ]
}

Config serialization

static (.babelrc, babel.config.json, package.json#babel)

The static configuration is JSON format, therefore the config we get is a plain object, it is straightforward to stringify it back and output to console.

dynamic (babel.config.js, babel.config.cjs, .babelrc.js, .babelrc.cjs)

The configuration object is produced from requireing CommonJS module before processing config items.

Serializing this object with customized JSON replacer replace(key, value):

If key is plugins or presets, for every array item, check by item, item.name, item[0].name for plugin/preset name

Otherwise if value is of function type, omit this property

Mark the output as serialized as it may be different from the original dynamic config.

Questions

Q: Should we support --show-merged-config flag to output a merged JSON configuration?

A: Would be good to include it in next phase. It should help reasoning about the ignore/include config items.

Q: Should we print the resolved presets config? (presets: ["@babel/env"] vs plugins: [...])

A: Not prioritized. It doesn't help on plugin ordering issues and it makes printed result more verbose.

Q: Should we print the extended config item? i.e. extends: "babel-preset-foo"

A: Not prioritized. I don't think it is popular.

Prior Art

This document is inspired from the following prior arts.

TypeScript Compiler tsc has a --showConfig option. It prints the merged configuration from the contents of tsconfig.json and default configs.

$ tsc --showConfig foo.ts

{
    "compilerOptions": {},
    "files": [
        "./foo.ts"
    ]
}

npm has a subcommand npm config list. It lists a chain of applicable configs with respect to current working directory.

$ npm config list

; cli configs
metrics-registry = "https://registry.npmjs.org/"

; userconfig /Users/foo/.npmrc
tag-version-prefix = ""

; globalconfig /usr/local/etc/npmrc
sign-git-tag = true
@babel-bot

This comment has been minimized.

Copy link
Collaborator

@babel-bot babel-bot commented Oct 30, 2019

Hey @JLHwung! We really appreciate you taking the time to report an issue. The collaborators on this project attempt to help as many people as possible, but we're a limited number of volunteers, so it's possible this won't be addressed swiftly.

If you need any help, or just have general Babel or JavaScript questions, we have a vibrant Slack community that typically always has someone willing to help. You can sign-up here for an invite."

@nicolo-ribaudo nicolo-ribaudo pinned this issue Nov 1, 2019
@nicolo-ribaudo

This comment has been minimized.

Copy link
Member

@nicolo-ribaudo nicolo-ribaudo commented Nov 1, 2019

  1. I think one env var is enough. If I specify BABEL_SHOW_CONFIG_FOR_PATH, then it's obvious that I want to print the config and I shouldn't need BABEL_SHOW_CONFIG.
  2. Maybe it could be a follow-up, but it would also be really useful to know why Babel is loading or not a configuration. For example:
- /my/project/folder
  - babel.config.js
  - .babelrc
  - packages
    - demo
      - package.json
      - .babelrc
      - src
        - input.js
Looking for root configuration files in ./
  Found babel.config.js
Looking for relative configuration files starting from ./packages/demo/src
	Found ./packages/demo/.babelrc
    Ignored because not in babelrcRoots
	Found package root at ./packages/demo/package.json: stopping
@JLHwung

This comment has been minimized.

Copy link
Contributor Author

@JLHwung JLHwung commented Nov 3, 2019

I think one env var is enough. If I specify BABEL_SHOW_CONFIG_FOR_PATH, then it's obvious that I want to print the config and I shouldn't need BABEL_SHOW_CONFIG.

Good point! I have updated the document and also removed the --show-config-for-path cli option.

why Babel is loading or not a configuration

We can append the inactive configs to the output config chains. i.e.

// user supplied config (serialized)
{
  ... babel configuration injected by CRA
}

// inactive configs
- babel config ./src/.babelrc.js (not in babelrcRoots)

and ignored when the effective config is empty. i.e.

// ignored from rules in ./src/.babelignore

What do you think?

@rajasekarm

This comment has been minimized.

Copy link
Contributor

@rajasekarm rajasekarm commented Nov 7, 2019

I worked on this implementation #7201 earlier, If this proposal is finalized I can re-implement this.

@JLHwung @nicolo-ribaudo

@JLHwung

This comment has been minimized.

Copy link
Contributor Author

@JLHwung JLHwung commented Nov 7, 2019

@rajasekarm That's awesome. I will assign to you. Also feel free to comment on this proposal should you have any suggestions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
4 participants
You can’t perform that action at this time.