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

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

Open
FelixKuehl opened this issue Sep 26, 2018 · 26 comments
Open

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

FelixKuehl opened this issue Sep 26, 2018 · 26 comments

Comments

@FelixKuehl
Copy link

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
Copy link
Contributor

gaearon commented Sep 26, 2018

Hey @FelixKuehl, we're really sorry about this! As mentioned in #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
Copy link
Author

FelixKuehl commented Sep 26, 2018

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
Copy link
Contributor

gaearon commented Sep 26, 2018

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
Copy link
Author

FelixKuehl commented Sep 27, 2018

@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
Copy link
Contributor

Timer commented Sep 27, 2018

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

@Timer Timer added this to the 2.0.0 milestone Sep 27, 2018
@FelixKuehl
Copy link
Author

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:

  • SVG Images used in the library are sometimes not correctly resolved
  • CSS Modules and SASS work out of the box. However it seems like all the css imported in any component within your library, is always getting included into your app. No matter which component you are importing from the library. A possible solution for resolving CSS treeshaking might be https://github.com/FullHuman/rollup-plugin-purgecss as referenced in Tree Shaking egoist/rollup-plugin-postcss#98 .
  • Rollup does a pretty good job in watching and recompiling your code. The downside however is, that every code change forces the create react app that uses the library to recompile completely. Depending on the complexity of your application and your library, compiling both on every code change can take a painfully amount of time. So I would highly recommend using some kind of styleguide setup to develop your components against.

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
Copy link
Contributor

Timer commented Sep 28, 2018

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

@FelixKuehl
Copy link
Author

FelixKuehl commented Sep 28, 2018

This bug is referenced in webpack-contrib/eslint-loader#165, webpack-contrib/eslint-loader#202 and webpack/webpack#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.

@Timer Timer mentioned this issue Oct 1, 2018
7 tasks
@Timer Timer modified the milestones: 2.0.0, 2.0.x Oct 1, 2018
@FelixKuehl
Copy link
Author

FelixKuehl commented Oct 1, 2018

@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 FelixKuehl/cra-monorepo@0d21eb5 on, this repo uses babel to watch and compile the libraries. Also I switched to using Styleguidist over Storybook.

@mattfysh
Copy link

mattfysh commented Oct 1, 2018

@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
Copy link

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
Copy link
Author

@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
Copy link
Author

FelixKuehl commented Oct 2, 2018

@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
Copy link

jolanglinais commented Apr 4, 2019

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:

  • node: 8.15.0
  • yarn: 1.13.0
  • npm: 6.4.1
  • react-scripts: ^2.1.8

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
Copy link

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
Copy link

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
Copy link

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
Copy link

geethab commented Aug 7, 2019

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

@earGO
Copy link

earGO commented Sep 9, 2019

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
  1. Export your component or module code in /src/index.js as a default export (export default YourComponent)

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

  3. 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
Copy link

billygl commented Oct 19, 2019

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
Copy link

any updates?

@kode8

This comment has been minimized.

@jrbentham
Copy link

any updates on this?

@mesrbn
Copy link

mesrbn commented Jan 30, 2021

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

@fabpico
Copy link

fabpico commented May 3, 2021

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
Copy link

fabpico commented May 4, 2021

It seems that this is all expected behavior, as Dan aka @gaearon says here #5103 (comment).

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).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests