neutrinojs / neutrino

Create and build modern JavaScript projects with zero initial configuration.
https://neutrinojs.org
Mozilla Public License 2.0
3.95k stars 214 forks source link

React (jsx): You may need an appropriate loader to handle this file type. #1406

Closed Tassfighter closed 4 years ago

Tassfighter commented 5 years ago

When starting the web app with webpack dev server:

1 error found.

ERROR in ../user/src/authentication/container.jsx 28:15
Module parse failed: Unexpected token (28:15)
You may need an appropriate loader to handle this file type.
|     switch (navigation) {
|       case loginState.SIGNUP:
>         return <SignUp {...props} />;
|       case loginState.SIGNOUT:
|         return <SignOut {...props} />;
ℹ 「wdm」: Failed to compile.

Please try to answer the following questions:

9.0.0-rc.3

  • Are you trying to use any presets? If so, which ones, and what versions? "@neutrinojs/airbnb": "^9.0.0-rc.3", "@neutrinojs/jest": "^9.0.0-rc.3", "@neutrinojs/react": "^9.0.0-rc.3",
  • Are you using the Yarn client or the npm client? What version? npm 6.4.1
  • What version of Node.js are you using? v10.15.3
  • What operating system are you using? Ubuntu 16.04
  • What did you do? import a neutrino react-component
  • What did you expect to happen? render my react-component into my web app
  • What actually happened, contrary to your expectations? module parser failed to load my react-component

The import works in production mode but not in development mode.

my react-component's package.json:

{
  "name": "login",
  "version": "0.0.0",
  "main": "build/web.js",
  "module": "src/web.js",
  "scripts": {
    "start": "webpack-dev-server --env.dev --mode development --open",
    "build": "webpack --mode production",
    "test": "jest",
    "lint": "eslint --cache --format codeframe --ext mjs,jsx,js src test",
    "fix": "npm run lint -- --fix",
    "registry": "npm publish --registry http://0.0.0.0:4873"
  },
  "devDependencies": {
    "@neutrinojs/airbnb": "^9.0.0-rc.3",
    "@neutrinojs/jest": "^9.0.0-rc.3",
    "@neutrinojs/react-components": "^9.0.0-rc.3",
  ...
}

Web app import statement: import Login from 'login';

Workaround: I can point to my build directly (that works): import Login from 'login/build/web';

edmorley commented 5 years ago

Hi @Tassfighter! Could you paste your .neutrinorc.js and also try running npm run lint to see what eslint reports? Thanks :-)

Tassfighter commented 5 years ago

No lint errors.

The react components neutrinorc.js

const airbnb = require('@neutrinojs/airbnb');
const reactComponents = require('@neutrinojs/react-components');
const jest = require('@neutrinojs/jest');

module.exports = {
  options: {
    root: __dirname,
  },
  use: [
    airbnb({
      eslint: {
        baseConfig: {
          rules: {
            // solves: 'react' should be listed in the project's dependencies, not devDependencies
            'import/no-extraneous-dependencies': 'off',
          },
        },
      },
    }),
    reactComponents({
      components: '.', // now you can put your components in src/
    }),
    jest(),
  ],
};

The web app's neutrinorc.js:

const airbnb = require('@neutrinojs/airbnb');
const react = require('@neutrinojs/react');
const jest = require('@neutrinojs/jest');

module.exports = {
  options: {
    root: __dirname,
  },
  use: [
    airbnb(),
    react({
      html: {
        title: 'DentaliQ.ortho'
      }
    }),
    jest()
  ]
};
edmorley commented 5 years ago

Ah ok so there are two project, one using @neutrinojs/react-components and the other trying to consume those components. To understand this more we'd really need a testcase repo to show more clearly how the project is laid out/which files are importing each other. Could you create a reduced testcase?

Tassfighter commented 5 years ago

I did setup a test project and found the problem: my react-component's package.json:

{ "name": "login", "version": "0.0.0", "main": "build/web.js", "module": "src/web.js", "scripts": { "start": "webpack-dev-server --env.dev --mode development --open", "build": "webpack --mode production", "test": "jest", "lint": "eslint --cache --format codeframe --ext mjs,jsx,js src test", "fix": "npm run lint -- --fix", "registry": "npm publish --registry http://0.0.0.0:4873" }, "devDependencies": { "@neutrinojs/airbnb": "^9.0.0-rc.3", "@neutrinojs/jest": "^9.0.0-rc.3", "@neutrinojs/react-components": "^9.0.0-rc.3", ... }

module": "src/web.js" causes the problem.

edmorley commented 5 years ago

It's still not exactly clear how the two projects are set up and/or what's going wrong here. If you could provide a reduced testcase I'm happy to take a look, otherwise I don't think there's much more we can do here unfortunately.

Tassfighter commented 5 years ago

Here is a demo project:

https://github.com/Tassfighter/demo-neutrino-issues-1406/tree/master

A workaround is to remove line 5 ("module": "src/web.js",) from:

https://github.com/Tassfighter/demo-neutrino-issues-1406/blob/master/packages/demo_component/package.json

The workaround will lead into another problem described here: https://github.com/neutrinojs/neutrino/issues/1409

edmorley commented 5 years ago

Hi! Sorry for the delayed reply.

So I tried this out locally and got the same error. The reason it occurs is that by default, Neutrino only babel-compiles first party source (the JSX -> JS transformation is handled by a babel plugin). It does this because even when using the module entry in package.json, it's expected that the provided file (and it's imports) still be JS and not in some other format - ie: the only difference from the content in main should be that it can use modules syntax (that is import and export rather than require etc).

Looking at some other popular React packages, they compile from JSX -> JS even for their ES (module) sources: https://unpkg.com/browse/reactstrap@8.0.1/es/ https://unpkg.com/browse/react-virtualized@9.21.1/dist/es/ https://unpkg.com/browse/react-table@6.10.3/es/

As such, I believe the best way to resolve this is for demo_component to have two build configs (see here for how to have several configs) - one that builds for older browsers (that will be output under say dist/) and another for newer browsers (output under es/) - using appropriate Neutrino babel options for each. The package.json will then set module to point at the es/ JS files, not the originals under src/.

If you'd rather not do this, an alternative would be to make Neutrino babel compile all files (see here), including those from other packages. However this will (a) slow down demo_webapp's build, (b) mean that your component won't work for some people (if you are publishing it publicly).

Does that help? :-)

Tassfighter commented 4 years ago

It seems reasonable to me. Thanks for your effort.