gatsby-node.js
doesn't allow ES6 javascript.
gatsby-node.js
:
import myOnCreatePage from './gatsby/node/onCreatePage';
export const onCreatePage = myOnCreatePage;
gatsby-node.js
should be transpiled and allow ES6 like gatsby-ssr.js
or gatsby-browser.js
.
Error
Error: <root>/gatsby-node.js:1
SyntaxError: Unexpected token import
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
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
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.
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?
Is there a way to use babel-node
instead of node
?
I use esm for this and it works so far. Here's what I did:
esm
(npm i esm
)gatsby-node.esm.js
in your root folder (the same folder that contains gatsby-node.js
)gatsby-node.js
to gatsby-node.esm.js
gatsby-node.js
with the following:javascript
require = require('esm')(module)
module.exports = require('./gatsby-node.esm.js')
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 :)
This pattern definitely works @nikoladev! Not sure where it'd go in the docs though. Any ideas @gatsbyjs/docs?
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.
@KyleAMathews How about under Sourcing Content and Data? At least that's the reason I used it for.
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.
@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!
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'
.
I use esm for this and it works so far. Here's what I did:
- Install
esm
(npm i esm
)- Create a file called
gatsby-node.esm.js
in your root folder (the same folder that containsgatsby-node.js
)- Move all your code from from
gatsby-node.js
togatsby-node.esm.js
- Replace all the code in
gatsby-node.js
with the following:
js require = require('esm')(module) module.exports = require('./gatsby-node.esm.js')
- Use
import
ingatsby-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"?
@WeZZard You're totally right! I'll fix it in my post.
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
@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
?
@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: https://github.com/reaktivo/gatsby-esm/commit/cf620259ac8b118dea38b99409963cb26bf1b240
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.
@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\""
},
@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
@reaktivo will do. thanks for all the help.
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.
esm
doesn't seem to work when using yarn workspaces. It says it can't find the workspace module.
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'
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
Please have in mind that we don't officially support it and the workarounds mentioned here can only go so far. Maybe some of our packages are not yet compatible with this experimental node feature or it just won't work. We can revisit this topic when things are stable.
Now that ES modules are no longer experimental, should this issue be reopened?
They are still experimental and not quite finished. Just the flag has been removed
however the implementation remains experimental and subject to change
I dove deep into this, and imo it's not worth the pain yet. Wait for loaders to be implemented or use esm
package.
Has anyone found a solution using babel? It'd be great if I could drop my babel config in a gatsby project, and have it all work.
Using gatsby, but then having to go back to module.exports
really feels like a massive step back.
Modern web tech without the headache
-> not so much :(
npm i esm
and then modify your commands to look like this:
https://github.com/wesbos/awesome-uses/blob/master/package.json#L39-L42
@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```
As an alternative, you may want to use TypeScript for gatsby-*
files.
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: https://github.com/reaktivo/gatsby-esm/issues/1
@caycecollins did you find a fix?
@wesbos I ended up reverting back to es5 require for now :(
EDIT: I just noticed your latest fix here https://github.com/gatsbyjs/gatsby/issues/24925 ... I'll give that a try!
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",
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!
P.S. A few relevant details that you might not be aware of ...
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 :)
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 馃様
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.
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?
Most helpful comment
I use esm for this and it works so far. Here's what I did:
esm
(npm i esm
)gatsby-node.esm.js
in your root folder (the same folder that containsgatsby-node.js
)gatsby-node.js
togatsby-node.esm.js
gatsby-node.js
with the following:javascript require = require('esm')(module) module.exports = require('./gatsby-node.esm.js')
import
ingatsby-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 :)