Serve multiple reactjs apps - Nodejs + Express + React - node.js

I'm trying to serve two separated Reactjs apps using Express.
App1
*Main app: displays different sets of data. Root front-end
*path: "/" (localhost:5000/)
App2
*Secondary App: User Dashboard, specific user-data.
*path: "/app" (localhost:5000/app)
I had a similar issue as:
1: Serving multiple react apps with client-side routing in Express
But that couldn't solve my problem.
Configuration files
App1 package.json
{
"name": "app1",
"version": "0.1.0",
"private": true,
"dependencies": {
"#fortawesome/fontawesome-svg-core": "^1.2.4",
"#fortawesome/free-solid-svg-icons": "^5.3.1",
"#fortawesome/react-fontawesome": "^0.1.3",
"axios": "^0.18.0",
"classnames": "^2.2.5",
"jwt-decode": "^2.2.0",
"moment": "^2.22.0",
"react": "^16.3.1",
"react-dom": "^16.3.1",
"react-image-gallery": "^0.8.11",
"react-moment": "^0.7.0",
"react-redux": "^5.0.7",
"react-router-dom": "^4.2.2",
"react-scripts": "1.1.4",
"redux": "^3.7.2",
"redux-thunk": "^2.2.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"proxy": "http://localhost:5000"
}
App2 package.json:
{
"name": "app2",
"version": "2.0.9",
"private": true,
"dependencies": {
"#coreui/coreui": "^2.0.4",
"#coreui/coreui-plugin-chartjs-custom-tooltips": "^1.2.0",
"#coreui/icons": "0.3.0",
"#coreui/react": "^2.0.5",
"bootstrap": "^4.1.3",
"chart.js": "^2.7.2",
"classnames": "^2.2.6",
"core-js": "^2.5.7",
"enzyme": "^3.5.0",
"enzyme-adapter-react-16": "^1.3.1",
"flag-icon-css": "^3.0.0",
"font-awesome": "^4.7.0",
"prop-types": "^15.6.2",
"react": "^16.4.2",
"react-chartjs-2": "^2.7.2",
"react-dom": "^16.4.2",
"react-loadable": "^5.5.0",
"react-router-config": "^1.0.0-beta.4",
"react-router-dom": "^4.3.1",
"react-test-renderer": "^16.4.2",
"reactstrap": "^6.4.0",
"simple-line-icons": "^2.4.1"
},
"devDependencies": {
"babel-jest": "^23.4.2",
"node-sass-chokidar": "^1.3.0",
"npm-run-all": "^4.1.3",
"react-scripts": "^1.1.5"
},
"scripts": {
"build-css": "node-sass-chokidar --include-path ./node_modules ./src/scss -o ./src/scss",
"watch-css": "npm run build-css && node-sass-chokidar --include-path ./node_modules ./src/scss -o ./src/scss --watch --recursive",
"start-js": "react-scripts start",
"start": "npm-run-all -p watch-css start-js",
"build-js": "react-scripts build",
"build": "npm-run-all build-css build-js",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"proxy": "http://localhost:5000",
"homepage": "http://localhost:5000/app2",
}
server.js
app.use("/app2", express.static(path.join(__dirname, "app2/build")));
app.get("app2/*", (req, res) => {
res.sendFile(path.join(__dirname + "/app2/build/index.html"));
});
app.use(express.static(path.join(__dirname, "app1/build")));
app.get("*", (req, res) => {
res.sendFile(path.join(__dirname + "/app1/build/index.html"));
});
localhost:5000 successfully renders app1, but if I try localhost:5000/app2/ it actually looks for a route=/app2/ within app1, therefore I got a blank page.
PS: I also tried this solution, but again, no good results.
Thank you!

By default CRA build will assume that your application is served from root directory. This is the reason you saw a blank page - HTML was served, but requests for js and css failed. (Actually, in your case it succeded - index.html was returned because you have a catch-all at the bottom of your server.js file)
Now this can be parametrized in package.json
If your app will be served at /app2 you need to add
//package.json
{
//...
"homepage":"app2"
}
Then your output files will have propper reference. You can check it out
I am attaching link to CRA docs - homepage attribute

Related

NestJS Project on Google App Engine shows error “Could not write file”

I try to deploy my nestJS application in app engine with standard env instance. But I received this error:
0mCould not write file '/workspace/dist/my/ts/file': EROFS: read-only file system, open '/workspace/dist/my/ts/file'.
I understand that nodejs will only be able to perform writing in the /tmp directory.
My question is: how can I put the workspace folder (created by cloud build) into tmp folder
here is my app.yaml:
runtime: nodejs12
env: standard
here my package.json:
{
"name": "elengui-api",
"version": "2.0.0",
"description": "",
"author": "",
"private": true,
"license": "UNLICENSED",
"scripts": {
"prebuild": "rimraf dist",
"build": "npx #nestjs/cli build",
"format": "prettier --write \"src/**/*.ts\" \"test/**/*.ts\"",
"start": "npx #nestjs/cli start",
"start:dev": "npx #nestjs/cli start --watch",
"start:debug": "npx #nestjs/cli start --debug --watch",
"start:prod": "node dist/main",
"lint": "eslint \"{src,apps,libs,test}/**/*.ts\" --fix",
"test": "jest",
"test:watch": "jest --watch",
"test:cov": "jest --coverage",
"test:debug": "node --inspect-brk -r tsconfig-paths/register -r ts-node/register node_modules/.bin/jest --runInBand",
"test:e2e": "jest --config ./test/jest-e2e.json",
"gcp-build": "npm run build",
"deploy": "gcloud app deploy"
},
"dependencies": {
"#hapi/joi": "^17.1.1",
"#nestjs/common": "^7.5.1",
"#nestjs/config": "^0.6.3",
"#nestjs/core": "^7.5.1",
"#nestjs/jwt": "^7.2.0",
"#nestjs/mapped-types": "^0.3.0",
"#nestjs/passport": "^7.1.5",
"#nestjs/platform-express": "^7.5.1",
"#nestjs/schedule": "^0.4.3",
"#nestjs/swagger": "^4.7.13",
"#nestjs/throttler": "^1.1.3",
"#nestjs/typeorm": "^7.1.5",
"#types/bcrypt": "^3.0.0",
"#types/cookie-parser": "^1.4.2",
"#types/hapi__joi": "^17.1.6",
"#types/nodemailer": "^6.4.0",
"#types/passport": "^1.0.6",
"#types/passport-jwt": "^3.0.4",
"#types/passport-local": "^1.0.33",
"bcrypt": "^5.0.0",
"class-transformer": "^0.4.0",
"class-validator": "^0.13.1",
"cookie-parser": "^1.4.5",
"crypto-random-string": "^3.3.1",
"csurf": "^1.11.0",
"express": "^4.17.1",
"hbs": "^4.1.1",
"helmet": "^4.4.1",
"mysql2": "^2.2.5",
"nodemailer": "^6.5.0",
"passport": "^0.4.1",
"passport-jwt": "^4.0.0",
"passport-local": "^1.0.0",
"path": "^0.12.7",
"reflect-metadata": "^0.1.13",
"rimraf": "^3.0.2",
"rxjs": "^6.6.3",
"swagger-ui-express": "^4.1.6",
"typeorm": "^0.2.31"
},
"devDependencies": {
"#nestjs/cli": "^7.5.4",
"#nestjs/schematics": "^7.1.3",
"#nestjs/testing": "^7.5.1",
"#types/cron": "^1.7.2",
"#types/express": "^4.17.11",
"#types/jest": "^26.0.15",
"#types/node": "^14.14.6",
"#types/supertest": "^2.0.10",
"#typescript-eslint/eslint-plugin": "^4.6.1",
"#typescript-eslint/parser": "^4.6.1",
"eslint": "^7.12.1",
"eslint-config-prettier": "7.2.0",
"eslint-plugin-prettier": "^3.1.4",
"jest": "^26.6.3",
"prettier": "^2.1.2",
"supertest": "^6.0.0",
"ts-jest": "^26.4.3",
"ts-loader": "^8.0.8",
"ts-node": "^9.0.0",
"tsconfig-paths": "^3.9.0",
"typescript": "^4.0.5"
},
"jest": {
"moduleFileExtensions": [
"js",
"json",
"ts"
],
"rootDir": "src",
"testRegex": ".*\\.spec\\.ts$",
"transform": {
"^.+\\.(t|j)s$": "ts-jest"
},
"collectCoverageFrom": [
"**/*.(t|j)s"
],
"coverageDirectory": "../coverage",
"testEnvironment": "node"
}
}
This error is explained with trying to write to directory diffent than /tmp.
Official documentation contain following:
While Cloud Storage is the recommended solution for reading and
writing files in App Engine, if your app only needs to write temporary
files, you can use standard Node.js methods to write files to a
directory named /tmp.
So this is the error, it seems your code is trying to use directory mentioned in the error massage. I do not have playgroud at hand for it, but I suppose this is related with start script using npx. You should use node <your-app.js> instead. I found different question where this was confirmed by question poster.

How to create tree-shakable react module? package.json "exports" not working

I'm trying to build a react components library (e.g Buttons, Modals, etc.)
But until now I still cannot figure how to do nested imports
the objective that i want to have is to be able to do this
import Something from '#company/moduleName/Something'
here is my package.json
{
"name": "#company/moduleName",
"version": "1.0.0",
"description": "company's react design system",
"author": "",
"license": "",
"repository": "",
"main": "dist/index.js",
"module": "dist/index.modern.js",
"source": "src/index.js",
"engines": {
"node": ">=13",
"npm": ">=7"
},
"type": "module",
"exports": {
".": "./dist/index.modern.js",
"./Button": "./dist/Button.modern.js",
"./Container": "./dist/Container.modern.js",
"./Input": "./dist/Input.modern.js",
"./Modal": "./dist/Modal.modern.js",
"./Select": "./dist/Select.modern.js",
"./Separator": "./dist/Separator.modern.js",
"./Sidebar": "./dist/Sidebar.modern.js",
"./Tab": "./dist/Tab.modern.js",
"./TextArea": "./dist/TextArea.modern.js",
"./theme": "./dist/theme.modern.js",
"./Typography": "./dist/Typography.modern.js"
},
"scripts": {
"build": "microbundle src/*.js --no-compress --no-sourcemap -f modern,cjs",
"start": "microbundle src/*.js --no-compress --no-sourcemap -f modern,cjs watch",
"rename": "cd dist && ren *.modern.js *.js",
"prepare": "run-s build",
"test": "run-s test:unit test:lint test:build",
"test:build": "run-s build",
"test:lint": "eslint .",
"test:unit": "cross-env CI=1 react-scripts test --env=jsdom",
"test:watch": "react-scripts test --env=jsdom",
"predeploy": "cd example && npm install && npm run build",
"deploy": "gh-pages -d example/build"
},
"peerDependencies": {
"react": "^17.0.1",
"lodash.merge": "^4.6.2",
"react-icons": "^4.2.0",
"react-modal": "^3.12.1",
"react-select": "^4.1.0",
"styled-components": "^5.2.1"
},
"devDependencies": {
"babel-eslint": "^10.0.3",
"cross-env": "^7.0.2",
"env-cmd": "^10.1.0",
"eslint": "^7.21.0",
"eslint-config-prettier": "^6.7.0",
"eslint-config-standard": "^14.1.0",
"eslint-config-standard-react": "^9.2.0",
"eslint-plugin-import": "^2.18.2",
"eslint-plugin-node": "^11.0.0",
"eslint-plugin-prettier": "^3.1.1",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-react": "^7.17.0",
"eslint-plugin-standard": "^4.0.1",
"gh-pages": "^2.2.0",
"microbundle": "latest",
"npm-run-all": "^4.1.5",
"prettier": "^2.0.4",
"react": "^17.0.1",
"react-dom": "^17.0.1",
"react-scripts": "^4.0.3",
"lodash.merge": "^4.6.2",
"react-icons": "^4.2.0",
"react-modal": "^3.12.1",
"react-select": "^4.1.0",
"styled-components": "^5.2.1"
},
"files": [
"dist"
],
}
currently i'm using microbundle to build everything in the src/ folder. I've added the exports field but it still says this in the example project inside the module
Module not found: Can't resolve '#company/moduleName/Button' in 'E:\Projects\Software\company\moduleName\example\src'
edit
To be clear, the dist folder shows up the correct desired result
-dist
index.modern.js
Modal.modern.js
...
I've also been able to do this, but this is not the desired output
#company/moduleName/dist/Something.modern
Any help would be greatly appreciated!

Could not proxy reques

Proxy error: Could not proxy request /api/profile/all from localhost:3000 to http://localhost:5000. [1] See https://nodejs.org/api/errors.html#errors_common_system_errors for more information (ECONNRESET)
Hi I was wondering if anyone knows the solution to this problem. The application was working just fine yesterday, but today it started raising this error up. Please I desperately need help. I have to finish this project before the 5th of February.
//package.json(Node)
{
"name": "devconnector",
"version": "1.0.0",
"description": "Social network for developers",
"main": "server.js",
"scripts": {
"client-install": "npm install --prefix client",
"start": "node server.js",
"server": "nodemon server.js",
"client": "npm start --prefix client",
"dev": "concurrently \"npm run client\" \"npm run server\""
},
"author": "Brad Traversy",
"license": "MIT",
"dependencies": {
"bcryptjs": "^2.4.3",
"body-parser": "^1.18.2",
"concurrently": "^3.5.1",
"express": "^4.16.3",
"gravatar": "^1.6.0",
"jsonwebtoken": "^8.2.0",
"moment": "^2.24.0",
"mongoose": "^5.0.12",
"npm": "^6.5.0",
"passport": "^0.4.0",
"passport-jwt": "^4.0.0",
"validator": "^9.4.1"
},
"devDependencies": {
"nodemon": "^1.17.3"
}
}
//package.json(React)
{
"name": "client",
"version": "0.1.0",
"private": true,
"dependencies": {
"#fortawesome/fontawesome": "^1.1.8",
"#fortawesome/react-fontawesome": "^0.1.3",
"axios": "^0.18.0",
"classnames": "^2.2.5",
"jwt-decode": "^2.2.0",
"moment": "^2.22.0",
"react": "^16.3.1",
"react-dom": "^16.3.1",
"react-html-table-to-excel": "^2.0.0",
"react-moment": "^0.7.0",
"react-redux": "^5.0.7",
"react-router-dom": "^4.2.2",
"react-scripts": "1.1.4",
"react-table": "^6.8.6",
"reactstrap": "^7.0.2",
"redux": "^3.7.2",
"redux-thunk": "^2.2.0"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
},
"proxy": "http://localhost:5000"
}

How to handle routes Heroku Create React App with express?

I have a create-react-app project which proxies a node express server at port 5000.
When we deploy it locally, all the requests get routed from client to the backend server and intermediate pages get rendered properly.
However, when I deploy it to Heroku, the flow always has to start from / route as any other URL directly hits the express server instead of being routed from front end.
Eg: https://consumesafe-dev.herokuapp.com works
But https://consumesafe-dev.herokuapp.com/dashboard goes directly to the node server instead of being proxied from front end.
here is the package.json for server:
{
"name": "example-create-react-app-express",
"version": "1.0.0",
"scripts": {
"client": "cd client && yarn start",
"server": "nodemon server.js",
"test": "cd client && npm install && yarn test",
"dev": "concurrently --kill-others-on-fail \"yarn server\" \"yarn client\""
},
"dependencies": {
"#google-cloud/language": "^1.0.0",
"#google-cloud/vision": "^0.12.0",
"async": "^2.6.0",
"body-parser": "~1.4.2",
"express": "^4.16.2",
"google-cloud": "^0.57.0",
"https": "^1.0.0",
"method-override": "~2.0.2",
"nodemon": "^1.17.3",
"pg": "^7.4.1",
"request": "^2.83.0",
"sequelize": "^4.37.2",
"winston": "^2.4.1"
},
"devDependencies": {
"concurrently": "^3.5.1"
}
}
and the package.json from client:
{
"name": "example-create-react-app-express",
"version": "0.1.0",
"private": true,
"proxy": "http://localhost:5000/",
"dependencies": {
"bootstrap": "^3.3.7",
"firebase": "^3.6.1",
"material-ui": "^0.20.0",
"react": "^16.2.0",
"react-checkbox-group": "^4.0.1",
"react-dom": "^16.2.0",
"react-event-timeline": "^1.5.1",
"react-notification-system": "^0.2.17",
"react-router-dom": "^4.2.2"
},
"devDependencies": {
"react-scripts": "1.1.1"
},
"scripts": {
"start": "react-scripts start",
"build": "react-scripts build",
"test": "react-scripts test --env=jsdom",
"eject": "react-scripts eject"
}
}

nodemon not refreshing when using typescript

I'm working on an app with NodeJs, express, typescript and nodemon.
But the page is not refreshed when I changed some code in the ts files.
How can I do to compile the ts file in js and refresh the browser with nodemon (or other tool)?
package.json
{
"name": "myapp",
"version": "1.0.0",
"description": "",
"main": "index.js",
"dependencies": {
"bcryptjs": "^2.4.3",
"body-parser": "^1.17.2",
"debug": "^2.6.8",
"dotenv": "^2.0.0",
"express": "^4.15.3",
"iconv-lite": "^0.4.17",
"inversify": "^4.11.1",
"jsonwebtoken": "^7.4.1",
"mongoose": "^5.0.10",
"morgan": "^1.8.2",
"passport": "^0.3.2",
"passport-jwt": "^2.2.1",
"rxjs": "^5.4.2",
"typescript": "^2.7.2",
"winston": "^2.3.1"
},
"devDependencies": {
"#types/chai": "^4.0.0",
"#types/debug": "0.0.29",
"#types/dotenv": "^2.0.20",
"#types/express": "^4.0.35",
"#types/mocha": "^2.2.41",
"#types/mongoose": "^4.7.15",
"#types/morgan": "^1.7.32",
"#types/node": "^6.0.77",
"#types/passport": "^0.3.3",
"#types/passport-jwt": "^2.0.20",
"chai": "^4.0.2",
"chai-http": "^3.0.0",
"gulp": "^3.9.1",
"gulp-clean": "^0.3.2",
"gulp-typescript": "^3.1.7",
"gulp-yaml": "^1.0.1",
"mocha": "^3.4.2",
"mocha-typescript": "^1.1.4"
},
"scripts": {
"start": "gulp build && nodemon dist/index.js",
"build": "gulp build",
"test": "gulp build && mocha -t 30000 dist/**/*.test.js"
},
"repository": {
"type": "git",
"url": "git+https://github.com/devslaw/TypeScript-Node.js-REST-example.git"
},
"keywords": [],
"author": "Arthur Arakelyan <arthur#devslaw.com>",
"license": "ISC",
"homepage": "https://github.com/devslaw/TypeScript-Node.js-REST-example#readme"
}
So know, anytime i make a change, I need to stop the server and run npm start again
The problem lies in the fact that your start script is watching dist/index.js. This folder only changes when the code gets recompiled into plain JavaScript. So you will need to watch the TypeScript files instead. The great thing is that you can change nodemon's default behavior. You will need to add ts-node to your package.json as well.
Try setting the script to something like the following:
nodemon --watch 'src/**/*.ts' --exec 'ts-node' src/index.ts
You will then want to set up a nodemon.json file with the following also:
{
"watch": ["src"],
"ext": "ts",
"exec": "ts-node ./src/index.ts"
}

Resources