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 manually1 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
npm install @craco/craco --save-dev
npm install craco-babel-loader --save-dev
craco.config.js
in the root folder of the projectpackage.json
:
react-scripts start
-> craco start
react-scripts build
-> craco build
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With