简体   繁体   中英

Create React App: Transpile JSX of external package in node_modules

I'm trying to use the react-scratchblocks package on my react project.

I've created my project using the create-app-react command.

After importing the package I got the following error:

Failed to compile.

./node_modules/react-scratchblocks/src/Scratchblocks.js
SyntaxError: /Users/jorge/Documents/React/elimu-analyzer-frontend/node_modules/react-scratchblocks/src/Scratchblocks.js: Unexpected token (45:6)

  43 |     const scripts = this.parseScripts(this.props.code);
  44 |     return (
> 45 |       <div className={this.classNames()}>
     |       ^
  46 |         {scripts.map((script,i) => (
  47 |           <Scratchblock key={i} className="script" script={script}/>
  48 |         ))}

I know that the jsx it's not been recognized, but what should I do to make this package work? Remember: i've used the create-rect-app to create my React project.

Thanks.

UPDATE 1:

module.exports = function () {

return {
    overrides: [{
        test: ["./node_modules/react-scratchblocks"],
        presets: ["@babel/preset-react"]
    }],
};
}

UPDATE 2: Component that where I import the react-scratchblocks.

import React, { useState } from 'react';
import { withRouter } from 'react-router-dom';
import './styles.css';
import Fire from '../../config/Fire';
import Realtime from '../Realtime';
import Scratchblocks from 'react-scratchblocks'

function Content(props) {

const [menuOption, setMenuOption] = useState(1);

async function logout() {
    await Fire.logout();
    props.history.push('/');
    console.log('oi');
}

if (menuOption === 0) {
    return (
        <div class='content'>
            <Realtime />
        </div>
    );
}
else if (menuOption === 1) {
    return (
        <div class="content">
            <button onClick={logout}> OUTRA OPÇÃO </button>
        </div>
    );
}
}

export default withRouter(Content);

Create React App (CRA) only transpiles standard JavaScript syntax inside node_modules .

This does not include JSX compilation. Package react-scratchblocks errors due to untranspiled JSX :

SyntaxError: .../Scratchblocks.js: Unexpected token (45:6)

Statement from maintainers ( link ):

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

The reason we've taken this stance is because compiling non-standard syntax tightly couples libraries to build tools.

It's also hard to draw a line once you allow experimental things. Most people will want to use not just JSX, but also experimental transforms like class properties. Or decorators. Now we have to argue with every library maintainer about which transforms we want to support, and which we don't.

Hence package authors would have needed to transpile JSX them selves before distribution.

To transpile JSX manually 1 you can apply the Babel React preset to react-scratchblocks inside node_modules :

babel node_modules/react-scratchblocks \
  -d node_modules/react-scratchblocks/dist \
  --presets=@babel/preset-react

The build step might be outsourced into its own config file ( transpile.js ):

module.exports = {
  ...
  overrides: [
    {
      test: ["./node_modules/react-scratchblocks"],
      presets: ["@babel/preset-react"]
    }
  ]
};
babel node_modules/react-scratchblocks \
  -d node_modules/react-scratchblocks/dist \
  --config-file ./transpile.js

Then adjust main entry inside node_modules/react-scratchblocks/package.json to point to the previously transpiled version in dist :

"main": "dist/index.js",

patch-package can further automate the process of fixing broken packages.

Remember this is only a workaround - the duty is on package developers to distribute an npm package with standard JavaScript features.

1 A different alternative would be to adjust Webpack config (only possible with ejected CRA).

I personally suggest you to use craco (see @craco/craco )

Craco is a powerful tool that allows you to edit built-in create-react-app configuration without forcing you to eject the project.

How to install it

  • run npm install @craco/craco --save-dev
  • run npm install craco-babel-loader --save-dev
  • create craco.config.js in the root folder of the project
  • update the scripts in package.json :
    • react-scripts start -> craco start
    • react-scripts build -> craco build
    • ...
  • this is the content of the configuration craco file
const path = require('path')
const fs = require('fs')
const cracoBabelLoader = require('craco-babel-loader')

// manage relative paths to packages
const appDirectory = fs.realpathSync(process.cwd())
const resolvePackage = relativePath => path.resolve(appDirectory, relativePath)

module.exports = {
  plugins: [
    {
      plugin: cracoBabelLoader,
      options: {
        includes: [
          resolvePackage('node_modules/package-to-transpile'),
          resolvePackage('node_modules/another-package-to-transpile'),
        ],
      },
    },
  ],
}

You can change a lot of other configurations, and I suggest you to give a look at craco npm package page

Credtis: https://stackoverflow.com/a/58603207/4277948

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM