Next.js: Resolve .jsx extension in webpack

Created on 4 Nov 2016  路  34Comments  路  Source: vercel/next.js

It's recommended to use the .jsx file extension for React components.

So, wouldn't it be great to add .jsx extension in webpack?

This will also help with editors doing syntax highlighting & linting.

Most helpful comment

+1 for .jsx extension support

All 34 comments

Interesting. Where did you get the information that .jsx is the recommended extension? I did a quick google search but couldn't find any official comments on this. I must admit that my google foo isn't the best.

Yea, I prefer .jsx simply for auto language selection in editors.

From airbnb style guide which is actually the mostly used in JavaScript projects linting.

@7s4r Ok, I know the airbnb style guide. What I was waiting for was a comment directly from facebook or babel. But sure the airbnb style guide is a good point. Maybe supporting both would be the right way to go. You already mentioned this in the description of the issue. So this gets a :+1: from me :).

Another point in favor of supporting the .jsx extension is that TypeScript compiles to that extension whenever you target ES6/ES2015

airbnb / eslint-plugin-react is complaining about react/jsx-filename-extension rule

Now that the webpack config can be manipulated this is possible https://github.com/zeit/next.js#customizing-webpack-config

Is there an example for how to make this work using next.config.js? As far as I can tell, this would require overwriting at least four loaders produced by the framework (babel-loader, hot-self-accept-loader, react-hot-loader/webpack, and emit-file-loader) which those docs explicitly calls out as a bad idea and kind of defeats the purpose of the framework.

I'm fine with this not being supported if that's the official stance, but the above comment seems to suggest that it is.

@AlteredConstants something like this:

module.exports = {
  webpack: (config, { dev }) => {
    config.resolve.extensions = ['', '.js', '.jsx'];
    return config;
  }
}

_However_, having just tried this, it looks like this approach does not work. I'll have to dig in to figure out why.

@rossipedia, that will only allow Webpack to recognize imported modules with a .jsx extension when the extension is excluded from the import, e.g. import Foo from './Foo' instead of import Foo from './Foo.jsx'.

In order to get Webpack to correctly process those modules, you need to (presumably) add .jsx to the test property of the loaders mentioned above. That feels a bit heavy-handed and prone to error, and it doesn't handle the pre-rendered case according to the docs linked above. I'm also not sure the automatic page/ importing will even work in that case鈥攖hat appears to happen outside of the Webpack process and/or perhaps as separate entry points?

Understandably, module resolution is more complicated in this framework than a simple Webpack config option. So again, unless I'm mistaken, the resolution to this issue seems to be "won't fix" more so than "workaround", and I just wanted to be clear on the team's stance. @impronunciable, any more insight?

Should add this to FAQ.

module.exports = {
  webpack: (config) => {
    config.resolve.extensions = ['.js', '.jsx'];
    config.module.rules.push(
      {test: /\.(js|jsx)$/, use: 'babel-loader'}
    );
    return config;
  }
}

@J-F-Liu not working for me.

I'm getting Error: Cannot find module '../components/Page' or Module build failed: Error: Couldn't find preset "stage-3" relative to directory "/Users/cla/Projects/with-mobx/node_modules/styled-jsx"

Trying to setup next.js 2-beta + mobx + airbnb

Maybe I miss something? What's your .babelrc content?

It seems also pages extensions cannot be .jsx

@foxhound87 yes, that doesn't work, I also give up.

TypeScript 2.2 now supports "jsx": "react-native", which will output .js files but also preserve JSX. See here

same problem here :<, any ideas how to solve this?

I ran into this while writing a bake-off as our company standard is to use .jsx for any files containing jsx markup. Understanding this is a webpack config and shouldn't impact performance, is there a reason specifically Next.js doesn't support jsx imports?

_Edit:_
As noted above, using the webpack config works well for importing components but files in /pages/ must have a .js extension to be routed correctly. As silly as this issue may seem, large teams must follow the standards/conventions put in place so this may block adoption of this great framework.

I'm really liking everything about Next except for this, which unfortunately precludes our using it.
I'll check back in to see if any progress is made though.

The issue seems to extend far deeper than Webpack and Babel; it is hardcoded in numerous places. :(

The only effort I've made so far is adding a line for "jsx" in server/resolve.js:34. I'm doing this through modifying files under my project's node_modules/next/dist/.

Making the modification outputs the below in the console. Note that the console now says Building page: /, rather than Client pings, but there's no entry for page: /.

 DONE  Compiled successfully in 12156ms                                                    8:34:44 PM

> Ready on http://localhost:3000
> Building page: /


 DONE  Compiled successfully in 10983ms                                                    8:34:58 PM

SyntaxError: Unexpected token m in JSON at position 0
    at JSON.parse (<anonymous>)
    at _callee$ (/Users/Jason/Repositories/radioapp/node_modules/next/dist/server/read-page.js:48:32)
    at tryCatch (/Users/Jason/Repositories/radioapp/node_modules/regenerator-runtime/runtime.js:64:40)
    at Generator.invoke [as _invoke] (/Users/Jason/Repositories/radioapp/node_modules/regenerator-runtime/runtime.js:299:22)
    at Generator.prototype.(anonymous function) [as next] (/Users/Jason/Repositories/radioapp/node_modules/regenerator-runtime/runtime.js:116:21)
    at step (/Users/Jason/Repositories/radioapp/node_modules/babel-runtime/helpers/asyncToGenerator.js:17:30)
    at /Users/Jason/Repositories/radioapp/node_modules/babel-runtime/helpers/asyncToGenerator.js:28:13

Edit:

This issue is actually bearable for me, because I simply created a server directory with a .eslintrc file:

{
  "parser": "espree",
  "parserOptions": {
    "ecmaVersion": 6,
  },

  "env": {
    "node": true
  },
}

In case it is helps anyone, you can configure different linter and also Sublime settings per directory. You can also create a public directory that contains your Next.js files and put the appropriate .eslintrc file there.

I'm using Sublime, with babel-sublime and SublimeLinter-contrib-eslint.

@jasonszhao I agree. But it's unlikely we are going to support .jsx support. Use .js extension.

@arunoda That's a shame. Many of us can't use it because of this arbitrary design choice. Guess I'm uninstalling.

Wouldn't it make more sense to make it configurable? Use next.config.js and have an option that defaults to ['.js'], or better yet a function that can filter things out such as .test.js or .spec.js for Jest.

EDIT: I'm trying to use .tsx as I cannot use the tsc approach in the TypeScript example as I'm trying to also run a custom server in TypeScript as well.

Is .jsx still not supported? I'm also running into an issue that my company would block from using next.js since our standard is to use .jsx for React components.

I know this one seems trivial but it's really making it difficult for our team to justify adopting Next :(

Would be awesome if someone from the core team could elaborate a bit on this seemingly non-consequential design decision.

+1 for .jsx extension support

You can easly add .jsx support but... not for SSR. You will get an error with that, but after changing something in the code and hot reload - you will see your page. F5 and boom, error.

Not sure how to fix that.

const originalJS = "/\\.js(\\?[^?]*)?$/";

config.resolve.extensions = [".js", ".jsx", ".json"];
config.module.rules.forEach((rule) => {
    if (String(rule.test) === originalJS) {
        rule.test = /\.jsx?(\?[^?]*)?$/;
    }
});

Like many, I don't get why this can't happen.

Many people use a linter config that says use jsx, editors use it to help differentiate between regular js and jsx and ... well seriously is it that big a deal to add it? If I understood the code well enough I'd just do it myself but...

PLEEEEASE

Just throwing in some more support for the idea that .jsx can reasonably be expected to work "out of the box". The workaround is trivial once someone figures out what the problem is (and finds this issue), but in my experience it is a _widely adopted convention_ (intentionally side-stepping "recommended" verbiage here) to use the .jsx extension for files that primarily export a React Component.

I'm about to simply swap extensions and continue on my way, but I'm struggling to understand why there's resistance to this. More importantly than this being a reasonable request, for many devs it's expected behavior, and (marginally) ratchets up the barrier to entry. And while I don't want to spin this off into a debate about the merits of .jsx as an extension in the first place, suffice it to say that it's not entirely unreasonable to only want valid JavaScript in .js files, and I would argue that's a sentiment that is held by many existing and potential next.js users.

Btw, just getting started, but loving things so far. Thanks for all the awesome work!

That's probably linked, I couldn't used a .md extension. I had to use the following trick to make it work on the server (.md.js):

next.config.js

// ...
          {
            test: /\.md\.js$/,
            loader: 'raw-loader',
          },
// ...

I use eslint with airbnb and added another rule to silence the warning

{
    "extends": "airbnb",
    "rules": {
        "react/jsx-filename-extension": [1, { "extensions": [".js", ".jsx"] }]
    }
}

Does anyone have a working example where .jsx files are

  • inside the pages directory,
  • working with server-side rendering, and
  • being imported as modules from another directory

?

This would make a great addition to the /examples directory.

+1 for adding jsx support.

I fixed it by doing something similar to what @rossipedia was suggesting.

If it's not already there, create next.config.js at the root of the project.
Then simply push 'jsx' to the config.resolve.extensions array, it works just fine.

module.exports = {
  webpack: function (config, { isServer }) {
    config.resolve.extensions.push('.jsx');
    return config
  }
}

EDIT
Be careful, this modification seems to have a bad impact on performances. Going to investigate further.

If you鈥檙e using next v5 there is no need to change anything whatshowever, the .jsx extension is supported out of the box. If you鈥檙e seeing anything performance related try upgrading to next@canary.

I noticed that, awesome!

Was this page helpful?
0 / 5 - 0 ratings