babel: Parser `decorators` plugin option `decoratorsBeforeExport` no longer defaulting

Bug Report

Current Behavior In a recent v7 release (maybe even the final?), the parser decorators plugin option decoratorsBeforeExport no longer defaults as it used to.

const { parse } = require('@babel/core')

const result = parse(code, {
  parserOpts: {
    plugins: [
      'decorators'
    ]
  }
})

Results in an error:

/Users/jaydenseric/Sites/demo/node_modules/@babel/core/lib/transformation/normalize-file.js:209
    throw err;
    ^

Error: The 'decorators' plugin requires a 'decoratorsBeforeExport' option, whose value must be a boolean.

This is unexpected, as the decoratorsBeforeExport option is meant to default to false. Manually providing the same value as the supposed default works:

  const result = parse(code, {
    parserOpts: {
      plugins: [
-       'decorators'
+       ['decorators', { decoratorsBeforeExport: false }]
      ]
    }
  })

Expected behavior/code A clear and concise description of what you expected to happen (or code).

Babel Configuration (.babelrc, package.json, cli command)

N/A.

Environment

  • Babel version(s): v7.0.0
  • Node/npm version: Node.js v10.9.0, npm v6.4.0
  • OS: macOS
  • Monorepo [e.g. yes/no/Lerna]: No
  • How you are using Babel: [e.g. cli, register, loader]: API

Possible Solution

Additional context/Screenshots

About this issue

  • Original URL
  • State: closed
  • Created 6 years ago
  • Reactions: 14
  • Comments: 29 (12 by maintainers)

Commits related to this issue

Most upvoted comments

I’m struggling with this right now, when I set this:

      [
        require('@babel/plugin-proposal-decorators'),
        { decoratorsBeforeExport: false, legacy: true }
      ],

OR

      [
        require('@babel/plugin-proposal-decorators'),
        { decoratorsBeforeExport: true, legacy: true }
      ],

For both I get the same error 'decoratorsBeforeExport' can't be used with legacy decorators.

if I remove the legacy flag, like this:

      [
        require('@babel/plugin-proposal-decorators'),
        { decoratorsBeforeExport: false }
      ],

I get “The new decorators proposal is not supported yet. You must pass the "legacy": true option to @babel/plugin-proposal-decorators”.

if I remove the decoratorsBeforeExport entirely and just do the legacy flag,

[require('@babel/plugin-proposal-decorators'), { legacy: true }],

I am able to proceed…

However this does now cause errors with using decorators and then using export default. I’m aware the spec is ‘still in flux’ but what is the way to configure this where I can use decorators like

@something
export default class MyClass

Is this no longer able to be done?

recently was getting problem with this error and installed npm install --save-dev @babel/plugin-proposal-decorators and setup "babel": { "plugins": [ [ "@babel/plugin-proposal-decorators", { "legacy": true } ] ], "presets": [ "react-app" ] },

this run my code with some errors, but app was working, I’m a beginner, so hope this comment is relevant

Yes, please explain how to resolve this with a webpack config. I dont’ even know where to start with this error.

For would be Googler’s and create-react-app users.

Create your create-react-app.

Then eject the project:

yarn eject

Add mobx, mobx-react and the decorator plugin:

yarn add @babel/plugin-proposal-decorators mobx mobx-react

Then in your package.json you’ll see:

"babel": {
  "presets": [
    "react-app"
  ]
}

Just update it to:

"babel": {
  "plugins": [
    [
      "@babel/plugin-proposal-decorators",
      {
        "legacy": true
      }
    ]
  ],
  "presets": [
    "react-app"
  ]
}

You can run npx nls why @babel/plugin-proposa-decorators to see why it is installed.

This issue should not have been closed, since the docs are still incorrect:

screen shot 2018-08-30 at 5 58 02 pm

The decoratorsBeforeExport option does not default to false.

Sorry for the confusion, I get that old/new proposal doesn’t mean anything for many people.

The “old” proposal is the one y’all are used to: it’s the only one implemented in Babel and TypeScript. It’s the one supported by babel-plugin-transform-decorators-legacy and @babel/plugin-transform-decorators, { legacy: true }. In @babel/parser it is decorators-legacy.

The “new” proposal is currently only implemented in @babel/parser (using the decorators plugin) and in babel-eslint, because it uses @babel/parser. We are implementing it (https://github.com/babel/babel/pull/7976), and also the TypeScript team is.

The decoratorsBeforeExport option is only meaningful for the “new” version of the proposal because, as you noted, there isn’t consensus yet. You can’t really use it in @babel/plugin-proposal-decorators because #7976 has not been merged yet, but you can use it in the @babel/parser’s decorators plugin.


with this plugin (@babel/plugin-proposal-decorators) can you do decorators like export default class Thing at all? you could in the beta version, was this removed?

You still can, the old behavior hasn’t changed. We only require the legacy option now:

const out = babel.transformSync(
  `
  @decorator
  export default class Foo {}
  `,
  {
    plugins: [
      [
        require("./packages/babel-plugin-proposal-decorators"),
        { legacy: true },
      ],
    ],
  }
);

console.log(out.code);

logs

var _class;

let Foo = decorator(_class = class Foo {}) || _class;

export { Foo as default };

could this simply be a problem with babel-eslint @9 ? where it is indeed parsing, but somehow the linter is throwing anyways? (maybe there is non parity between the linter and parser?)

In babel-eslint you have to opt-in to use the “old” proposal: in your eslint config, you should have something like this:

{
  parserOptions: {
    ecmaFeatures: {
      legacyDecorators: true
    }
  }
}

@the-simian I had you same problem, solved with @nicolo-ribaudo suggestion, change you eslint config:

    "eslintConfig": {
        "parser": "babel-eslint",
        "parserOptions": {
            "ecmaVersion": 2019,
            "sourceType": "module",
            "impliedStrict": true,
            "ecmaFeatures": {
                "jsx": true,
                "impliedStrict": true,
                "globalReturn": false,
                "experimentalObjectRestSpread": true,
                "legacyDecorators": true
            }
        },
        "env": {
            "browser": true,
            "serviceworker": true,
            "node": true,
            "jest": true,
            "es6": true
        },
        "plugins": [
            "react",
            "jest"
        ],
        "extends": [
            "eslint:recommended",
            "plugin:react/recommended",
            "plugin:jest/recommended"
        ],
        "rules": {
            "no-console": "off"
        }
    },

Fixed:

image

Sorry for any confusion the docs caused, as you can imagine… lots of moving parts leading up to shipping 7!

The doc is not fixed. It still says decoratorsBeforeExport defaults to false.

screen shot 2018-09-09 at 12 59 09

@nicolo-ribaudo I’ll answer your questions first: I am indeed using @babel/plugin-proposal-decorators at 7.0.0. I was using this in the 7 beta as well. I am using babel-eslint at 9.0.0 also.

I am a bit confused on what is meant about the new/old proposal. I have been using this ‘new’ proposal lib and only with the release of 7.0.0 did it break. It was working with beta-49+ as far as i can recall. I’m using and have been using the new behavior. However, I am not sure what the expectation right now in this proposal plugin should be. I was under the impression that there was no consensus yet on before or after export (such as in this thread) https://github.com/tc39/proposal-decorators/issues/69 and that the plugin you’ve authored here allowed the enduser to configure, via a flag (decoratorsBeforeExport).

Regardless, rather than referencing these confusing threads with hundreds of back-and-forth comments, more directly I am asking :

  • with this plugin (@babel/plugin-proposal-decorators) can you do decorators like export default class Thing at all? you could in the beta version, was this removed?
  • if not, can you post a very very small snippet of a decorator that this plugin actually accepts so I understand ‘code first’ what should actually be written with this plugin ?
  • could this simply be a problem with babel-eslint @9 ? where it is indeed parsing, but somehow the linter is throwing anyways? (maybe there is non parity between the linter and parser?)

I’ve already converted my codebase to

@decorator
class Thing{}
export default Thing

I’ve been able to move past, but this was really time consuming, and to be honest I preferred the way it was beforehand.

Sorry to keep this going, but any answers you give help other folks besides myself reading this get some clarity. The decorators ‘situation’ is very confusing overall, even if you’re studiously reading the TC-39 threads (most people aren’t).

Thanks again for any replies, and I appreciate the effort on this project.