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

Class constructor Model cannot be invoked without 'new' #388

Closed
amiuhle opened this issue May 23, 2017 · 40 comments
Closed

Class constructor Model cannot be invoked without 'new' #388

amiuhle opened this issue May 23, 2017 · 40 comments

Comments

@amiuhle
Copy link

amiuhle commented May 23, 2017

I'm getting the following error after upgrading to 0.8.0:

TypeError: Class constructor Model cannot be invoked without 'new'
  at new UserModel (/path/to/project/src/server/graphql/models/User/userModel.js:29:103)
  at Function.fromDatabaseJson (/path/to/project/node_modules/objection/lib/model/Model.js:443:19)
  at Object.createModels (/path/to/project/node_modules/objection/lib/queryBuilder/QueryBuilder.js:826:41)
  at Object.tryCatcher (/path/to/project/node_modules/bluebird/js/release/util.js:16:23)
  at Promise._settlePromiseFromHandler (/path/to/project/node_modules/bluebird/js/release/promise.js:512:31)
  at Promise._settlePromise (/path/to/project/node_modules/bluebird/js/release/promise.js:569:18)
  at Promise._settlePromise0 (/path/to/project/node_modules/bluebird/js/release/promise.js:614:10)
  at Promise._settlePromises (/path/to/project/node_modules/bluebird/js/release/promise.js:693:18)
  at Async._drainQueue (/path/to/project/node_modules/bluebird/js/release/async.js:133:16)
  at Async._drainQueues (/path/to/project/node_modules/bluebird/js/release/async.js:143:10)
  at Immediate.Async.drainQueues (/path/to/project/node_modules/bluebird/js/release/async.js:17:14)
  at runCallback (timers.js:672:20)
  at tryOnImmediate (timers.js:645:5)
  at processImmediate [as _immediateCallback] (timers.js:617:5)
@koskimas
Copy link
Collaborator

koskimas commented May 23, 2017

EDIT:
As of objection 1.5.0 this problem should no longer exist. But please, stop transpiling your backend to ES5 in the year 2019! That's idiotic! Target node 6 in your babel config instead. Node 6, that has everything objection needs, was released four years ago! Surely you are not using node versions < 6 are you? Transpiling to ES5 will, among other things, use regenerator to rewrite your async/await code into a switch/case state machine that adds quite a bit of overhead.
END EDIT

Yep, please read the change log. Legacy node versions (0.10, 0.12) are no longer supported. You also need to migrate from the legacy ES5 inheritance to class and extend keywords. This is because of the way classes are implemented in Ecmascript. You cannot invoke class constructors without new and therefore this doesn't work:

class Model {

}

function UserModel() {
  // You cannot do this.
  Model.apply(this, arguments);
}

And since objection Model is a native ES2015 class, you get that error. If you are using Babel you need to remove the babel-plugin-transform-es2015-classes plugin that does the conversion. You don't need it anyway with node >= 4.0.0.

Check out the ESNext example project as an example of how to setup babel.

@amiuhle
Copy link
Author

amiuhle commented May 24, 2017

Thanks. I did look at the changelog, maybe you should be more explicit about Babel.

I have shared code between backend and frontend, guess I'll have to do some refactoring before I can upgrade to 0.8.x.

@koskimas
Copy link
Collaborator

You're right, I'll add a mention about Babel & friends to the change log. I'll also leave this open for other people to find.

@juhaelee
Copy link

juhaelee commented Jun 6, 2017

You can also make it so that babel is using your node version by doing something like this:

{
  "presets": [
    ["env", {
      "targets": {
        "node": "current"
      }
      }],
    "stage-1"
  ],
  "plugins": []
}

@koskimas
Copy link
Collaborator

koskimas commented Jun 6, 2017

@juhaelee Awesome, didn't know about that! Do you happen to know which Babel versions support that?

@juhaelee
Copy link

juhaelee commented Jun 6, 2017

@koskimas I believe you can use it as long as you're using Babel 6. You just need to use the env preset package instead of es2015

@koskimas
Copy link
Collaborator

I think this can be closed now that most people have migrated to objection 0.7.

@jnelken
Copy link

jnelken commented Jan 13, 2018

I'm using babel-register, and have node_modules ignored by babel with this flag:

  ignore: /\/(build|node_modules)\/(?!objection)/,
  presets: [...

this means babel compiles my code on the fly, except for things being imported from my build/node_modules folder.

However, it turns out that objection does not compile into something es6+ compatible, so writing something like class User extends Model caused this error to appear.

Changing the babel config to ignore node_modules EXCEPT for objection made everything work (meaning it DID compile the objection library for me, but not other modules)

  ignore: /\/(build|node_modules)\/(?!objection)/,
  presets: [...

As I learned from this comment (and the ones below)

My versions:
Node v 7.5, babel 6, objection 0.9

@koskimas
Copy link
Collaborator

@jnelken I don't know if I misunderstood something, but you don't need to transpile objection! The problem is not objection code but the way babel emulates classes in ES5. What you need to do is to turn off the class emulation since node 7.5 fully supports native classes. You don't need that emulation. That's what the env preset does.

@jnelken
Copy link

jnelken commented Feb 3, 2018

@koskimas Ok, so it seems the react-app plugin I use for server-side rendering my react app is causing this, most likely by simulating classes as you mentioned. If I turn it off, I experience no problem. However I'm going to need it on and the quickest workaround seems to be the one I mentioned above (by transpiling the library) :/

@earllee
Copy link

earllee commented Mar 9, 2018

Hi, I'm trying to use objection.js in a next.js project but am also running into this problem with objection@1.0.0 and next@5.0.0. I'm running Node v9.6.0.

It probably has something to do with their babel preset next/babel but am not sure how to fix this.

Looks like this is the preset: https://github.com/zeit/next.js/blob/canary/server/build/babel/preset.js

@newhouse
Copy link
Contributor

newhouse commented Mar 9, 2018

I'm not that familiar with next, but I did have this issue when running my Objection code in the server for testing with nightwatch.

For me, I had to execute require('babel-core/register'); after I'd required all of my Objection code. I ended up fixing it and not worrying much about how/why too deeply, but there's also a bunch of stuff I found back then in this search that has to do with when/how to configure babel/es2015 that may help you, too:
https://www.google.com/search?q=nightwatch+babel-core%2Fregister&oq=nightwatch+babel-core%2Fregister&aqs=chrome..69i57j0j69i65l3j0.4102j0j7&sourceid=chrome&ie=UTF-8

@vjpr
Copy link

vjpr commented Mar 24, 2018

Ran into this too. Objection should export ES5 code (perhaps something like objection/es5), because most people are using a transpiler, and this forces the user to modify their babel config which may affect other things.

@koskimas
Copy link
Collaborator

World should be ready for ES6 classes by now. We will not add support for ES5.

@aldofunes
Copy link

I am trying to use objection.js with Node in AWS Lambda (Node 8.10). I struggled for a few hours until I hit the jackpot. I tried several configuration recommendations and what finally did the trick was excluding the babel-plugin-transform-classes in the preset-env options. I share this for future reference, since it may help others searching for the same solution.

Cheers!

// webpack.config.js

...

{
  test: /\.(js|jsx)$/,
  exclude: /node_modules/,
  use: {
    loader: 'babel-loader',
    options: {
      presets: [
        [
          '@babel/preset-env',
          {
            target: { node: '8.10' }, // Node version on AWS Lambda
            modules: false,
            exclude: ['babel-plugin-transform-classes'],
          },
        ],
      ],
      plugins: [
        '@babel/plugin-proposal-class-properties',
        '@babel/plugin-proposal-object-rest-spread',
        '@babel/plugin-transform-runtime',
      ],
    },
  },
},

...

@inversion
Copy link

inversion commented May 16, 2018

Just in case it helps anyone, I had a lot of trouble with @babel/preset-env and objection because my .browserslistrc was being read and included in its targets, meaning the transform-classes plugin was being used for my node 8.9.4 code when in fact no transpilation of classes was necessary.

There is an ignoreBrowserslistConfig option you can use to avoid this.

@bahmutov
Copy link

If using TypeScript compiler, set output to at least es2015 in tsconfig.json

{
  "compilerOptions": {
     "target": "es2015"
  }
}

@oliviertassinari
Copy link

oliviertassinari commented Jul 20, 2018

I'm facing the same issue with Next.js. We use a single .babelrc inside a mono git repository. The web (Next.js) and api (Objection) servers live under two different folders, they share the same configuration.

I agree with @vjpr, I think that it would be simpler to publish a ES5 code in the npm package. I'm gonna start looking for a solution now.

@oliviertassinari
Copy link

oliviertassinari commented Jul 20, 2018

1 hour later, my solution:

babelrc.js

const node = [`${__dirname}/src/api`]

module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        targets: {
          ie: 11,
          edge: 14,
          firefox: 45,
          chrome: 49,
          safari: 10,
          node: '6.11',
        },
      },
    ],
  ],
  overrides: [
    {
      test: filename => node.some(prefix => filename.startsWith(prefix)),
      presets: [
        [
          '@babel/preset-env',
          {
            targets: {
              node: 'current',
            },
          },
        ],
      ],
    },
  ],
}

@mhaagens
Copy link

mhaagens commented Jul 24, 2018

Having the same issue. Cannot for the life of me get it to work.
Webpack babel-loader on node 10.7.0;

EDIT: It was my .browserslistrc that caused the error as noted by @inversion above.
Adding ignoreBrowserslistConfig": true to my babel config for the server solved the issue.

{
  test: /\.js?$/,
  exclude: /node_modules/,
  use: {
    loader: "babel-loader",
    options: {
      babelrc: false,
      presets: [
        [
          "@babel/preset-env",
          {
            modules: false,
            targets: {
              node: "current"
            }
          }
        ],
        [
          "@babel/preset-stage-0",
          {
            decoratorsLegacy: true,
            pipelineProposal: "minimal"
          }
        ],
        "@babel/preset-react"
      ],
      plugins: [
        ...(!WEBPACK_ENV.PRODUCTION ? ["react-hot-loader/babel"] : []),
        "react-loadable/babel",
        [
          "babel-plugin-styled-components",
          {
            ssr: true,
            displayName: !WEBPACK_ENV.PRODUCTION
          }
        ]
      ]
    }
  }
}

@vjpr
Copy link

vjpr commented Jul 24, 2018

@koskimas After all the reports, don't you think its worth transpiling it? I don't think the world is ready just yet. Most people run their code through babel, and its tricky to ignore one file from transpilation. It also entails having to ignore all the files that touch objection. Objection is the only lib in my stack that I need this complicated workaround for right now.

@mhaagens
Copy link

@vjpr Don't know your environment, but @inversion had a fix that worked for me, the error was unrelated to objection.

@koskimas
Copy link
Collaborator

koskimas commented Jul 24, 2018

@vjpr No I don't think we should transpile objection. You should open issues in whatever project is preventing you from using libraries that use the class keyword.

@heisian
Copy link
Contributor

heisian commented Jul 24, 2018

I've tried babel transpilation for about a year but mainly do server-side dev and was pretty unpleased with the results.. until the ECMAScript guys can solve their (several year) battle of .js/.mjs, I'm sticking with common JS and "vanilla" node.

At any rate, classes are supported in most modern browsers: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes
And have been supported in Node since 6.4.0: https://node.green/#ES2015-functions-class

So perhaps I'm missing something here - but the majority of your babel issues seem to stem from mis-configurations.

@ericvicenti
Copy link

Yeah this is difficult. My JS environment is pretty crazy because I'm using Razzle for server-side rendering of a React app, and I use react-native-web to share code with iOS/Android with the same codebase.

Because I'm using Razzle, I don't have full access to my full webpack+babel config. Even if I could edit my config, it would feel hacky to carve out an exception for objection.

Long story short, I found it easier to fork and compile objection to ES5+CommonJS, so that I don't hit this error. If anybody else wants to use my compiled version, you can add the following to your package.json:

    "objection": "https://github.com/ericvicenti/objection.js",

@thenanyu
Copy link

thenanyu commented Dec 28, 2018

@ericvicenti I ended up doing something similar, thanks for the idea

"objection": "https://github.com/thenanyu/objection.js"

compiled using @babel/preset-env with default settings, as it seems to be the fashionable approach. I'm using NextJs and trying to convince webpack to do the right thing in that env was a huge timesink.

@Malouda
Copy link

Malouda commented Jan 12, 2019

I am trying to use objection.js with Node in AWS Lambda (Node 8.10). I struggled for a few hours until I hit the jackpot. I tried several configuration recommendations and what finally did the trick was excluding the babel-plugin-transform-classes in the preset-env options. I share this for future reference, since it may help others searching for the same solution.

Cheers!

// webpack.config.js

...

{
  test: /\.(js|jsx)$/,
  exclude: /node_modules/,
  use: {
    loader: 'babel-loader',
    options: {
      presets: [
        [
          '@babel/preset-env',
          {
            target: { node: '8.10' }, // Node version on AWS Lambda
            modules: false,
            exclude: ['babel-plugin-transform-classes'],
          },
        ],
      ],
      plugins: [
        '@babel/plugin-proposal-class-properties',
        '@babel/plugin-proposal-object-rest-spread',
        '@babel/plugin-transform-runtime',
      ],
    },
  },
},

...

This definitely helped me...

@vjpr
Copy link

vjpr commented Jan 18, 2019

This is so painful. I don't know any other library that is using untranspiled ES6 classes that you inherit from.

Using babel overrides is really frustrating, and every new environment has to deal with it. E.g. Ava test babel config, Wallaby test babel config, webpack config, and project babel config. There are so many issues open about this and

@vjpr
Copy link

vjpr commented Jan 18, 2019 via email

@elhigu
Copy link
Contributor

elhigu commented Jan 18, 2019

@vjpr if babel is giving you so much problems, why are you using it? Even node 6 LTS is going out of maintenance in April (if I remember correctly), so I don't see why babel targetting es5 is so necessary... 🤔

Other thing you could do is to provide your own transpiled objection version available.

@koskimas
Copy link
Collaborator

@vjpr Could you try out this commit in your package.json and import objection/babel instead of objection. I'm trying to support babel ES5 transpilation without actually transpiling objection.

@koskimas
Copy link
Collaborator

@vjpr This commit removes the need to require('objection/babel'). The normal import { something } from 'objection' should now work.

@koskimas
Copy link
Collaborator

koskimas commented Jan 20, 2019

@ericvicenti @thenanyu Could you also try pointing your package.json to this commit to see if it works with your setups without adding any special cases for objection?

@koskimas
Copy link
Collaborator

also @Malouda ⬆️

@vjpr
Copy link

vjpr commented Jan 20, 2019

@vjpr This commit removes the need to require('objection/babel'). The normal import { something } from 'objection' should now work.

@koskimas Cool! Seems to work. Can we get an npm published version?

@koskimas
Copy link
Collaborator

@vjpr I can release an RC version right now, but I want to run some additional tests before releasing 1.5.0 (I've rewritten the insertGraph/upsertGraph code and want to make sure I didn't break anything).

@koskimas
Copy link
Collaborator

You can install the RC version using npm install objection@next

@koskimas
Copy link
Collaborator

koskimas commented Jan 20, 2019

Oh crap, some tests are broken because of this and I also need to wrap other classes. I'll probably release the next RC during the next week.

@koskimas
Copy link
Collaborator

1.5.0-rc.5 is now released with the fix.

@koskimas
Copy link
Collaborator

And now the official 1.5.0 is released. No need for @next tag anymore.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests