package.json scripts failing on heroku - node.js

So I have a series of scripts that are set up to either dev servers for a React/Node Express application OR a production server on heroku. The structure of the app is as follows:
client/package.json //pckg for react app
package.json //pckg for the node server
these are the scripts in the clients package:
"scripts": {
"start": "if-env NODE_ENV=production && npm run start:prod || npm run start:dev",
"start:prod": "node server.js",
"start:dev": "set NODE_ENV=development&& concurrently \"nodemon --ignore 'client/*'\" \"npm run client\"",
"client": "cd client && npm run start",
"seed": "node scripts/seedDB.js",
"install": "cd client && npm install",
"build": "cd client && npm run build",
"heroku-postbuild": "npm run build"
}
and the only difference between the react apps package.json and the one that is automatically generated with create-react-app is as follows:
"proxy": "http://localhost:3001/",
the way its supposed to run is, install scripts at root folder, run install script to cd into client and install react apps dependencies, then heroku's post-build script should kick in to run the build script which cds into client and builds a production ready react app. finally the start script should see a NODE_ENV of production and run start:prod.
my problem is that for some reason when i push to heroku, it seems to get stuck on an infinite loop on the install script. I have NO clue why, as the exact same scripts work on other projects PERFECTLY.
https://github.com/LordKriegan/reactdbdemo
https://github.com/LordKriegan/reactdbdemo2/ if anyone wants to look at it. (doing a full stack demo for my students :/ not much of a demo if i cant get it deployed)

I got it working. Forgot create-react-app also initializes a git repo...? either that or somewhere along the way i did an extra git init. anyways i had a .git folder in my client folder, which was preventing my client folder from being pushed up. i ended up creating a new repo and pushing everything to that one and now it works. so incase anyone comes here with a similar problem... make sure you didnt end up in some kind of gitception trap. :/

Related

Heroku Build Not Copying React Files

I have a Node application, including an express server, set to respond to various backend requests and then to try to serve static content from a React app's build folder. It works great locally. The two different package.json files in the server and client respectively build the React app, copy its build files into the server's ./dist folder, then builds the server app and does the same, then runs the server. Everything is perfect.
However, on Heroku, the React build folder is never copied into the server's dist folder, and I get 404 errors trying to load the app. I know this worked at some point but I'm not sure what I changed that broke it and nothing is making sense to me to get it working again.
"scripts" section of the client (react) package.json:
"scripts": {
"start": "react-scripts start",
"react-build": "react-scripts build",
"build": "npm run clean && npm run react-build && npm run copy && cd server && npm run client-build",
"clean": "rimraf server/dist/",
"copy": "copyfiles build/**/* server/dist -E",
"test": "react-scripts test",
"eject": "react-scripts eject",
"prod": "cd server && npm run start"
},
and the "scripts" section of the server's package.json:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "nodemon -i dist -i creds index.ts",
"clean": "rimraf dist/",
"copy-files": "copyfiles views/**/* assets/**/* creds/**/* dist/",
"copy-web": "copyfiles -u 1 ../build/**/* dist/ -E",
"build": "cd .. && npm run react-build && cd server && npm run clean && tsc && npm run copy-files && npm run copy-web",
"client-build": "npm i && tsc && npm run copy-files",
"start": "node dist/index.js"
},
Heroku, of course, runs npm run build from the root folder to kick off the build process, which is the client's package.json, so it runs:
npm run clean && npm run react-build && npm run copy && cd server && npm run client-build
Specifically the npm run copy doesn't seem to be doing anything. When I hit the ls through the heroku-cli, the folder is not there. I'm not getting any errors in the build.
I have been able to put a cludgey piece of code into the main server so that it checks to see if the build folder exists where it's supposed to exist before setting up the static middleware, and to go up the file tree to where they're supposed to be copied from if it doesn't, so it's working, but I don't think I should have to do this and I can't just point to the initial React build location or I'd be serving stale build's while I'm in dev locally instead of a specific dev page that links to the webpack npm run start instance that updates as I hack at it.
I understand that between the workaround in prod and just not relying on the server's static files in dev is "good enough" for me to move on, but my OCD won't let me until I understand why copyfiles works fine copying the server's extra files into dist but can't manage to copy the React app to the place it's supposed to go.
This seems like a pretty basic thing, and long run my plan here is to serve multiple independent React applications as "widgets" from different paths on the server and if I can't get the root path to behave because I'm an idiot then idk what kinds of problems I'm going to run into down the line.
TIA, lmk if any additional info is needed.
CORRECTION: I had been building an outdated version without the -E flag on the copyfiles call. Once I updated that, I did in fact get an error that no files were copied. To reiterate though, the files ARE in the build folder where they were supposed to be copied from, just not in the dist/build folder where they're supposed to go, as confirmed now by copyfiles deciding it had nothing to copy.
Is this an async issue? I thought the && suggested that the left side (the build) had to finish before the right side (the copy) would execute?

webpack script in package.json

I have a question regarding the script property in package.json of my app. If I type npm start, the app gets compiled successfully. And it seems that by typing the above command, www file starts running.
However, if I type npm webpack, nothing happens. I have a react/express app. And the server runs on localhost:3000 on npm start. I want to know, is webpack serving both react and express? I am able to send requests from the client to the server and show the result on the client-side. I just wanted to know how things are working.
"scripts": {
"start": "NODE_ENV=development nodemon ./bin/www",
"webpack": "webpack-dev-server --config ./webpack.config.js --mode development"
}
for other scripts than "start", you have to type npm run [scriptname].
in your case: npm run webpack

Webpack add watch mode without compiling

I have the following npm scripts:
"build:server:dev": "webpack --config ./webpack.server.dev.config.js --watch",
"build:client:dev": "webpack --config ./webpack.client.dev.config.js --watch",
"build:server:prod": "webpack --config ./webpack.server.prod.config.js",
"build:client:prod": "webpack --config ./webpack.client.prod.config.js",
"start:server:prod": "export NODE_ENV=production && node ./dist/server.*.js",
"start:iso:dev": "export NODE_ENV=development && npm run build:client:dev & npm run build:server:dev",
"start:iso:dev:win": "set NODE_ENV=development && concurrently --kill-others \"npm run build:client:dev\" \"npm run build:server:dev\"",
"start:iso:prod": "npm run build:client:prod && npm run build:server:prod && npm run start:server:prod"
The problem I'm facing is that the server compilation depends on the client compilation (I generate an html template where I inject the scripts with webpack on the client, and I use this template for server rendering in the server script).
In nearly all of the cases, the client finishes compiling before the server, but while running these scripts concurrently, there is no way to ensure that this will always be true.
When running webpack watch mode, it is not possible to run these scripts in sequence, as watch mode will block the second script from running.
The most obvious solution in my mind is to compile them without watch mode once, and then attach watch mode on the fly after the initial compilation.
I'm not sure how to achieve this though, and I would not like to compile them twice, just for the sake of attaching watch mode.
The second alternative I have in mind is to fiddle with webpack progress plugin, and somehow compile the server script after the client script has finished.
I dislike this solution, because I don't want to hard couple one script to another.
So is there a way to run client and server compilation sequentially from an npm script while using webpack --watch mode?
Maybe this will help you parallel-webpack although I didn't try it it has watch mode and would probably just require connecting your configs for both server and client side someway along this way:
// some script for running parallel builds
module.exports = [
require('./webpack.server.dev.config.js'),
require('./webpack.client.dev.config.js'),
];
then check running in watch mode
I found a nice solution using the npm package wait-on:
https://github.com/jeffbski/wait-on
The npm script I used (Unix & Windows):
"start:iso:dev": "export NODE_ENV=development && npm run clean:build && npm run build:client:dev & wait-on public/build/index-dev.html && npm run build:server:dev --inspect",
"start:iso:dev:win": "npm run clean:build:win && set NODE_ENV=development&& concurrently \"npm run build:client:dev\" \"wait-on public\\build\\index-dev.html && npm run build:server:dev\"",
This works like a charm.

Deploy on AWS ElasticBeanstalk - run custom npm script before starting server?

I have been trying to deploy my nuxt universal app onto AWS elastic beanstalk. I've tried using custom npm script in my package.json:
"scripts": {
"dev": "nuxt",
"build": "nuxt build",
"start": "nuxt start",
"generate": "nuxt generate",
"precommit": "npm run lint",
"deploy": "nuxt build && nuxt start"
},
Then under AWS EB config, i added Node command: npm run deploy
However, it is not working.
Basically, i need to tell EB to run "npm run build" before "npm run start"
Anybody can help?
What you've described lies in the npm realm, and can be solved by using a prestart script, like so:
"prestart": "nuxt build"
More details here: https://docs.npmjs.com/misc/scripts
So far this has helped me, it seems to work for default nuxt project (nuxt create) in universal mode.
I am using Elastic Beanstalk, CodePipeline and Bitbucket.
CodePipeline takes code from Bitbucket once it is pushed and builds in on Elastic Beanstalk.
What helped me is adding to package.json:
"deploy": "npm run build && npm run start"
or
"deploy": "npm run install && npm run build && npm run start"
and creating Procfile in root directory of project, content/command of Pocfile triggers the deploy script in package.json file
web: npm run deploy
Before, there were "hooks" but now they're almost deprecated https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/custom-platform-hooks.html
Now you can use Buildfile and Procfile as described here https://docs.aws.amazon.com/elasticbeanstalk/latest/dg/platforms-linux-extend.html
Try Adding to your .ebextensions a "source_compile.config" file as follows:
# source_compile.config
container_commands:
compile:
command: "./node_modules/.bin/nuxt build"
env:
PATH: /opt/elasticbeanstalk/node-install/node-v12.16.3-linux-x64/bin/
Got the idea from the same need to pre compile a typescript nodejs server before deploying to Elastic Beanstalk :)
Here a ref:
https://medium.com/#lhviet88/deploy-a-typescript-expressjs-into-elasticbeanstalk-nodejs-server-8381e00e7e52

How do I deploy my Typescript Node.js app to Heroku?

When testing locally I was previously running:
"build-live": "nodemon --exec ./node_modules/.bin/ts-node -r dotenv/config -- ./index.ts"
I then figured my Procfile should be something like:
web: ./node_modules/.bin/ts-node -- ./index.ts
But it says module 'typescript' not found, even when it is in package.json. I read in a few places that ts-node is not the way to go to deploy to Heroku, so I am not sure what to do.
UPDATE: I think I am supposed to compile it, so I tried:
web: ./node_modules/.bin/tsc --module commonjs --allowJs --outDir build/ --sourceMap --target es6 index.ts && node build/index.js
This succeeds, however when actually running it, a bunch of the libs I'm using get "Cannot find module '...'".
Alternatively you can have the TypeScript compile as a postinstall hook and run node build/index.js as the only Procfile command:
Your package.json should contain a postinstall hint that gets executed after npm install and before the node process launches:
"scripts": {
"start": "node build/index.js",
"build": "tsc",
"postinstall": "npm run build"
}
You can then leave your Procfile as is:
web: npm start
This 'build on deploy' approach is documented by Heroku here.
The command you've given Heroku is to launch the web "process" by compiling index.ts and dependencies and starting node at index.js. Depending on how things are timed, index.js might or might not exist at the time node starts.
You need to already have your sources compiled by the time you want to start your app. For example, web should just be web: node index.js or similar.
Each build process is different, so you need to figure that out for your own setup. But, suppose you have a classical setup where you push to git and then Heroku picks up that change and updates the app with the new slug. You could just compile things locally and include index.js and any other build output in the repository, for it to be available in the slug for Heroku to use.
A better approach is to use a build server which has an integration with Heroku. After you do the build there, configure it to send the build results to Heroku. Travis has a straighforward setup like this. This way you don't need to include build outputs in your repository, which is considered an anti-pattern.
On a sidenode, try using a tsconfig.json to keep the tsc configuration. It will save you from having to write such long command lines all over the place.
Fabian said that we could do something like:
"scripts": {
"start": "node build/index.js",
"build": "tsc",
"postinstall": "npm run build"
}
As of me writing this, I tested this and can state: postinstall is not required since build script is ran by Heroku. If you want to do it without build script, then you can use heroku-postbuild which will run after dependencies are installed there you run tsc to compile.
My problem was about missing Typescript npm modules. The Typescript compiler tsc was not found when deployed the app to Heroku.
The Heroku deploy process (rightly) does not install development dependencies, in my case the Typescript module was part of devDependencies and thus the tsc command was not running on the Heroku platform.
Solution 1
Add typescript to dependencies: npm i typescript -s
Solution 2
Open Heroku console:
Select console type:
Run the command npm i typescript && npm run tsc
Install typescript as a dev dependency (cf. https://www.typescriptlang.org/download). Once built, your app does not need typescript anymore!
npm install -D typescript
Then in your package.json:
{
"main": "index.js", // <- file will be generated at build time with `tsc`
"scripts": {
"build": "tsc",
"start": "node ."
"start:dev": "ts-node index.ts" // idem, install ts-node as a dev dependency
}
}
The key point here is "build": "tsc".
Why?
Heroku does install all dependencies during build and remove the dev dependencies before the app is deployed (source here).
Node.js deployments will automatically execute an app’s build script during build (since March 11. 2019 source here)
In package.json
"scripts": {
"tsc": "./node_modules/typescript/bin/tsc",
"postinstall": "npm run tsc"
},
Works for me for Heroku deployment.
Installing typescript npm install -D typescript and writing tsc in the build script "build": "tsc", does not work for me. Also, try to run npm i typescript && npm run tsc in the Heroku console which also does not work.
In my case, I remove some dependencies from "devDependencies" to "dependencies", so it goes like this:
"dependencies": {
// The other dependencies goes here, I don't touch them.
// But all TS dependencies I remove to here.
"ts-node": "^9.1.1",
"tsconfig-paths": "^3.9.0",
"typescript": "^4.2.3",
"ts-loader": "^8.0.18"
},

Resources