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

gatsby-node.js doesn't allow ES6 import #7810

Closed
olivierpascal opened this issue Sep 2, 2018 · 52 comments
Closed

gatsby-node.js doesn't allow ES6 import #7810

olivierpascal opened this issue Sep 2, 2018 · 52 comments

Comments

@olivierpascal
Copy link

Description

gatsby-node.js doesn't allow ES6 javascript.

Steps to reproduce

gatsby-node.js:

import myOnCreatePage from './gatsby/node/onCreatePage';
export const onCreatePage = myOnCreatePage;

Expected result

gatsby-node.js should be transpiled and allow ES6 like gatsby-ssr.js or gatsby-browser.js.

Actual result

Error

Error: <root>/gatsby-node.js:1
SyntaxError: Unexpected token import

Environment

  System:
    OS: macOS High Sierra 10.13.6
    CPU: x64 Intel(R) Core(TM) i7-6567U CPU @ 3.30GHz
    Shell: 3.2.57 - /bin/bash
  Binaries:
    Node: 8.10.0 - ~/.nvm/versions/node/v8.10.0/bin/node
    Yarn: 1.9.4 - /usr/local/bin/yarn
    npm: 6.4.1 - ~/.nvm/versions/node/v8.10.0/bin/npm
  Browsers:
    Chrome: 68.0.3440.106
    Firefox: 61.0.2
    Safari: 11.1.2
  npmPackages:
    gatsby: next => 2.0.0-rc.5 
    gatsby-source-filesystem: next => 2.0.1-rc.1 
  npmGlobalPackages:
    gatsby-cli: 1.1.58
@KyleAMathews
Copy link
Contributor

That file is run by node.js so it supports whatever the version of node you're using supports. Es6 module support in node is still a wip https://medium.com/@giltayar/native-es-modules-in-nodejs-status-and-future-directions-part-i-ee5ea3001f71

@hsribei
Copy link
Contributor

hsribei commented Sep 17, 2018

I'm also running into this. I need to use gatsby-mdx/mdx-renderer, and even if I require it, the required file itself uses ES6 module syntax and breaks. Is there a way to change configuration to have gatsby-node.js go through babel? It would be cool to be able to use JSX inside it as well, though less urgent for me.

@SachaG
Copy link
Contributor

SachaG commented Oct 10, 2018

What would be the steps to enable import/export support in gatsby-node.js? The Medium post linked to mentions using .mjs files but I don't think that will work with Gatsby?

@iray-tno
Copy link

Is there a way to use babel-node instead of node?

@nikoladev
Copy link
Contributor

nikoladev commented Dec 24, 2018

I use esm for this and it works so far. Here's what I did:

  1. Install esm (npm i esm)
  2. Create a file called gatsby-node.esm.js in your root folder (the same folder that contains gatsby-node.js)
  3. Move all your code from from gatsby-node.js to gatsby-node.esm.js
  4. Replace all the code in gatsby-node.js with the following:
    require = require('esm')(module)
    module.exports = require('./gatsby-node.esm.js')
  5. Use import in gatsby-node.esm.js all you want 🎉

@KyleAMathews Is there anything dangerous about doing it this way? Because if it's safe I could add it to the docs :)

@KyleAMathews
Copy link
Contributor

This pattern definitely works @nikoladev! Not sure where it'd go in the docs though. Any ideas @gatsbyjs/docs?

@SachaG
Copy link
Contributor

SachaG commented Dec 25, 2018

Here's how I did it:

require('babel-register')({
  presets: [ 'env' ]
})
require('babel-polyfill')
module.exports = require(`./gatsby-node.mjs`)

It seems to work well enough but I wonder if it might not mess with the cache? I think the cache is supposed to reset when you modify gatsby-node.js but I've been running into issues with that, although I don't know if they're related.

@nikoladev
Copy link
Contributor

@KyleAMathews How about under Sourcing Content and Data? At least that's the reason I used it for.

@SachaG
Copy link
Contributor

SachaG commented Dec 27, 2018

It's kind of a different debate, but any chance using import could be supported out of the box? I feel like for larger Gatsby projects, what happens in gatsby-node.js is almost as important as your actual front-end and it sucks not to be able to code in a modern way with import, async/await, etc. without extra hacks.

@codeithuman
Copy link

@KyleAMathews, is there a way to require a local ES6 file? For example, I have a src/utils/article.js file that looks like the following:

// src/utils/article.js
import { format } from 'date-fns'

export const createArticleUrl = (a) => (
  `/${format(a.publishDate, 'YYYY')}` +
  `/${format(a.publishDate, 'MM')}` +
  `/${format(a.publishDate, 'DD')}` +
  `/${a.category.urlSlug}` +
  `/${a.urlSlug}`
)

and the my gatsby-node.js file:

// gatsby-node.js
...
const { createArticleUrl } = require(`./src/utils/article`)
...

And I get the error:

  Error: .../src/utils/article.js:1
  (function (exports, require, module, __filename, __dirname) { import { format } from 'date-fns'
                                                                ^^^^^^
  SyntaxError: Unexpected token import

Any ideas? I use the function to create the url for our articles/posts and would like to import it like I do in my React components. Thanks!

@codeithuman
Copy link

codeithuman commented Jan 23, 2019

I was able to resolve my issue by using ES5 in my src/utils/article.js file, like so:

// src/utils/article.js
const { format } = require('date-fns')

var createArticleUrl = function (a) {
  return (
    `/${format(a.publishDate, 'YYYY')}` +
    `/${format(a.publishDate, 'MM')}` +
    `/${format(a.publishDate, 'DD')}` +
    `/${a.category.urlSlug}` +
    `/${a.urlSlug}`
  )
}

module.exports.createArticleUrl = createArticleUrl

and then gatsby-node.js, like this:

// gatsby-node.js
...
const { createArticleUrl } = require(`./src/utils/article`)
...

I can also import createArticleUrl like normal in ES6 files, import { createArticleUrl } from '../utils/article'.

@WeZZard
Copy link

WeZZard commented Jan 24, 2019

I use esm for this and it works so far. Here's what I did:

  1. Install esm (npm i esm)
  2. Create a file called gatsby-node.esm.js in your root folder (the same folder that contains gatsby-node.js)
  3. Move all your code from from gatsby-node.js to gatsby-node.esm.js
  4. Replace all the code in gatsby-node.js with the following:
    require = require('esm')(module)
    module.exports = require('./gatsby-node.esm.js')
  5. Use import in gatsby-node.js all you want 🎉

@KyleAMathews Is there anything dangerous about doing it this way? Because if it's safe I could add it to the docs :)

Is the 5th "Use import in gatsby-node.esm.js all you want"?

@nikoladev
Copy link
Contributor

@WeZZard You're totally right! I'll fix it in my post.

@reaktivo
Copy link

Another way I found this to work was by updated your package.json with the following:

  "scripts": {
    "build": "npx --node-arg '-r esm' gatsby build",
    "develop": "npx --node-arg '-r esm' gatsby develop",
    "start": "npx --node-arg '-r esm' npm run develop",
    "serve": "npx --node-arg '-r esm' gatsby serve",
    "test": "echo \"Write tests! -> https://gatsby.app/unit-testing\""
  },

No need to create new files

@rotexhawk
Copy link
Contributor

@reaktivo your scripts work locally but I wasn't able to get it to work with netlify. Are u able to deploy your site to netlify with npx?

@reaktivo
Copy link

@rotexhawk Just pushed an example and it worked fine:

https://github.com/reaktivo/gatsby-esm/
https://gatsby-esm-example.netlify.com/

Make sure you're running npm install --save-dev esm before and that your build config runs npm run build instead of gatsby build

Check out this commit: reaktivo/gatsby-esm@cf62025

@rotexhawk
Copy link
Contributor

Thanks, I have installed esm. the problem is that netlify doesn't have access to npx, says command failed. I specified my node version but that didn't help.

@reaktivo
Copy link

@rotexhawk That's really weird, considering the project that I sent you was deployed to Netlify... anyway, if you need to avoid npx, the following might work:

  "scripts": {
    "build": "node -r esm ./node_modules/bin/gatsby build",
    "develop": "node -r esm ./node_modules/bin/gatsby develop",
    "start": "npm run develop",
    "serve": "node -r esm ./node_modules/bin/gatsby serve",
    "test": "echo \"Write tests! -> https://gatsby.app/unit-testing\""
  },

@reaktivo
Copy link

@rotexhawk Got in touch with the Netlify team, you might also need to specify the NPM_VERSION, see https://www.netlify.com/docs/build-settings/#node-npm-and-yarn

@rotexhawk
Copy link
Contributor

@reaktivo will do. thanks for all the help.

@ArcanisCz
Copy link

ArcanisCz commented Mar 21, 2019

I would strongly consider adding that esm approach to documentation, since Gatsby is indicating es6 modules should work inside gatsby-node.js file. This error message is printed, when you mix modules:

error This plugin file is using both CommonJS and ES6 module systems together which we don't support. You'll need to edit the file to use just one or the other.

It clearly indicates, you CAN use es6 modules.

erikthedeveloper added a commit to erikthedeveloper/erikaybar.name-gatsby that referenced this issue Mar 29, 2019
ardillan added a commit to ardillan/torlavega that referenced this issue Oct 5, 2019
Gatsby no permite incluir importaciones en su fichero Node. Esta solucíón está sacada de un hilo de Github gatsbyjs/gatsby#7810 (comment), donde el paquete incluido resuelve el problema permitiendo realizar importaciones.
@TidyIQ
Copy link

TidyIQ commented Nov 11, 2019

esm doesn't seem to work when using yarn workspaces. It says it can't find the workspace module.

@TidyIQ
Copy link

TidyIQ commented Nov 11, 2019

Actually it seems like it only works for the first level import in gatsby-node.ems.js, not for anything that the imported component also imports.

For example,

./gatsby-node.ems.js

import foo from "./foo";
const fooText = foo + " more text";

./foo

import bar from "bar";
const foo = bar("whatever");
export default foo;

Throws an error:

Error in "C:\...\gatsby-node.js": Cannot find module 'bar'

@dandv
Copy link
Contributor

dandv commented Nov 11, 2019

Since Node modules are almost there, I wanted to use node with --experimental-modules instead of esm.

I changed scripts.start to "node --experimental-modules ./node_modules/.bin/gatsby develop", renamed gatsby-node.js to gatsby-node.mjs, but I get

Error in "~/website/gatsby-node.mjs": Must use import to load ES Module: ~/website/gatsby-node.mjs

Error: [ERR_REQUIRE_ESM]: Must use import to load ES Module: ~/website/gatsby-node.mjs

@caycecollins
Copy link

caycecollins commented Jun 3, 2020

@wesbos @reaktivo are you able to use that fix still with the latest gatsby (2.22.17 in my case)?

I've had it working without any issues using that solution, but updated gatsby today and started getting the import errors again:

> npx --node-arg '-r esm' gatsby develop

ERROR #10123  CONFIG

We encountered an error while trying to load your site's gatsby-config. Please fix the error and try again.

Error: /project/gatsby-config.js:1
(function (exports, require, module, __filename, __dirname) { import urlJoin from "url-join";
                                                              ^^^^^^
SyntaxError: Cannot use import statement outside a module```

@dandv
Copy link
Contributor

dandv commented Jun 3, 2020

As an alternative, you may want to use TypeScript for gatsby-* files.

@wesbos
Copy link
Contributor

wesbos commented Jun 10, 2020

my esm trick above just stopped working. I even rolled back gatsby and node version and it persists.

Detailed it here if anyone has the same issue: reaktivo/gatsby-esm#1

@caycecollins did you find a fix?

@caycecollins
Copy link

caycecollins commented Jun 17, 2020

@wesbos I ended up reverting back to es5 require for now :(

EDIT: I just noticed your latest fix here #24925 ... I'll give that a try!

@semireg
Copy link

semireg commented Jun 19, 2020

Just a heads up that I struggled with this for an hour and finally figured out that no matter what I put in my package.json for build, the Netlify UI configuration was taking precedence. It wasn't until I added a netlify.toml that this became apparent. Moral of the story, edit your Netlify UI build settings, or clear them out and toss it in the config. I prefer the latter. 😄

[build]
  command = "npm run build"
  publish = "public"

It's worth noting that yes, this worked for me:

"build": "NODE_OPTIONS='-r esm' gatsby build",

@machineghost
Copy link

machineghost commented Jun 22, 2020

Wow, I understand change is hard, but ES Modules are Javascript now, so it's really disappointing to see (for whatever totally valid reasons) the maintainers fighting against supporting Javascript ... especially when JDalton and his esm package makes it so easy!

@machineghost
Copy link

machineghost commented Jun 22, 2020

P.S. A few relevant details that you might not be aware of ...

  • This is a two-line fix. Unless Gatsby has multiple "entry points", the entire PR to fix this will be three lines: the package.json entry for the esm package, and the lines:
require = require("esm")(module/*, options*/)
module.exports = require("./main.js")
  • This module is already widely used in major libraries like Knex. There are literally 135 ... thousand libraries depending on it already!

  • It was written by the creator of Lodash, so this is not some Junior Engineer's first NPM project: it's a serious library written by a seasoned professional

  • It's completely backwards-compatible: unless someone uses import or export in their non-ES Module code (and I'm pretty sure those have been JS banned keywords since the dawn of time) all existing code will continue working the same

  • if there was any kind of performance concern it's trivially easy to "gate keep" this feature with a command line argument (knex opted to go this route, for instance)

So it's "gain modern Javascript language features with three lines of code" or ... fight it for ? benefit.

If there's interest, I'd be more than happy to submit a PR :)

@Aditya94A
Copy link

Aditya94A commented Sep 8, 2020

Can someone provide a final solution and lock this thread?

Hate doing this dance of skimming all comments in really important but seemingly closed issues where conversation is still happening and trying to sift through all comments to see which one has the most thumbs ups and is likely to be the best solution 😔

@machineghost
Copy link

machineghost commented Sep 8, 2020

Like I said, the hard part is not making the esm module work: it's designed to make things extremely simple. I would submit a PR myself if I knew anything about the Gatsby architecture (and again, to see another major library use it just look at Knex).

The hard part is just getting a maintainer with that knowledge to care :(

You'd think that even if every maintainer had a personal hated for modern JS module syntax, they still could at least appreciate their users' desire for it ... but the refusal to even re-open this issue, let alone fix it (again, possibly with only two lines of code) suggests otherwise. Given how great this team has been with other issues, it's honestly confusing to me.

@maulerjan
Copy link

Like I said, the hard part is not making the esm module work: it's designed to make things extremely simple. I would submit a PR myself if I knew anything about the Gatsby architecture (and again, to see another major library use it just look at Knex).

The hard part is just getting a maintainer with that knowledge to care :(

You'd think that even if every maintainer had a personal hated for modern JS module syntax, they still could at least appreciate their users' desire for it ... but the refusal to even re-open this issue, let alone fix it (again, possibly with only two lines of code) suggests otherwise. Given how great this team has been with other issues, it's honestly confusing to me.

Any word from maintainers on this subject, please?

@lrq3000
Copy link

lrq3000 commented Dec 28, 2020

ERROR #10123 CONFIG

We encountered an error while trying to load your site's gatsby-config. Please fix the error and try again.

Error: /project/gatsby-config.js:1
(function (exports, require, module, __filename, __dirname) { import urlJoin from "url-join";
^^^^^^
SyntaxError: Cannot use import statement outside a module```

Just got bitten by this but in gatsby-node.js. I am not a javascript developer so I don't care much about ideology, but the ESM import syntax seemed so natural to me (I'm more experienced in Python, which has a very close import syntax) that I thought it was native to modern JS. I just want to extend Gatsby to my needs, and it feels very weird when you can use ESM everywhere in Gatsby (it's even the format used in the documentation) but not in some specific files at the root.

Whatever is your ideology, I think we can agree consistency is always a good practice. And here the import format is inconsistent within gatsby.

@logemann
Copy link

i also think this is kind of important enough to be revisited.

@wesbos
Copy link
Contributor

wesbos commented Jan 11, 2021

It's not worth implementing the esm module into Gatsby - that is a great solution for now, but the future is using native esm in Node by either:

  1. Supporting "type": "module" in package.json, allowing up to use the import syntax in gatsby-node
  2. Support .mjs for gatsby-node.js

We will have some growing pains as node moves to esm and we wait for lots of packages to catch up, but as long as authors know that as well at the node version limitations, we should be able to at least use .mjs

@machineghost
Copy link

machineghost commented Jan 11, 2021

we should be able to at least use .mjs

The .mjs extension is hot garbage. Please don't force every Gatsby developer to use it: the Node org added the other options precisely because of all of the fallback from the Node' orgs misguided attempt to make everyone use "Michael Jackson Script".

@wesbos
Copy link
Contributor

wesbos commented Jan 11, 2021

Then use "type": "module" in your package.json and use .cjs for any legacy stuff.

There are only two options - gatsby isn't going to force you to do anything - this is a standard in Node.js

@machineghost
Copy link

machineghost commented Jan 11, 2021

"type": "module" is great; I just got concerned by the bit:

at least use .mjs

Thanks :)

@wesbos
Copy link
Contributor

wesbos commented Jan 11, 2021

mjs is going to be needed in some cases where you have a massive commonjs project. You can't just snap your fingers and have the thing swich over. you need to do it bit by bit, and opting into esm on a per file basis is a good solution until you can get there.

I realize it's an ugly extension (?) and it's funny to say michael jackson script, but that is a good option going forward

@machineghost
Copy link

machineghost commented Jan 11, 2021

Sure, but asking a fully working ESM-using app to rename all its files just to use modern JS syntax is complete idiocy.

Again, the Node org provided options for a reason, and my only concern was making sure Gatsby supports those options (or better yet, supports the esm package ... but that doesn't sound like it's happening). And again, I only said anything because you yourself carved out the possibility of not doing so:

we should be able to at least use .mjs

(which clearly implies not supporting the other option)

@machineghost
Copy link

Man, what a welcoming community Gatsby has. A user asks for something basic (like support for the JS language) and this is the response they get.

@alishaevn
Copy link

alishaevn commented Apr 14, 2021

It's worth noting that yes, this worked for me:

"build": "NODE_OPTIONS='-r esm' gatsby build",

this also worked for me!

make sure to install the package first: yarn add esm

package.json

"scripts": {
	"start": "NODE_OPTIONS='-r esm' gatsby develop -p 9988 -o",
	"build": "NODE_OPTIONS='-r esm' gatsby build",
	"serve": "NODE_OPTIONS='-r esm' gatsby serve -p 9500 -o"
},

gatsby-config

import { config } from './content/meta/config'
import emoji from 'remark-emoji'

gatsby-node

import { createFilePath } from 'gatsby-source-filesystem'
import path from 'path'

@01binary
Copy link

oops @alishaevn did you mean yarn add esm? It's cool that I learned about https://www.npmjs.com/package/ems though.

@alishaevn
Copy link

yes @01binary that is what I meant! updated. 🙂

@LekoArts
Copy link
Contributor

LekoArts commented Feb 7, 2022

Please go to #34613 and you can use TypeScript with Gatsby. By the time you're reading this it's also possible that the feature already was shipped in Gatsby 4. If that is the case the RFC will be marked as done.

You can also expect ESM support (through this) very soon, please follow #31599 for progress. Again, if the feature is shipped it'll be noted in the discussion.

@gatsbyjs gatsbyjs locked as resolved and limited conversation to collaborators Feb 7, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests