facebook / create-react-app

Set up a modern web app by running one command.
https://create-react-app.dev
MIT License
102.61k stars 26.79k forks source link

Babel JSX Syntax error when importing from a linked library #5100

Open FelixKuehl opened 6 years ago

FelixKuehl commented 6 years ago

Is this a bug report?

Yes

Did you try recovering your dependencies?

Yes

Which terms did you search for in User Guide?

(Write your answer here if relevant.)

Environment

Running npx create-react-app --info does not seem to work. Getting:

Please specify the project directory:
  create-react-app <project-directory>

For example:
  create-react-app my-react-app

Run create-react-app --help to see all options.

However I am using: Node v8.11.3 Yarn 1.9.4 npm 6.4.1 react-scripts 2.0.0-next.2150693d

Steps to Reproduce

  1. Create a new Create React App (The actual App)
  2. Create another Create React App (The "Library")
  3. Link them together: Import a component from the Library into the App

This used to work with react-scripts 2.0.0-next.a671462c

Expected Behavior

The app should compile just fine as it used to in 2.0.0-next.a671462c

Actual Behavior

Application fails to compile with "Syntax error: Unexpected token" in the component, that was attempted to be imported from the other application.

screen shot 2018-09-26 at 16 36 00

To me it seems like the babel loader is somehow not transpiling the imported component.

Reproducible Demo

https://github.com/FelixKuehl/cra-alpha-issue-example

gaearon commented 6 years ago

Hey @FelixKuehl, we're really sorry about this! As mentioned in https://github.com/facebook/create-react-app/issues/5024, our monorepo support was incomplete and we think it would create more issues for our users in long term if we shipped it in that state. On the other hand, the 2.x branch has stalled for many months, and we were worried it would never get shipped. So we made a difficult decision to remove some of the features that existed in 2.0 earlier alphas in order to ship a stable 2.0 within two weeks.

We'll offer migration strategies that you could use to unblock your migration to 2.x, but they'll likely include introducing another compiler like nwb for packages outside the main one. We are also open to more proposals about monorepo support, except that if we land it next time it would need to be a more complete one.

FelixKuehl commented 6 years ago

Hey @gaearon, thank you for your fast reply. This actually is quite a bummer for our current setup. We did enjoy developing cra powered applications in a monorepo due to the flexibility and the productive development workflow it gave us. Personally I have no experience with nwb or similar. Wouldn't it be possible to at least support Yarn Workspaces to be able to share components between applications? I feel like this is quite an important feature when developing multiple applications, that have shared elements. Do you have migration proposals written down already? Having to use an intermediate compiler feels like it would come with a lot of configuration work and some serious pitfalls.

gaearon commented 6 years ago

Yeah I understand why it's useful very well. It was just half-baked, especially with regards to how testing works, or how to opt out certain packages from compilation.

@Timer can give you some pointers.

FelixKuehl commented 6 years ago

@gaearon Thanks for explaining. I will take a look at projects like nbw and create-react-library to transpile our library code. I am especially worried about sass and css-modules. Would be great to get a hint on your future roadmap / ideas regarding this topic. Every pointer would be helpful @Timer ;)

Timer commented 6 years ago

Hey @FelixKuehl! I'll probably be drawing up some more extensive documentation here soon. I'll post here when it's ready.

FelixKuehl commented 6 years ago

As an Update for all those having the same issue: I gave create-react-library a try and it did a decent job as a drop-in solution without a lot of manual adjustments. However it comes with some caveats:

Another problem I stumbled across, that might be interesting for @Timer's migration proposals or create react app itself, was the way ESLint handles locally symlinked dependecies. With cra's current ESLint setup, everything within the "node_modules" folder gets ignored by ESLint as expected. However, if a dependency is symlinked locally (Yarn Workspace, Lerna, npm link, etc.) the path is resolved first and then checked against the eslintignore settings and therefore not excluded from linting. This results in ESLint errors showing up in your create react app when consuming a locally linkend library (Or more precisely its "dist" folder). A quick fix for this was using babel-plugin-eslint-disable. However I do not see any use case where you would want to lint a dist folder, so adding **/dist* to the default eslintignore would be a more defensive solution. Or am I missing something?

I will take a look at nbw now and see how this integrates.

Timer commented 6 years ago

Hmm, ESLint resolving symlinks sounds like a bug. Can we turn this feature off?

FelixKuehl commented 6 years ago

This bug is referenced in https://github.com/webpack-contrib/eslint-loader/issues/165, https://github.com/webpack-contrib/eslint-loader/issues/202 and https://github.com/webpack/webpack/issues/985. I am not a webpack expert but setting symlinks: false in the webpack config or adding **/dist/* to eslintignore could work. Would need to test this though.

FelixKuehl commented 6 years ago

@Timer following @gaearon's suggestion, I spend the last day experimenting with nwb as a compiler. The setup I came up with, seemed quite decent to me. I put up an example repo here: https://github.com/FelixKuehl/cra-monorepo Maybe this can help you out a bit or gets you some ideas for your documentation. Let me know if I can do anything to help.

So what did I do? (See https://github.com/FelixKuehl/cra-monorepo/blob/master/README.md for details) Using nwb as a compiler seemed quite intuitive. However it did require some configuration in order to work with create react apps features, such as CSS Modules, SASS, etc. Also, I wanted to have a dev server / watcher, that handles recompiling on code changes. All this can be found in the library-utils package within the example repository. These utils provide a nwb (and Storybook) config, that works quite well when the components are targeted at being consumed by a create react app. In order to have a decent development workflow, I build the library-utils build:watch and library-utils start scripts. The first one starts a custom nodemon based watcher, that automatically recompiles the library on changes in the src folder and the second one starts this watcher together with a storybook server. This feels quite convenient when developing. When having multiple libraries in the monorepo you can now simply run lerna exec -- yarn run build:watch to start a single terminal application that watches all the packages that have the "build:watch": "library-utils build:watch" script in their package.json. The watcher simply transpiles all the components and copies the assets for the create react app to bundle. Again for details just take a look at the linked example repository above or just ask me :) Hope this might help a bit.

Update:

Form commit https://github.com/FelixKuehl/cra-monorepo/commit/0d21eb5534dfa5a13d90282af55f91429baa4738 on, this repo uses babel to watch and compile the libraries. Also I switched to using Styleguidist over Storybook.

mattfysh commented 6 years ago

@FelixKuehl in terms of performance, a couple of questions:

  1. when a change is detected in a source dependency, are the whole contents of that package re-compiled, or just the file that changed?
  2. does create-react-app automatically refresh the page when running in dev mode?
bugzpodder commented 6 years ago

I currently using a babel --watch to achieve this rather than nwb (haven't had time to evaluate nwb/create-react-library) and it works fine from limited testing. (obviously you'll need your own babel config).

FelixKuehl commented 6 years ago

@mattfysh

  1. when a change is detected in a source dependency, are the whole contents of that package recompiled, or just the file that changed?

At the moment it is recompiling the entire library on every code change. Sadly this cannot really be avoided when using nwb. It would be trivial to detect changes to assets and css / scss files (nodemon does that automaticly) and copy those without any recompilation. That would also enable the create react app to show style changes without recompiling. I am currently trying a babel --watch setup, as @bugzpodder suggested. Using babel directly feels much more performant, but of course compromises the advantages of nwb. To be honest this feels like a simpler and faster approach. (Until nwb findes a way of making their babel work in watch mode)

  1. does create-react-app automatically refresh the page when running in dev mode?

Yes ist does.

I will update the example repo once I am happy with my final solution. At the moment I feel like I am going to build a simple container around a babel watch process.

FelixKuehl commented 6 years ago

@bugzpodder At first I kind of liked the idea of using a library like nwb over using babel directly but

rm -rf es && NODE_ENV=production babel -w --presets=react-app src --out-dir es --copy-files --ignore __tests__,spec.js,test.js,__snapshots__

pretty much gets the job done.

jolanglinais commented 5 years ago

Hello all! I have been searching for a solution to my problem, and this seems to be the most relevant. Please let me know if this doesn't fit with this open issue.

Goals:

I am building two separate repositories. One will be a page which will import other React Components as npm packages once published. So currently I have a local repository that depends on another. For development, I am attempting to link them with npm link.

Versions:

Circumstances:

  1. Local repository containing a React Component. .../Code/A/MyComponent/src/TL
    • This renders and works.
  2. Local repository that will eventually import and render the first React Component. .../Code/A/MyApp/src
    • Created this with npm create-react-app MyApp
  3. Linked these two with npm link, starting with MyComponent, then running npm link MyComponent in MyApp
    • This created a MyComponent node_module in MyApp.
  4. When importing and attempting to render MyComponent in MyApp, received Syntax error
    • Unexpected token at the beginning of MyComponent's JSX code.
    • This is the issue it looks like @FelixKuehl was having and seems this is a compiling issue.
  5. Run npm run transpile in MyComponent to create a dist directory.
  6. When running npm start now, I receiv this message: Error: Failed to compile.
    • In .../MyApp/src/App.js:
    • Module not found: Can't resolve 'A/MyComponent' in '.../Code/A/MyApp/src'

I tried adding symlinks: false here in node_modules/react-scripts/config/webpack.config.js:

module.exports = function(webpackEnv) { 
  return { 
    resolve: {
      symlinks: false,
    }
  }
}

This did not help.

  1. After tinkering, I am left with this current error: Screen Shot 2019-04-04 at 2 14 50 PM

Concerns:

This seems to be either a Babel or Webpack issue concerning npm link. I imagine MyApp is either not being pulled together by Webpack and/or not being compiled by Babel.

jolanglinais commented 5 years ago

An update on my issue for future reference if someone may have a similar issue:

The code for the MyComponent React component was showing up and being unrecognized (as in my #4 in Circumstances). This was because I had yet to build the code. I ran npm build and re-did the npm link process, and this works.

Hopefully that was clear and helpful.

chrisdel101 commented 5 years ago

I have a similar error but @irmerk solution did not work for me. I just simply get a syntax error.

Screen Shot 2019-06-18 at 3 45 29 PM
deepakkatara commented 5 years ago

I have got the issue (ref: https://stackoverflow.com/questions/56680612/react-script-compatibility-issue-with-third-party-node-module) which is very similar to @irmerk
if anyone got this issue resolved please help here.

@gaearon @Timer i am not sure if this is out of the scope of cra 2.1.8 because this issue look like babel/webpack config issue and in cra we are not suppose to make any changes in config.

geethab commented 5 years ago

I have got the exact issue as @chrisdel101 . Any updates on resolving the compilation error?

earGO commented 5 years ago

We've had quite some time figuring this one out, but I think we found the reason and solution. Check this out guys - I bet you'll be blown away.

So, when CRA tries to transpile your package, it uses babel to transpile JSX code to commonjs. Last versions of babel transpilers have big troubles with unnamed exports. So when you try and import your default as unnamed export (for example export default YourComponent), it throws an error.

But we do not see this error, 'cause of CRA bundle. This error shows in console, for example, when we try and configure babel with webpack in monorepo by hand.

The solution, that worked for me and my colleagues is this one:

  1. make package structure like this

    YourPackage
    |-src
    |   |-index.js
    |-index.js
  2. Export your component or module code in /src/index.js as a default export (export default YourComponent)

  3. In root index.js export your component as follows export { default as YourComponent } from './src/index.js'

  4. you can import your component in consumer app like this: import {YourComponent} from YourPackage (plus the namespace, of course)

And that's it. This worked for us beautifully.

Special thanks to this hero, https://github.com/aivtel who actually solved the problem. My part was in pointing where to look and why this unfortunate issue was happening in the first place.

billygl commented 4 years ago

I have the same issue integrating with react native mono repo. It has issues with external libraries in the react native repo, and I also had the suggested structured

YourPackage
|-src
|   |-index.js
|-index.js

But it doesn't work because it is symlinked by lerna.

Iuriy-Budnikov commented 4 years ago

any updates?

kode8 commented 4 years ago

Spent a day to work out this heap of crap. Why is the React eco system so f__ked? Back to Vue I go.

jrbentham commented 4 years ago

any updates on this?

mesrbn commented 3 years ago

any updates? getting the following error when importing from own npm package containing jsx:

template2
fabpico commented 3 years ago

I have the same issue when using a component from node_modules. Error is not happening when loading the component from the current working project itself.

Module parse failed: Unexpected token (38:15)
You may need an appropriate loader to handle this file type, currently no loaders are configured to process this file. See https://webpack.js.org/concepts#loaders
|             return;
|         }
>         return <HeaderMenuButton aria-label="Open menu" onClick={onClickSideNavExpand} isActive={isSideNavExpanded}/>;
|     }
|     const searchBar = props.search ?

When I change App.js to App.jsx, the error message is slightly different.

./node_modules/@...my-vendor.../style-guide/src/components/Header/Header.js
SyntaxError: C:\foo\node_modules\@...my-vendor...\style-guide\src\components\Header\Header.js: Support for the experimental syntax 'jsx' isn't currently enabled (38:16):

  36 |             return;
  37 |         }
> 38 |         return <HeaderMenuButton aria-label="Open menu" onClick={onClickSideNavExpand} isActive={isSideNavExpanded}/>;
     |                ^
  39 |     }
  40 |     const searchBar = props.search ?
fabpico commented 3 years ago

It seems that this is all expected behavior, as Dan aka @gaearon says here https://github.com/facebook/create-react-app/issues/5103#issuecomment-425459196.

We only compile valid JavaScript syntax in node_modules. JSX is not valid JavaScript. You are using JSX there.

So this issue will likely never be solved within create-react-app. The external library maintainer should serve a transpiled code i guess.

Also see https://stackoverflow.com/a/57762228/4840661:

the duty is on package developers to distribute an npm package with standard JavaScript features.
A different alternative would be to adjust Webpack config (only possible with ejected CRA).