Browserify cannot find module 'react-router-dom' - reactjs

I try to play with react-router but can't make it working with browserify. I'm stuck with this error:
events.js:182
throw er; // Unhandled 'error' event
^
Error: Cannot find module 'react-router-dom' from '/usr/src/app'
at /usr/src/app/node_modules/browserify/node_modules/browser-resolve/node_modules/resolve/lib/async.js:46:17
at process (/usr/src/app/node_modules/browserify/node_modules/browser-resolve/node_modules/resolve/lib/async.js:173:43)
at ondir (/usr/src/app/node_modules/browserify/node_modules/browser-resolve/node_modules/resolve/lib/async.js:188:17)
at load (/usr/src/app/node_modules/browserify/node_modules/browser-resolve/node_modules/resolve/lib/async.js:69:43)
at onex (/usr/src/app/node_modules/browserify/node_modules/browser-resolve/node_modules/resolve/lib/async.js:92:31)
at /usr/src/app/node_modules/browserify/node_modules/browser-resolve/node_modules/resolve/lib/async.js:22:47
at FSReqWrap.oncomplete (fs.js:152:21)
npm info lifecycle irregular_verbs#1.0.0~start: Failed to exec start script
My first js file is server.js which generate a bundle to load app.js.
I removed everything on my app.js file to be sure that no personal components create a conflict. So it is very light now! But still doesn't work.
My app.js file:
var React = require('react');
require('react-router-dom');
React.render(<div><p>Blop</p></div>, document.getElementById('base_ihm'));
Without the require('react-router-dom');, everything works!
My server.js:
var express = require('express');
var browserify = require('browserify');
var React = require('react');
var jsx = require('node-jsx');
var app = express();
// Constants
const PORT = 8080;
jsx.install();
// Enable compression
var compression = require('compression');
app.use(compression());
// Create a path name bundle.js which call app.js and apply browserify
app.use('/bundle.js', function(req, res) {
res.setHeader('content-type', 'application/javascript');
browserify('./app.js', {
debug: true
})
.transform('reactify')
.bundle()
.pipe(res);
});
// static ressources
app.use(express.static(__dirname + '/static/css'));
app.use(express.static(__dirname + '/static/images'));
// Main route
app.use('/', function(req, res) {
res.setHeader('Content-Type', 'text/html');
res.end(React.renderToStaticMarkup(
React.createElement(
'html', null,
// Header
React.createElement(
'head', null,
// Title
React.createElement('title', null, 'Irregular Verbs'),
// Meta
React.createElement('meta', {charSet: 'UTF-8'}, null),
React.createElement('meta', {name: 'viewport', content: 'width=device-width, initial-scale=1'}, null),
// Custom CSS
React.createElement('link', { rel: 'stylesheet', href: 'main.css' }, null)
),
// Body
React.DOM.body(
null,
React.DOM.div({
id: 'base_ihm',
dangerouslySetInnerHTML: {
__html: React.renderToString(React.createElement('div', null))
}
}),
// Use the path create just before
React.DOM.script({
src: '/bundle.js'
})
)
)
));
});
var server = app.listen(PORT, function() {
var addr = server.address();
console.log('Listening # http://%s:%d', addr.address, addr.port);
});
Is react-router well installed?
There is the content of my package.json file:
{
"main": "server.js",
"scripts": {
"start": "node server.js"
},
"dependencies": {
"express": "^4.13.3",
"body-parser": "^1.15.2",
"node-jsx": "^0.13.3",
"react": "^15.6.1",
"react-dom": "^15.6.1",
"react-router-dom": "^4.0.0",
"browserify": "^14.4.0",
"reactify": "^1.1.1",
"mysql": "^2.11.1"
}
}
I use docker and docker-compose. On my Dockerfile, I added RUN npm ls and RUN ls node_modules: I can see react-router and react-router-dom. So there are here!
Any cache with docker?
I rename my image to be sure to use the good one and not an old one.
I also restart my container using docker-compose up --force-recreate.
So I presume it is ok.
Erreur with server.js where browserify is used
I think I've made a mistake in my server.js file but I have no idea...
There are what I have tried with no success:
I try to add a global:true then global:false at my transform('reactify')
In my Dockerfile, I try to add npm install react-router-dom -g to be sure it was installed
I finaly upgraded my versions. And also tried react-router-dom in version 4.1.1
I replace the require('react-router-dom') by require('./node_modules/react-router-dom') but get the same error (except it was the new path which wasn't found).
Do you have any idea?
Thank you for your help!

Sorry for the late answer. It was finaly a Docker/Docker-compose problem...
Even using docker-compose up --force-recreate, the old image was still used.
I renamed my container in my docker-compose.yml file so at the next start, it created a new container with the new image.

Related

process.env empty object in Cypress

I am working on a React app bootstraped from create-react-app few years ago.
The app has a .env.dev file with many variables.
The start script is "start": "env-cmd -f .env.dev --use-shell \"react-scripts start\"",
React script version: "react-scripts": "^4.0.1",
When I console.log("gggg", process.env); I get all the variables.
When I:
describe('Login via API', () => {
it('Test login', () => {
console.log('teeest', process.env)
cy.login()
})
})
instead I get an empty object.
I tried to read the question How to use process.env variables in browser running by Cypress
however this question does not answer my question on how to make the process.env variables available to Cypress test files.
Also this question says to install dotenv. Dotenv comes with react-scripts, so no need to install it if the app was create by create-react-app.
I also tried this:
in cypress.config.js I added:
const { defineConfig } = require("cypress");
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
config.env = process.env
return config
}
}
})
And in the spec I try to get the variable defined in .env.dev file:
it('Test login', () => {
console.log('new', Cypress.env('REACT_APP_USERNAME'))
cy.login()
})
Still getting undefined.
Can anyone please help me to understand what's wrong? How can I make it work?
Edit:
According to an answer here I tried to install dotenv:
npm install dotenv --save
imported in the test:
import 'dotenv/config'
describe('Login via API', () => {
it('Test login', () => {
console.log('newwwww', Cypress.env('REACT_APP_USERNAME'))
console.log('teeest', process.env)
cy.login()
})
})
Npm start
npm run cypress:open
Result:
newwwww undefined
login-test.cy.js:7 teeest {}
Thanks
When you use "start": "env-cmd -f .env.dev --use-shell \"react-scripts start\"", the env-cmd command is specific to the process for the react app.
You would need the same to run before cypress opens it's process
package.json
{
...
"dependencies": {
...
},
"scripts": {
"cy:open": "env-cmd -f .env.dev cypress open",
...
}
}
Avoiding conflict with other env setting
I also recommend using the spread operator as shown below, otherwise you would lose any env var added in other ways, e.g command line additions.
const { defineConfig } = require("cypress");
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
config.env = {
...process.env, // add all process env var here
...config.env // plus any command line overrides
}
return config // return the altered config
},
},
env: {
login_url: '/login', // define some specific env var here
products_url: '/products'
}
});
Avoiding pollution of Cypress settings
If you take a look at Settings/Project Settings in the Cypress runner, you'll see a huge number of unnecessary settings which come from the general machine env var.
To pick just those with prefix REACT_,
const { defineConfig } = require("cypress");
module.exports = defineConfig({
e2e: {
setupNodeEvents(on, config) {
const reactEnv = Object.keys(process.env).reduce((obj, key) => {
if (key.startsWith('REACT_')) {
obj[key] = process.env[key];
}
return obj;
}, {});
config.env = {
...reactEnv, // add REACT_ process env var here
...config.env // plus any command line overrides
}
return config // return the altered config
},
},
env: {
login_url: '/login', // define some specific env var here
products_url: '/products'
}
});
You're right about dotenv being included with react-scripts, but to access it in your test files you'll have to explicitly import it.
npm install dotenv
then at the top of your cypress code
import 'dotenv/config'
See usage instructions here
https://www.npmjs.com/package/dotenv

React application hosted on GCP using Docker only opens when i type the URL folowed by "//" double slash

So basically i have deployed a react application on docker using express to serve my build folders. But the after i deployed the application only opens when i follow the url with "//".
I have set the homepage property of package.json to "."
The main js chunk will not load if i just type the application URL . It will load only if the application url is followed by double slash for example https://example.com//
Can any one please make me understand why might this behavior occur? Following is the code for the server.js
const path = require("path");
const express = require("express");
const app = express();
const PORT = process.env.PORT || 3000;
app.use(express.static(path.join(__dirname, "..", "build")));
app.use(express.static("public"));
app.use((req, res, next) => {
res.sendFile(path.join(__dirname, "..", "build", "index.html"));
});
app.listen(PORT, () => {
console.log(`Server started on PORT ${PORT}`);
});
Dockerfile
FROM node:16 AS ui-build
WORKDIR /usr/src/app/
COPY . .
RUN npm install && npm run build
EXPOSE 3000
ENV PORT 3000
ENTRYPOINT ["node", "server/server.js"]
package.json
{
"name": "app",
"version": "0.1.0",
"homepage": ".",
"private": true,
"dependencies": {...
}

Error: Couldn't find a style target. It started to appear after SSR with React implementation. How to fix?

I had a CSR app and now implemented Server-Side Rendering (SSR) with React, and get this error
Error: Couldn't find a style target
We used reactDOMserver, react-app-wire, with webpack-override file
See webpack configs below:
const { resolve } = require("path");
require("ignore-styles");
module.exports = {
webpack: function (config) {
config.entry = resolve(dirname, "../client/src/ssr");
config.optimization = undefined;
config.output = {
filename: "ssr.js",
globalObject: 'this',
libraryTarget: "commonjs",
path: resolve(dirname, "../client/build"),
};
return config;
},
};
from server
app.get("^/$", (req, res) => {
Object.assign(global, {
navigation: {},
window: ssr.getWindow(),
navigator: {
userAgent: req.headers["user-agent"],
},
global: {},
document:ssr.ssrDocument
});
const App = require("./build/ssr");
const context = {};
let app = App.default(req.url, context);
then res,render app
AND SSR JS FILE
ssr.js file :
import { renderToString } from "react-dom/server";
for renderToString(
....
<App/>
....
)
And received Error: Couldn't find a style target
I had a CSR app and now implemented Server-Side Rendering (SSR) with React, and get this error
Error: Couldn't find a style target. This probably means that the value for the 'insert' parameter is invalid
Get this error when I run the server and try to access the page.
We also tried other approaches with these loaders:
css-loader, sass loader and style-loader and even with isomorphic-style-loader
They led to the error with No PostCSS config and after fixing this by adding to the project postcss.config.js file AND AFTER we received same error about style target and additional error with antd
Error: No PostCSS Config found in: D:_PROJECT....\client\node_modules\antd\dist
Tech sack in use: nodejs, reactjs, antdesign, babel and webpack.
I already tried a lot of solutions from StackOverflow and other sources, nothing helped!
Please, help me to solve it.
Thank you!
I think you cannot use style-loader server side.
Find the loader like this: https://github.com/codebandits/react-app-rewire-css-modules/blob/master/index.js just use style-loader instead, and remove it.. or switch to razzle

jsx passed to react-dom/server renderToString

I'm trying to understand react-dom/server.
I have a react application, using express as the server.
I have an express route like so :
var server = app.listen(3000);
app.get('/test', (req, res) => {
const context = {}
const html = ReactDOMServer.renderToString(
<h1>foo</h1>
)
if (context.url) {
res.writeHead(302, {
Location: context.url
})
res.end()
} else {
res.write(html)
res.end()
}
});
If I run the server file with node app-server, I get this error :
<h1>adasd</h1>
^
SyntaxError: Unexpected token <
I passed JSX to renderToString based on the example there :
https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/StaticRouter.md
How can I make the express server file processed this JSX code ?
For the client side, I use webpack with the babel loader, and it works fine.
Thanks to #azium.
Solution was to first convert the ES6/JSX file with babel-cli .
I used this babel-cli command :
npx babel --no-babelrc script.js --out-file script-compiled.js --presets=es2015,react
npx is used to "execute npm package binaries"

serving react files with express

This is my first time serving react files with express.js. The build has been run and the server is listening, but I cant figure out why the components aren't being injected into the html file. Instead it's rendering just the html template.
Here is a picture of my build folder:
build folder structure
Here is my index.js file from my server folder:
const express = require('express');
const morgan = require('morgan');
const path = require('path');
const app = express();
app.use(morgan(':remote-addr - :remote-user [:date[clf]] ":method
:url HTTP/:http-version" :status :res[content-length] :response-time
ms'))
app.use(express.static(path.resolve(__dirname, '..', 'build')))
app.get('*', (req, res) => {
res.sendFile(path.resolve(__dirname,'..', 'build', 'index.html'))
});
const PORT = process.env.PORT || 3000;
app.listen(PORT, () => {
console.log(`App listening on port ${PORT}!`);
});
this what I see in the console:
served page console
Any help would greatly be appreciated.
This question is still unanswered and Im facing the same question. I have deployed the default react app to a build-directory and am hoping to serve the files through Express.
The browser actually received the deployed file BUT it shows me a blank page.
Any ideas?
Using a simple Express server:
const express = require("express");
const path = require("path");
const app = express();
app.use(express.static(".\build"));
app.get("*", (req, res) => {
res.sendFile(path.resolve(__dirname, ".", "build", "index.html"));
});
app.listen(8081, () => {
console.log(App listening on port 8081!);
});
See the following link
react-express-boilerplate
Add the following code to index.html file
<script src="src="/js/main.33e13313.js""></script>
main.33e13313.js is a file that packages js with webpack.
Your package.json file will be set as follow:
"scripts": {
"clean": "rm -rf build public/bundle.js",
"build": "babel server --out-dir build && webpack",
"start": "NODE_ENV=production supervisor ./build/main.js",
"development": "NODE_ENV=development node ./build/main.js"
},
You will use npm run build to run.
You can use babel to change es6 to es5. this is build tool.
You can use webpack to package JavaScript files. packagig is bundles JavaScript files into one file. this is packaging tool.

Resources