I have a WordPress theme and for a part of it I want to use a React component (I don’t need SSR). I have used create-react-app in the past but now I have this code:
<div id="react-nav-bar"></div> <script src="https://unpkg.com/react@17/umd/react.production.min.js" crossorigin></script> <script src="https://unpkg.com/react-dom@17/umd/react-dom.production.min.js" crossorigin></script> <script src="<?php echo get_template_directory_uri() ?>/react-nav-bar/build/static/js/runtime-main.39639aca.js"></script>
and it does not work. The request to runtime-main.39639aca.js
succeeds but it does not load my nav bar.
The issue is that create-react-app produces more than a JS file, and I need just a JS file that I can put in the theme.
I have tried some things with webpack without success. I searched on GitHub and there are some things, I do not know which one to try. I tried react-embedded and it threw me an error. I also tried this but it does not work for me.
I also dislike the ES Lint warnings (I use VS Code).
Update 1
This command does what I want, partially:
npx babel --watch react-nav-bar/src --out-dir react-nav-bar/dist --presets react-app/prod
This is how I’ve tried without WebPack, but the editor in VS Code is filled with red squiggles although it compiles well, and I cannot import npm modules. Is there a way to be able to import npm modules? Autocompletion makes me a lot more productive.
Advertisement
Answer
I gave Rollup a try and it works beautifully.
I get some warnings in the DevTools console but it works! With autocompletion and npm module includes.
Based on this gist I have these files:
src/index.tsx
import * as React from "react"; import { render } from 'react-dom'; const App = () => { return <button onClick={() => alert('React from WordPress !')}>Cool!!!</button>; }; window.addEventListener('DOMContentLoaded', () => { render(<App />, document.getElementById('react-nav-bar')); });
package.json
Just two additional scripts:
"build": "rollup -c", "watch": "rollup -cw"
The unusual dependencies when compared with the gist linked above:
"@rollup/plugin-commonjs": "^18.0.0", "@rollup/plugin-node-resolve": "^11.2.1", "rollup-plugin-typescript": "^1.0.1",
rollup.config.js
import typescript from 'rollup-plugin-typescript'; import resolve from '@rollup/plugin-node-resolve'; import commonjs from '@rollup/plugin-commonjs'; export default { input: './src/index.tsx', output: { file: './dist/bundle.js', }, format: 'iife', plugins: [ resolve(), typescript(), commonjs() ], };
tsconfig.json
{ "compilerOptions": { "emitDecoratorMetadata": true, "experimentalDecorators": true, "forceConsistentCasingInFileNames": true, "jsx": "react", "module": "es6", "moduleResolution": "node", "noImplicitAny": true, "outDir": "./dist", "preserveConstEnums": true, "target": "es5", "allowSyntheticDefaultImports": true }, "exclude": [ "node_modules" ] }
For React to work with this I have the special line: "allowSyntheticDefaultImports": true
.
../footer.php
<div id="react-nav-bar"></div> <script>try { process.env.NODE_ENV } catch(e) { var process = { env: { NODE_ENV: 'production' } }; }</script> <script src="<?php echo get_template_directory_uri() ?>/react-nav-bar/dist/bundle.js"></script>
This helped a lot: https://github.com/hybridsjs/hybrids/issues/27#issuecomment-452346986