React is not loaded / Build is not generated - reactjs

I am trying to create a WordPress plugin with React. I am following this link. I have the following package.json file
{
"name": "test-plugin",
"version": "1.0.0",
"private": true,
"description": "Sample plugin for React",
"main": "index.js",
"devDependencies": {
"#wordpress/scripts": "^13.0.3"
},
"scripts": {
"build": "wp-scripts build",
"check-engines": "wp-scripts check-engines",
"check-licenses": "wp-scripts check-licenses",
"lint:css": "wp-scripts lint-style",
"lint:js": "wp-scripts lint-js",
"lint:pkg-json": "wp-scripts lint-pkg-json",
"start": "wp-scripts start",
"test:e2e": "wp-scripts test-e2e",
"test:unit": "wp-scripts test-unit-js"
},
"author": "thor",
"license": "ISC"
}
I am enqueueing the react script as follows
wp_enqueue_script( 'react-script', plugin_dir_url(__DIR__) . 'build/index.js', ['wp-element'], $this->version, false );
ISSUES
The build react js file is not generated. I have followed the above link and everything was installed correctly. But no index.js file is created in build folder
The script is not working if I enqueue src/index.js instead of build/index.js. The script is loaded but not working as expected. I have the div with id my_app in one of the pages in which the script is loaded.
Following is the react script file
const { render, useState } = wp.element;
const Votes = () => {
const [votes, setVotes] = useState(0);
const addVote = () => {
setVotes(votes + 1);
};
return (
<div>
<h2>{votes} Votes test</h2>
<p>
<button onClick={addVote}>Vote!</button>
</p>
</div>
);
};
render(<Votes />, document.getElementById('my_app'));

Had the same problem with you and I spent good couple of hours trying to fix this. Here are problem that I encountered:
One of the issues was the node_modules folder was in the wrong place, supposed to be at the same level as your theme.
The other one was I had to run npm run start instead of npm start. Whenever wp-scripts output something like this :
asset index.js 4.35 KiB [emitted] (name: index)
1 related asset asset index.asset.php 107 bytes [emitted] (name: index)
means it is working. If don't get that means something wrong with your folder location.
Try and let me know.

Related

React compiler end up with Unexpected token <

I am beginner in React and I am struggling with compiler error. Let me introduce my situation. I have two independent React applications:
App A - Big ERP
App B - "Plugin" to the App A
I supposed I will develop App B as an independent application. Then, I will install it to the App A (using npm install git#github.repo/...) once I finish development of the App B. I expected I will call components from App B within the App A source code. Everything went fine until I run the compilation. I am receiving:
SyntaxError: /frontend/node_modules/connector_frontend/src/views/Connector/FormView/index.js: Unexpected token
In my /frontend/node_modules/connector_frontend/src/views/Connector/FormView/index.js there is following code:
const ConnectorFormView = ({ AppValues, secureFetch, ...rest }) => {
return (
<p>Hello world</p>
)
}
export default ConnectorFormView;
Error is ocuring at the position of <p>.
I call this functional component from App A (frontend/src/views/Connector/ConnectorNewEditView/index.js) like this
import ConnectorFormView from "connector_frontend/src/views/Connector/FormView";
const ConnectorNewEditView = () => {
return (<ConnectorFormView AppValues={appValues} secureFetch={secureFetch} />)
}
export default ConnectorNewEditView;
I tried to return just a plain text from the ConnectorFormView component like this:
const ConnectorFormView = ({ AppValues, secureFetch, ...rest }) => {
return (
'Hello world'
)
}
export default ConnectorFormView;
and it was compiled successfully, but once I return a JSX from the ConnectorFormView component the compiler get crashed.
Can anyone explain the source of this error please?
I successfully figured out the source of this problem and also I found a solution. I expected I can reuse however React component implemented in JSX. I expected, the only requirement is to install it, resp. download it in JSX form to my project using NPM. It's FALSE.
According to my research, I can reuse React components compiled from JSX to ES only. It is achievable using Babel. Another very important requiremen, it should not by installed as React application as I installed it. It must be installed as a NPM package with clearly defined set of exported components.
I found this paper https://levelup.gitconnected.com/publish-react-components-as-an-npm-package-7a671a2fb7f and I followed it step by step and finally I achieved desired result.
I can very briefly mention steps which I performed:
Implemented my custom component (mentioned above)
const ConnectorFormView = ({ AppValues, secureFetch, ...rest }) => {
return (
<p>Hello world</p>
)
}
export default ConnectorFormView;
Added the component to /src/index.js file in order to export it for host App
import ConnectorFormView from './components/ConnectorFormView';
export { ConnectorFormView };
Installed Babel and all needed presets
npm install --save-dev #babel/core #babel/cli #babel/preset-env
npm install -save #babel/polyfill
configured Babel - created file /babel.config.json with following content
{
"presets": [
[
"#babel/env",
{
"targets": {
"edge": "17",
"firefox": "60",
"chrome": "67",
"safari": "11.1"
},
"useBuiltIns": "usage",
"corejs": "3.6.5"
}
],
"#babel/preset-react"
]
}
Added new script to the package.json to compile React components to ES:
"build": "rm -rf dist && NODE_ENV=production babel src --out-dir dist --copy-files";
Executed npm run build to compile React components to ES. Compiled components are located in new dist folder.
Adjusted package.json that looks like this now
{
"name": "my_react_components",
"version": "0.1.0",
"private": true,
"description": "Some description",
"author": "Lukas",
"main": "dist/index.js",
"module": "dist/index.js",
"files": [ "dist", "README.md" ],
"dependencies": {
.
.
},
"scripts": {
"build": "rm -rf dist && NODE_ENV=production babel src--out-dir dist --copy-files",
.
.
.
},
"eslintConfig": {
"extends": "react-app"
},
"devDependencies": {
"#babel/cli": "^7.17.10",
"#babel/core": "^7.18.5",
"#babel/preset-env": "^7.18.2"
}
}
Pushed dist folder to the git.
Installed repository to the host project using NPM
npm install https://github.com/my_custom/react_component.git
Import and use the component from installed git repo
import ConnectorFormView from 'my_react_components';
function App() {
return (
<ConnectorFormView />
);
}
export default App;
Actually that's all. I very recommend to see the attached paper at the beginning of this answer because I maybe skipped very important info for you.

Invalid hook creating Liferay React component

I'm trying to create custom react components based on Liferay's Clay components.
Using e.g. just a ClayButton works, but as soon as i try to use hooks (like React.useState), the browser console tells me:
Minified React error #321; visit https://reactjs.org/docs/error-decoder.html?invariant=321 for the full message
The full message tells me i could be using mismatching versions of react and react-dom. I'm not.
I also don't have 2 different versions of react, according to the test described there.
I created a minimal example module at https://github.com/ReFl3x0r/liferay-react-component-test which can be tested in a Liferay Gradle Workspace.
There's also an older thread in Liferay Forums discussing this error, but with no solution.
(https://liferay.dev/ask/questions/development/re-lr-7-3-react-portlet-invalid-hook-call)
What am i doing wrong?
EDIT:
Trying to point out the main code snippets.
First CustomButtonFail.es.js:
import React from 'react';
import ClayButton from '#clayui/button';
const CustomButton = () => {
const [name, setName] = React.useState('test');
return (
<ClayButton displayStyle='primary'>
TEST
</ClayButton>
);
}
export default CustomButton;
The package.json:
{
"dependencies": {
"#clayui/button": "^3.40.0",
"#clayui/css": "3.x",
"react": "^16.12.0",
"react-dom": "^16.12.0"
},
"devDependencies": {
"#liferay/npm-scripts": "47.0.0",
"react-test-renderer": "^16.12.0"
},
"name": "component-test",
"scripts": {
"build": "liferay-npm-scripts build"
},
"version": "1.0.0"
}
The view.jsp including the component (shortened):
<%#taglib uri="http://liferay.com/tld/react" prefix="react" %>
<div class="react-component-failing">
<react:component
module="js/CustomButtonFail.es"
/>
</div>
I finally got it working. Reducing package.json like this:
{
"devDependencies": {
"#liferay/npm-scripts": "47.0.0"
},
"name": "component-test",
"scripts": {
"build": "liferay-npm-scripts build"
},
"version": "1.0.0"
}
and adding a ".npmbundlerrc" in modules root with content:
{
"config": {
"imports": {
"frontend-taglib-clay": {
"#clayui/button": ">=3.40.0",
"#clayui/css": ">=3.x"
},
"#liferay/frontend-js-react-web": {
"react": ">=16.12.0"
}
}
}
}
did the trick.
Working example is at https://github.com/ReFl3x0r/liferay-react-component-test/tree/working

Snowpack is not reloading

i started to use snowpack and ran into a big problem. Snowpack is not hot reloading for me.
I tried the basic minimal template, a svelte template and a react template - Everytime the same problem. I also created on from scratch based on the getting started.
Here a my example files:
index.jsx
import React from 'https://cdn.skypack.dev/react';
import ReactDom from 'https://cdn.skypack.dev/react-dom';
ReactDom.render(
<React.StrictMode>
<div>This is working</div>
</React.StrictMode>,
document.getElementById('root'),
);
// Hot Module Replacement (HMR) - Remove this snippet to remove HMR.
// Learn more: https://www.snowpack.dev/concepts/hot-module-replacement
if (import.meta.hot) {
import.meta.hot.accept();
}
snowpack.config.js
/** #type {import("snowpack").SnowpackUserConfig } */
module.exports = {
mount: {
public: { url: '/', static: true },
src: { url: '/dist' },
},
plugins: ['#snowpack/plugin-react-refresh'],
packageOptions: {
/* ... */
},
devOptions: {
/* ... */
},
buildOptions: {
/* ... */
},
};
package.json
{
"name": "chatclient",
"version": "1.0.0",
"description": "",
"scripts": {
"start": "snowpack dev",
"build": "snowpack build",
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"#snowpack/plugin-react-refresh": "^2.4.0",
"snowpack": "^3.0.11"
}
}
I hope someone can help me. Snowpack is such an amazing tool but i can't get it to work.
I found a solution
Credits
I used to run my dev environment on wsl2. Some no known reason does nodejs not hot reload when you are in wsl2 and the files are on the windows filesystem. Moved everything to my linux filesystem and i worked.
I hope someone will find this helpful!

electron-builder not working for production due to path

everyone
I created a React app in order to build an electron app. I'm trying to use electron-builder to create the installers. I'm working on Ubuntu trying to generate a .deb.
I didn't use create-react-app, I used a boilerplate I already had, but I don't know if this is the problem.
I can make it work as long as I edit the index.html the webpack generates in the build folder. I have to change the path to main.css and build.js from /main.css and /build.js to ./main.css and ./build.js.
I read that I have to use the "homepage" property in package.json, but it's not working, seems to be ignored.
My folder structure is like:
package.json
src/
config/
main_electron_file.js
build/ #generated by webpack when I run the 'build:prd' command
public/ #empty
package.json
{
"name": "frontend",
"version": "1.0.0",
"description": "",
"main": "./main_electron_file.js",
"scripts": {
"dev": "./node_modules/.bin/webpack-dev-server --config ./config/webpack.config.dev.js --mode development --open --hot",
"build:prd": "./node_modules/webpack/bin/webpack.js --mode production --config ./config/webpack.config.prd.js --env.NODE_ENV=production --progress",
"electron": "electron .",
"start": "npm run dev && npm run electron",
"start:dev": "ELECTRON_START_URL=http://localhost:3000 electron .",
"dist": "build"
},
"keywords": [],
"author": {
"name": "name",
"email": "email#mail.com"
},
"license": "ISC",
"dependencies": {
...
},
"devDependencies": {
...
},
"homepage": "./",
"build": {
"appId": "com.myself.myapp",
"linux": {
"target": [
"deb"
]
}
}
}
main_electron_file.js
// Modules to control application life and create native browser window
const { app, BrowserWindow } = require('electron');
const path = require('path');
const url = require('url');
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let mainWindow
function createWindow() {
const startUrl = process.env.ELECTRON_START_URL || url.format({
pathname: path.join(__dirname, 'build/index.html'),
protocol: 'file:',
slashes: true
});
// Create the browser window.
mainWindow = new BrowserWindow({ width: 800, height: 600, resizeble: false });
mainWindow.setResizable(false);
// and load the index.html of the app.
// win.loadURL('http://localhost:3000');
mainWindow.loadURL(startUrl);
// Open the DevTools.
mainWindow.webContents.openDevTools()
// Emitted when the window is closed.
mainWindow.on('closed', function () {
// Dereference the window object, usually you would store windows
// in an array if your app supports multi windows, this is the time
// when you should delete the corresponding element.
mainWindow = null
})
}
// This method will be called when Electron has finished
// initialization and is ready to create browser windows.
// Some APIs can only be used after this event occurs.
app.on('ready', createWindow)
// Quit when all windows are closed.
app.on('window-all-closed', function () {
// On OS X it is common for applications and their menu bar
// to stay active until the user quits explicitly with Cmd + Q
if (process.platform !== 'darwin') {
app.quit()
}
})
app.on('activate', function () {
// On OS X it's common to re-create a window in the app when the
// dock icon is clicked and there are no other windows open.
if (mainWindow === null) {
createWindow()
}
})
// In this file you can include the rest of your app's specific main process
// code. You can also put them in separate files and require them here.
By the way. I'm not building it. I'm running it pointing to the index.html in the dist, as I would do in production mode. So i'm running npm run build:prd and then npm run electron
ANy ideas how I could make this process automatic?
Please try adding this line in your index.html
<base href="./">
And your main.css and build.js directory should be set relative to your index.html in build folder
What worked for me was:
Add to webpack config:
output: {
publicPath: './',
...
}
This tells webpack to have every link between files it creates based at the same directory.
As suggested by carlokid, add to index.html:
< base href="./" />

Transpiling NextJS for IE 10/11; 'Weakset undefined'

I have a NextJS website I'm building and it's great, except that it does not work in IE 10/11 because some code is not being transpiled correctly. I'm really bad with babel and webpack, and have never had to config them myself before. I've been trying to solve by reading online for two days now, and nothing seems to work for me.
The exact error I get is weakSet is not defined, and it is coming from the common.js file.
Here is my .babelrc file, located in the root of my project.
// .babelrc
{
"presets": ["next/babel"],
"plugins": [
["styled-components", {
"ssr": true,
"displayName": true,
"preprocess": false
}]
]
}
my package.json
{
"name": "bradshouse",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "next",
"build": "next build",
"start": "next start"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"next": "^7.0.2",
"react": "^16.6.0",
"react-dom": "^16.6.0",
"react-pose": "^4.0.1",
"styled-components": "^4.0.2"
},
"devDependencies": {
"babel-plugin-styled-components": "^1.8.0"
}
}
The full repo is here if you're interested in launching it yourself. node modules are excluded, so npm install, then npm run build, then npm run start.
https://github.com/TJBlackman/Brads-House
Thanks for the help! Feel free to just link articles and I'll read them thoroughly! Thanks.
Edit: As a quick fix, I added this polyfill script to the <head> of all my pages, and it still did not fix this issue... Wat?! <script src="https://cdn.polyfill.io/v2/polyfill.min.js"></script>
How to support IE 11 by transpiling node_modules code in NextJS
Original answer found in the ziet/nextjs issues thread (view here). Shout out to joaovieira <3
npm install --save-dev babel-polyfill
create a polyfill.js where ever you want it, and inside that file, import the babel-polyfill like so:
import 'babel-polyfill';
Next, if you do not have a next.config.js file, create it at your root directory. Now update your this file to include the following webpack config. Notice how it's using the polyfill file you just made. Full file example:
module.exports = {
webpack: (config) => {
// Unshift polyfills in main entrypoint.
const originalEntry = config.entry;
config.entry = async () => {
const entries = await originalEntry();
if (entries['main.js']) {
entries['main.js'].unshift('./path_to/polyfills.js'); // <- polyfill here
}
return entries;
};
return config;
}
}
Finally, if you don't have a .babelrc file in your project's root directory, create one. Inside it, use the code below that matches the version of babel you're using.
Babel 7
{
"presets": [
[
"next/babel",
{
"preset-env": {
"useBuiltIns": "usage"
}
}
]
]
}
Babel 6
{
"presets": [
[
"next/babel",
{
"preset-env": {
"targets": {
"browsers": "defaults"
},
"useBuiltIns": true
}
}
]
]
}
That's all I know. I'm not even thinking about IE 10...
Good luck!!
I am using next#9.3 with reflect-metadata, and here is my solution:
/** next.config.js > webpack **/
const pathToPolyfills = './src/polyfills.js'
// Fix [TypeError: Reflect.metadata is not a function] during production build
// Thanks to https://leerob.io/blog/things-ive-learned-building-nextjs-apps#polyfills
// There is an official example as well: https://git.io/JfqUF
const originalEntry = config.entry
config.entry = async () => {
const entries = await originalEntry()
Object.keys(entries).forEach(pageBundleEntryJs => {
let sourceFilesIncluded = entries[pageBundleEntryJs]
if (!Array.isArray(sourceFilesIncluded)) {
sourceFilesIncluded = entries[pageBundleEntryJs] = [sourceFilesIncluded]
}
if (!sourceFilesIncluded.some(file => file.includes('polyfills'))) {
sourceFilesIncluded.unshift(pathToPolyfills)
}
})
return entries
}
/** src/polyfills.js **/
// Other polyfills ...
import 'reflect-metadata'

Resources