Unhandled Runtime Error ReferenceError: require is not defined (Electron + Next.js) - node.js

I'm writing (Electron + Next.js) nextron desktop app.
I want to use contextIsolation=true , when i enabled contextIsolation=true and use import in renderer file like (import axios from 'axios') and something like that (third party package) it shows required is not define i think so its webpack error.
Need help to solve this issue
Error message:
Preload.js
import { contextBridge, ipcRenderer } from 'electron'
//i try both import or require
contextBridge.exposeInMainWorld('electronAPI', {
setTitle: (title) => ipcRenderer.send('set-title', title)
})
**Renderer.js **
import React, { useEffect } from 'react';
import Head from 'next/head';
import Link from 'next/link';
//When i import axios here, it doesn't works
import axios from 'axios'
function Home() {
useEffect(() => {
const setButton = document.getElementById('btn')
const titleInput = document.getElementById('title')
setButton.addEventListener('click', () => {
const title = titleInput.value
window.electronAPI?.setTitle(title)
});
data()
}, [])
return (
<React.Fragment>
<Head>
<title>Home - Nextron (with-typescript-tailwindcss)</title>
</Head>
Title: <input id="title" />
<button id="btn" type="button">Set</button>
</React.Fragment>
);
}
export default Home;
Background.ts
import { app, ipcMain, BrowserWindow } from "electron";
import serve from "electron-serve";
import path from "path";
import { createWindow } from "./helpers";
const isProd: boolean = process.env.NODE_ENV === "production";
if (isProd) {
serve({ directory: "app" });
} else {
app.setPath("userData", `${app.getPath("userData")} (development)`);
}
(async () => {
await app.whenReady();
const mainWindow = createWindow("main", {
width: 1000,
height: 600,
webPreferences: {
nodeIntegration:true,
contextIsolation: true,
preload: path.join(__dirname, "preload.js"),
},
});
if (isProd) {
await mainWindow.loadURL("app://./home.html");
} else {
const port = process.argv[2];
await mainWindow.loadURL(`http://localhost:${port}/home`);
mainWindow.webContents.openDevTools();
}
})();
ipcMain.on("set-title", (event, title) => {
const webContents = event.sender;
const win = BrowserWindow.fromWebContents(webContents);
win.setTitle(title);
console.log(title, "title");
});
app.on("window-all-closed", () => {
app.quit();
});
NextConfig.js
module.exports = {
webpack: (config, { isServer }) => {
if (!isServer) {
config.target = 'electron-renderer';
config.node = {
__dirname: true,
};
}
config.output.globalObject = 'this';
return config;
},
};

Related

Unhandled Runtime Error ReferenceError: require is not defined (Nextron)

I want to use contextIsolation=true when i enabled contextIsolation=true and use import in renderer file like (import axios from 'axios') [it through this error message]
https://i.stack.imgur.com/b7lsz.png
its webpack error , but having no solution to handle this issue
Preload.js file in nextron main folder
import { contextBridge, ipcRenderer } from 'electron'
//i try both import or require
contextBridge.exposeInMainWorld('electronAPI', {
setTitle: (title) => ipcRenderer.send('set-title', title)
})
**Renderer.js **
import React, { useEffect } from 'react';
import Head from 'next/head';
import Link from 'next/link';
//When i import axios here, it doesn't works
import axios from 'axios'
function Home() {
useEffect(() => {
const setButton = document.getElementById('btn')
const titleInput = document.getElementById('title')
setButton.addEventListener('click', () => {
const title = titleInput.value
window.electronAPI?.setTitle(title)
});
data()
}, [])
return (
<React.Fragment>
<Head>
<title>Home - Nextron (with-typescript-tailwindcss)</title>
</Head>
Title: <input id="title" />
<button id="btn" type="button">Set</button>
</React.Fragment>
);
}
export default Home;
Background.ts nextron main folder
import { app, ipcMain, BrowserWindow } from "electron";
import serve from "electron-serve";
import path from "path";
import { createWindow } from "./helpers";
const isProd: boolean = process.env.NODE_ENV === "production";
if (isProd) {
serve({ directory: "app" });
} else {
app.setPath("userData", `${app.getPath("userData")} (development)`);
}
(async () => {
await app.whenReady();
const mainWindow = createWindow("main", {
width: 1000,
height: 600,
webPreferences: {
nodeIntegration:true,
contextIsolation: true,
preload: path.join(__dirname, "preload.js"),
},
});
if (isProd) {
await mainWindow.loadURL("app://./home.html");
} else {
const port = process.argv[2];
await mainWindow.loadURL(`http://localhost:${port}/home`);
mainWindow.webContents.openDevTools();
}
})();
ipcMain.on("set-title", (event, title) => {
const webContents = event.sender;
const win = BrowserWindow.fromWebContents(webContents);
win.setTitle(title);
console.log(title, "title");
});
app.on("window-all-closed", () => {
app.quit();
});
NextConfig.js
module.exports = {
webpack: (config, { isServer }) => {
if (!isServer) {
config.target = 'electron-renderer';
config.node = {
__dirname: true,
};
}
config.output.globalObject = 'this';
return config;
},
};

StreamMessageReader is not a constructor in Electron + Monaco app

I'm trying to build an application using Electron with Monaco editor. I used monaco language client to integrate the editor with clangd. But somehow it didn't work... After manually connecting to the LSP server through web socket, I get the following error in the terminal:
TypeError: node.exports.StreamMessageReader is not a constructor
at createStreamConnection (/Volumes/Data/Develop/cpcode/dist/electron/main.js:3100:18)
at createProcessStreamConnection (/Volumes/Data/Develop/cpcode/dist/electron/main.js:3094:12)
at createServerProcess (/Volumes/Data/Develop/cpcode/dist/electron/main.js:3090:10)
at launch (/Volumes/Data/Develop/cpcode/dist/electron/main.js:3114:28)
at /Volumes/Data/Develop/cpcode/dist/electron/main.js:3160:13
at WebSocketServer.completeUpgrade (/Volumes/Data/Develop/cpcode/node_modules/ws/lib/websocket-server.js:431:5)
at WebSocketServer.handleUpgrade (/Volumes/Data/Develop/cpcode/node_modules/ws/lib/websocket-server.js:339:10)
at Server.<anonymous> (/Volumes/Data/Develop/cpcode/dist/electron/main.js:3147:13)
at Server.emit (node:events:526:28)
at onParserExecuteCommon (node:_http_server:727:14)
I am starting the server in Electron main process. Here's the code for it:
process.env.DIST = join(__dirname, '..')
process.env.PUBLIC = app.isPackaged ? process.env.DIST : join(process.env.DIST, '../public')
import { join } from 'path'
import { app, BrowserWindow } from 'electron'
import ws from "ws";
import http from "http";
import url from "url";
import net from "net";
import express from "express";
import * as rpc from "vscode-ws-jsonrpc";
import * as server from "vscode-ws-jsonrpc/server";
import * as lsp from "vscode-languageserver";
import { Message } from "vscode-languageserver";
export function launch(socket: rpc.IWebSocket) {
const reader = new rpc.WebSocketMessageReader(socket);
const writer = new rpc.WebSocketMessageWriter(socket);
// start the language server as an external process
const socketConnection = server.createConnection(reader, writer, () =>
socket.dispose()
);
const serverConnection = server.createServerProcess("CPP", "clangd");
if (serverConnection) {
server.forward(socketConnection, serverConnection, (message) => {
if (Message.isRequest(message)) {
console.log("server request!!!");
if (message.method === lsp.InitializeRequest.type.method) {
const initializeParams = message.params as lsp.InitializeParams;
initializeParams.processId = process.pid;
}
}
return message;
});
}
}
process.on("uncaughtException", function (err: any) {
console.error("Uncaught Exception: ", err.toString());
if (err.stack) {
console.error(err.stack);
}
});
export const startLSP = () => {
// create the express application
const app = express();
// server the static content, i.e. index.html
app.use(express.static(__dirname));
// start the server
const server = app.listen(3000);
// create the web socket
const wss = new ws.Server({
noServer: true,
perMessageDeflate: false
});
server.on(
"upgrade",
(request: http.IncomingMessage, socket: net.Socket, head: Buffer) => {
// eslint-disable-next-line n/no-deprecated-api
const pathname = request.url
? url.parse(request.url).pathname
: undefined;
if (pathname === "/lsp") {
wss.handleUpgrade(request, socket, head, (webSocket) => {
const socket: rpc.IWebSocket = {
send: (content) =>
webSocket.send(content, (error) => {
if (error) {
throw error;
}
}),
onMessage: (cb) => webSocket.on("message", cb),
onError: (cb) => webSocket.on("error", cb),
onClose: (cb) => webSocket.on("close", cb),
dispose: () => webSocket.close()
};
// launch the server when the web socket is opened
if (webSocket.readyState === webSocket.OPEN) {
launch(socket);
} else {
webSocket.on("open", () => launch(socket));
}
});
}
}
);
};
let win: BrowserWindow | null
// Here, you can also use other preload
const preload = join(__dirname, './preload.js')
// 🚧 Use ['ENV_NAME'] avoid vite:define plugin - Vite#2.x
const serverURL = process.env['VITE_DEV_SERVER_URL']
function createWindow() {
win = new BrowserWindow({
icon: join(process.env.PUBLIC, 'logo.svg'),
webPreferences: {
contextIsolation: false,
nodeIntegration: true,
preload,
},
titleBarStyle: process.platform === 'darwin' ? 'hiddenInset' : 'hidden',
})
startLSP();
// Test active push message to Renderer-process.
win.webContents.on('did-finish-load', () => {
win?.webContents.send('main-process-message', (new Date).toLocaleString())
})
if (app.isPackaged) {
win.loadFile(join(process.env.DIST, 'index.html'))
} else {
win.loadURL(serverURL)
}
}
app.on('window-all-closed', () => {
win = null
})
app.whenReady().then(createWindow)
I am using Vite as a bundler and I'm not sure if it has anything to do with this. Anyway, here's my vite.config.ts:
import fs from 'fs'
import path from 'path'
import { defineConfig } from 'vite'
import electron from 'vite-plugin-electron'
import renderer from 'vite-plugin-electron-renderer';
import { nodePolyfills } from 'vite-plugin-node-polyfills'
fs.rmSync('dist', { recursive: true, force: true }) // v14.14.0
export default defineConfig({
plugins: [
electron({
main: {
entry: 'electron/main.ts',
},
preload: {
input: {
// Must be use absolute path, this is the restrict of Rollup
preload: path.join(__dirname, 'electron/preload.ts'),
},
},
// Enables use of Node.js API in the Renderer-process
// https://github.com/electron-vite/vite-plugin-electron/tree/main/packages/electron-renderer#electron-renderervite-serve
renderer: {},
}),
nodePolyfills({
// Whether to polyfill `node:` protocol imports.
protocolImports: true,
}),
],
})
After Googling, I tried to install vscode-languageserver and vscode-languageserver-protocol, but no luck. The problem still continues.
Does anyone has a solution to this? Thanks in advance!

Increase body limit with nestjs & fastify

My main.ts looks like this :
import { NestFactory } from '#nestjs/core';
import { FastifyAdapter, NestFastifyApplication } from '#nestjs/platform-fastify';
import { Logger } from 'nestjs-pino';
import { processRequest } from 'graphql-upload';
import { AppModule } from './app.module';
async function bootstrap() {
const adapter = new FastifyAdapter();
const fastifyInstance = adapter.getInstance();
fastifyInstance.addContentTypeParser('multipart', (request, done) => {
request.isMultipart = true;
done();
});
fastifyInstance.addHook('preValidation', async (request: any, reply) => {
if (!request.raw.isMultipart) {
return;
}
request.body = await processRequest(request.raw, reply.raw);
});
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
adapter,
{ bufferLogs: true },
);
app.useLogger(app.get(Logger));
app.enableCors();
await app.listen(parseInt(process.env.SERVER_PORT || '3000', 10), '0.0.0.0');
}
bootstrap();
According to the fastify doc the body limit is 1MiB by default, however I want it to be larger. So I tried like this :
const adapter = new FastifyAdapter({ bodyLimit: 124857600 }); but I still get the same problem with my payload being too large.
Try to add this when you are creating the app
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter({ bodyLimit: 10048576 }),

Multiple listeners & removeListener removes everything Socket.io

Folks! I am writing a socket.io chat. When the user sends a message, the socket.on event occurs. Everything works, but the amount of listeners is growing exponentially. I tried to remove the listener with socket.off/socket.remove..., take out the event socket.on separately from connection - nothing works. Please, please help me figure it out. I`m using react, node, socket & mongoDB
Server part:
const express = require("express");
const app = express();
const cors = require("cors");
const { UserModel } = require("./models");
app.use(cors());
app.use(express.json());
app.use(express.urlencoded({ extended: true }));
app.options("http://localhost:3000", cors());
const mongoose = require("mongoose");
require("dotenv").config();
const http = require("http").createServer(app);
const io = require("socket.io")(http, {
cors: {
origin: ["http://localhost:3002"],
},
});
http.listen(3001, function () {
console.log("Server is running");
});
io.on("connection", (socket) => {
console.log("Socket connected", socket.id);
socket.on("message:send", (data) => {
console.log("Пришло в socket.onMessage", data);
socket.emit("message:fromServer", data);
// socket.removeListener("message:fromServer");
});
});
const { userApi } = require("./api/userApi");
app.use("/", userApi);
app.use((err, _, res, __) => {
return res.status(500).json({
status: "fail",
code: 500,
message: err.message,
});
});
const { PORT, DB_HOST } = process.env;
const dbConnection = mongoose.connect(DB_HOST, {
useNewUrlParser: true,
useFindAndModify: false,
useCreateIndex: true,
useUnifiedTopology: true,
});
dbConnection
.then(() => {
console.log("DB connect");
app.listen(PORT || 3000, () => {
console.log("server running");
});
})
.catch((err) => {
console.log(err);
});
Client part:
io.js
import { io } from "socket.io-client";
export const socket = io("http://localhost:3001/");
Message component
import React from "react";
import { useState } from "react";
// import { useSelector } from "react-redux";
// import { getMessages } from "../../Redux/selectors";
import { socket } from "../helpers/io";
import Message from "../Message/Message";
import { nanoid } from "nanoid";
export default function MessageFlow() {
const [message, setMessage] = useState([]);
socket.on("message:fromServer", (data) => {
console.log("На фронт пришло сообщение: ", data);
setMessage([...message, data]);
// setMessage((message) => [...message, data]);
console.log("Массив сообщений компонента MessageFlow", message);
console.log(socket.io.engine.transports);
// socket.off();
// getEventListeners(socket)['testComplete'][0].remove()
// socket.removeListener("message:fromServer");
});
// const dispatch = useDispatch();
// const allMessages = useSelector(getMessages);
return (
<div id="mainDiv">
{message &&
message.map((i) => {
// return <Message />;
return <Message content={i.userId} id={nanoid()} />;
})}
</div>
);
}
Message Form - the beginning of emitting process
import React, { useState } from "react";
import { useDispatch, useSelector } from "react-redux";
import { sendMessage } from "../../Redux/Chat/Chat-operations";
import { getUser } from "../../Redux/selectors";
import { getToken } from "../../Redux/Auth/Auth-selectors";
import { socket } from "../helpers/io";
import { useEffect } from "react";
import styles from "./MessageForm.module.css";
export default function MessageForm() {
const [message, setMessage] = useState("");
const dispatch = useDispatch();
const userId = useSelector(getUser);
const currentToken = useSelector(getToken);
// const getAll = useSelector(allContacts);
const updateMessage = (evt) => {
setMessage(evt.target.value);
};
const handleSubmit = (e) => {
e.preventDefault();
if (message) {
socket.emit("message:send", { userId: message });
dispatch(
sendMessage(
{
_id: userId,
text: message,
},
currentToken
)
);
} else {
alert(`Молчать будем?`);
}
};
return (
<div className={styles.messageInputContainer}>
<form>
<input
type="text"
value={message}
onChange={updateMessage}
required
className={styles.messageInput}
placeholder="Type message to send"
/>
<button
type="submit"
className={styles.messageAddBtn}
onClick={handleSubmit}
>
Send
</button>
</form>
</div>
);
}
You add a listener on every render, you should use useEffect hook
export default function MessageFlow() {
useEffect(()=>{ // triggered on component mount or when dependency array change
const callback = (data) => {
// what you want to do
}
socket.on("message:fromServer", callback);
return () => { // on unmount, clean your listeners
socket.removeListener('message:fromServer', callback);
}
}, []) // dependency array : list variables used in your listener
// [...]
}

Jest - Invariant failed: You should not use <Link> outside a <Router>

I'm getting this error when running a test, however I have wrapped the component I am testing in a <BrowserRouter> component:
● Axios › gets a response
Invariant failed: You should not use <Link> outside a <Router>
91 |
92 | if (RootComponent) {
> 93 | const component = mountWithCustomWrappers(<Wrapper store={store}><RootComponent
{...props} />, rootWrappers);
nock.integration.test
import React from 'react';
import axios from 'axios';
const core = require('tidee-life-core');
import httpAdapter from 'axios/lib/adapters/http';
import doFetch from '../../../helpers/doFetch.js';
import ComponentBuilder from "../component-builder";
import LoginPage from "../../../scenes/login/login-page";
const host = 'http://example.com';
process.env.API_URL = host;
axios.defaults.host = host;
axios.defaults.adapter = httpAdapter;
const makeRequest = () => {
return doFetch({
url: core.urls.auth.login(),
queryParams: { foo: 'bar' },
})
.then(res => res.data)
.catch(error => console.log(error));
};
describe('Axios', () => {
let component;
let componentBuilder;
beforeEach(() => {
componentBuilder = new ComponentBuilder();
});
test('gets a response', async () => {
componentBuilder.includeInterceptor('login');
component = await componentBuilder.build({
RootComponent: LoginPage,
selector: 'LoginForm',
});
return makeRequest()
.then(response => {
expect(typeof response).toEqual('object');
expect(response.data.token).toEqual('eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJhNDY3MGE3YWI3ZWM0ZjQ2MzM4ODdkMzJkNzRkNTY5OSIsImlhdCI6MTU1MjA5MDI1NX0.vsKLXJEqSUZK-Y6IU9PumfZdW7t1SLM28jzJL89lcrA');
});
});
});
login-page.jsx:
import React, { Component } from 'react';
import PropTypes from "prop-types";
import { withRouter } from 'react-router-dom';
import { injectIntl, intlShape } from 'react-intl';
import queryString from 'query-string';
import { Link } from 'tidee-life-ui';
import LoginForm from './login-form.jsx';
import { doLogin } from '../../api/auth/auth-api';
import Auth from '../../modules/Auth';
import messages from '../../messages';
const { urls } = require('tidee-life-core');
class LoginPage extends Component {
constructor(props) {
super(props);
const { intl } = props;
if (Auth.isUserAuthenticated()) {
props.history.replace({ pathname: urls.pages.pathBoxes() });
}
this.messages = {
'account.activation.error.expired': intl.formatMessage(messages['account.activation.error.expired']),
'account.activation.required': intl.formatMessage(messages['account.activation.required']),
'common.click': intl.formatMessage(messages['common.click']),
'common.here': intl.formatMessage(messages['common.here']),
'error.500.msg': intl.formatMessage(messages['error.500.msg']),
'forgot.success': intl.formatMessage(messages['forgot.success']),
'login.account.needs.activating.partial': intl.formatMessage(messages['login.account.needs.activating.partial']),
'login.error.account.credentials': intl.formatMessage(messages['login.error.account.credentials']),
'login.validation.email': intl.formatMessage(messages['login.validation.email']),
'login.validation.password': intl.formatMessage(messages['login.validation.password']),
'signup.account.created': intl.formatMessage(messages['signup.account.created'])
};
let alertMessage;
let alertMessageType;
const query = queryString.parse(props.location.search);
if ('signup-success' in query) {
alertMessage = this.messages['signup.account.created'];
alertMessageType = 'success';
} else if ('forgot-success' in query) {
alertMessage = this.messages['forgot.success'];
alertMessageType = 'success';
}
this.state = {
alert: {
type: alertMessageType ? alertMessageType : '',
msg: alertMessage ? alertMessage : '',
},
user: {
email: '',
password: ''
}
};
this.changeUser = this.changeUser.bind(this);
this.clearAlert = this.clearAlert.bind(this);
this.processForm = this.processForm.bind(this);
}
clearAlert() {
this.setState({ alert: {
type: '',
msg: '',
}});
}
processForm(e) {
e.preventDefault();
return doLogin({
email: this.state.user.email,
password: this.state.user.password,
}).then((response) => {
Auth.authenticateUser(response.data.token);
this.props.history.replace({ pathname: urls.pages.pathBoxes() });
}).catch((error) => {
const msg = error.message && this.messages[error.message] ? [this.messages[error.message]] : [this.messages['error.500.msg']];
if (error.message === 'account.activation.error.expired' || error.message === 'account.activation.required') {
const to = urls.pages.pathResendLink(error.data.confirmHash);
msg.push(` ${this.messages['common.click']} `);
msg.push(<Link underline color="inherit" key="email" to={to}>{this.messages['common.here']}</Link>);
msg.push(` ${this.messages['login.account.needs.activating.partial']}`);
}
this.setState({
alert: {
type: 'error',
msg,
}
});
});
}
changeUser(event) {
const { name, value } = event.target;
this.setState((currentState) => ({
user: {
...currentState.user,
[name]: value,
}
}));
}
render() {
return (
<LoginForm
data-test="login-form"
alert={this.state.alert}
onSubmit={this.processForm}
onChange={this.changeUser}
user={this.state.user}
/>
);
}
}
LoginPage.propTypes = {
history: PropTypes.object,
intl: intlShape.isRequired,
location: PropTypes.object.isRequired,
};
export default injectIntl(withRouter(LoginPage));
component-builder.js
import React from "react";
import nock from 'nock';
import cloneDeep from 'lodash.clonedeep';
import { mountWithCustomWrappers } from 'enzyme-custom-wrappers';
import { waitForStoreState } from './wait/wait-for-store-state';
import Wrapper from './wrapper.jsx';
import waitForComponentPredicate from './wait-for-component-predicate/wait-for-component-predicate';
import waitForComponentSelector from './wait-for-component-selector/wait-for-component-selector';
import { startAllNockServiceIntercepts } from './nock/nock-manager';
import nockServices from './nock/services';
import store from "../../store/store";
import wrappers from './wrappers';
const rootWrappers = component => wrappers(component);
class ComponentBuilder {
constructor() {
this.nockInterceptors = [];
this.storePreparers = [];
}
includeInterceptor( interceptorName, nockConfigOverride = null ) {
// Maybe need to do a clone deep here if things start breaking!
const clonedNockService = cloneDeep(nockServices[interceptorName]().nockConfig);
const nockService = {
[interceptorName]: {
...clonedNockService,
...(nockConfigOverride || {}),
}
};
this.nockInterceptors.push(nockService);
}
prepareStore( storePreparer ) {
this.storePreparers.push(storePreparer);
}
async waitForStoreToUpdate() {
const promises = this.storePreparers
.map(service => waitForStoreState(service.redux.storeStateToWaitFor, store));
await Promise.all(promises);
}
async runStorePreparers() {
nock.cleanAll();
const interceptors = [];
this.storePreparers.forEach((service) => {
const interceptorName = service.http.interceptor;
const clonedNockService = service.http.interceptor && cloneDeep(nockServices[interceptorName]().nockConfig);
interceptors.push({
[interceptorName]: {
...clonedNockService,
}
});
});
startAllNockServiceIntercepts(interceptors);
this.storePreparers.forEach(service => service.redux.actionToDispatch && store.dispatch(service.redux.actionToDispatch()));
return await this.waitForStoreToUpdate();
}
/**
* Build a component to be tested.
* #param RootComponent
* #param selector {string} - A selector to wait for. CSS selector or name of component.
* #param props {object}
* #param store {object}
* #param predicate {function} - A function that returns true if a condition is met.
* #param predicateMaxTime {number}
* #param predicateInterval {number}
* #returns {Promise<*>}
*/
async build({
RootComponent = null,
selector = '',
props = {},
predicate = null,
predicateMaxTime = 2000,
predicateInterval = 10,
} = {}) {
try {
await this.runStorePreparers();
startAllNockServiceIntercepts(this.nockInterceptors);
if (RootComponent) {
const component = mountWithCustomWrappers(<Wrapper store={store}><RootComponent {...props} /></Wrapper>, rootWrappers);
if (selector) {
await waitForComponentSelector({ selector, rootComponent: component, store });
}
if (predicate) {
await waitForComponentPredicate({
predicate,
rootComponent: component,
store,
maxTime: predicateMaxTime,
interval: predicateInterval,
});
}
return component;
}
} catch(err) {
throw err;
}
}
}
export default ComponentBuilder;
wrapper.jsx
import PropTypes from 'prop-types';
import React, { Component } from 'react';
import { BrowserRouter } from "react-router-dom";
import { Provider } from 'react-redux';
import ThemeProvider from "../../theme/Theme.jsx";
import LocaleProviderWrapper from "./locale-provider-wrapper.jsx";
const propTypes = {
children: PropTypes.element.isRequired,
store: PropTypes.object.isRequired,
};
class Wrapper extends Component {
getStore() {
return this.props.store;
}
render() {
return (
<Provider store={this.props.store}>
<LocaleProviderWrapper>
<ThemeProvider>
<BrowserRouter>{this.props.children}</BrowserRouter>
</ThemeProvider>
</LocaleProviderWrapper>
</Provider>
);
}
}
Wrapper.propTypes = propTypes;
export default Wrapper;
Exactly as message says, you cannot use Link which doesn't have any parent of type Router. In you processForm function you are building a messaage with Link component which is worng.
if (error.message === 'account.activation.error.expired' || error.message === 'account.activation.required') {
const to = urls.pages.pathResendLink(error.data.confirmHash);
msg.push(` ${this.messages['common.click']} `);
msg.push(<Link underline color="inherit" key="email" to={to}>{this.messages['common.here']}</Link>);
msg.push(` ${this.messages['login.account.needs.activating.partial']}`);
}
You should use a tag to build dynamic link. May be something like:
msg.push(`${this.messages['common.here']}`);

Resources