Deploy frontend and backend app to Heroku - heroku

I tried to deploy my app to Heroku, but it is not working correctly. (using create-react-app for frontend and node.js in the backend)
My full app structure looks like this:
my-app
|
| ____ backend
| └── ...
| ____ frontend
└── ...
In the package.json I've added --dest ../backend/public to the build script:
scripts": {
"start": "react-scripts start",
"build": "react-scripts build --dest ../backend/public",
},
Then I've ran these commands in the CMD on my backend folder:
> git init
> heroku create <my-app-name>
And this command on my frontend folder:
npm run build
Then, in the CMD on my backend folder:
> git add .
> git commit -m “<commit-messgae>”
> git push heroku master
When I go the my heroku app link I see the "Hello Backend!" message that I wrote in my server.js file:
app.get('/', (req, res) => {
res.send('Hello Backend!')
})
Please let me know what am I doing wrong. Thanks.

Related

Pusher referencing development app key in production

I've been trying to diagnose an issue with pusher not working on production, when it works fine locally. This morning I discovered after tinkering around in the console, that when I do this on production:
Echo.private('App.Models.User.1');
I get this output:
which is the key from my development .env file:
PUSHER_APP_KEY=f9d9********011e
My production key shown in pusher is:
key = "07ae********2d4"
My production .env file also references this correct production key:
PUSHER_APP_KEY=07ae*********2d4
HOWEVER, that is NOT what's actually being used by the production application (see prior screenshot).
I'm not doing anything different from the "stock" implementation of importing pusher in my bootstrap.js file:
import Echo from 'laravel-echo';
window.Pusher = require('pusher-js');
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
encrypted: true
});
After searching my codebase, I found that the key gets hard-coded into the public/js/app.js file when you run npm run dev locally. I verified this by changing the key in my .env file and running npm run dev which then updated the key reflected in the app.js file.
I then went out to my production site's FTP and downloaded the app.js file, and sure enough, the development key is hard-coded in the app.js file.
If I update the app.js file to reflect the correct key, and then run Echo.private('App.Models.User.1'); again, this is the output, which shows the correct key:
And also, notifications start working as expected after making that change. However, that's obviously problematic as every time I deploy, it will be overwritten by the dev value.
Could it be my build process? (also see this SO question I asked yesterday)
What the actual *** is going on here?
I've not had any other issues with npm not building things correctly (that I'm aware of), but it seems that the code in my app.js file must be getting generated via the .env file and somehow my production environment is not referencing the correct key?
Here are some details around my build process (I use Github Actions).
Here is my github actions .yml file:
steps:
- name: Set up MySQL
run: |
sudo systemctl start mysql
mysql -e 'CREATE DATABASE testdb;' -uroot -proot
mysql -e 'SHOW DATABASES;' -uroot -proot
- uses: actions/checkout#main
- name: Copy .env
run: php -r "file_exists('.env') || copy('.env.example', '.env');"
- name: Install Dependencies
run: composer install -q --no-ansi --no-interaction --no-scripts --no-progress
- name: Generate key
run: php artisan key:generate
- name: Directory Permissions
run: chmod -R 777 storage bootstrap/cache
- name: Clean Install
run: npm ci
- name: Compile assets
run: npm run prod
- name: Execute tests (Unit and Feature tests) via PHPUnit
run: vendor/bin/phpunit
from my package.json file:
"scripts": {
"dev": "npm run development",
"development": "mix",
"watch": "mix watch",
"watch-poll": "mix watch -- --watch-options-poll=1000",
"hot": "mix watch --hot",
"prod": "npm run production",
"production": "mix --production"
},
UPDATE:
My public folder, and in turn my public/js/app.js file is getting pushed to source control. I just deleted it from my repo and pushed the code to production, and now I'm getting a jquery not defined error, which tells me that the app.js file isn't getting re-created during my build process.
UPDATE:
My .env file is not in source control, so the github action is using .env.example which has the variables but no values, and has a couple of other "mix" variables, which may be the problem.
PUSHER_APP_ID=
PUSHER_APP_KEY=
PUSHER_APP_SECRET=
PUSHER_APP_CLUSTER=
MIX_PUSHER_APP_KEY="${PUSHER_APP_KEY}"
MIX_PUSHER_APP_CLUSTER="${PUSHER_APP_CLUSTER}"
as mentioned earlier in the question, my bootstrap.js file is referencing those 2 MIX_PUSHER_* variables:
window.Echo = new Echo({
broadcaster: 'pusher',
key: process.env.MIX_PUSHER_APP_KEY,
cluster: process.env.MIX_PUSHER_APP_CLUSTER,
encrypted: true
});
I guess I need to set up a github environment variable for the app key for each environment?
UPDATE:
I found this SO answer that details how to create a github secret and basically put your whole environment file in it, but it's saying it's an invalid:
The environment file is invalid!
Failed to parse dotenv file. Encountered unexpected whitespace
The problem occurs from your js. It seems that you are using the development env in your js for production. Make sure that you are compile your js files for production in your live environment.

Vue.js App on Heroku Server: Cannot GET /. How Do I Solve This?

When I enter my URL for my Vue.js application (https://harrishealthtest.herokuapp.com/), the browser takes me to the homepage. Good. However, when I click on the 'Start' button, that's supposed to take me to '/test', I get this message 'Cannot GET /test'.
What am I doing wrong? I have history mode enabled in my routing. I'm not sure if that is causing issues. Or if it's something to do with the connectivity between my Vue.js app and my Laravel REST API. Both are on separate domains. When I click on 'Start', the app is supposed to take me to '/test', and that's where the data from the API is received.
This is what I currently have in my App.vue file:
mounted() {
fetch('https://pure-mountain-87762.herokuapp.com/', {
method: 'get'
})
.then((response) => {
return response.json()
})
// 'jsonData' refers to the json parsed response
.then((jsonData) => {
this.testData = jsonData.data
})
What kind of issue am I having here? Routing? API connectivity? Or something else?
It seems heroku is pointing to the server instead of the client. I had the same error a few weeks back. Two things:
If you are running two npm commands, resume them in the json file that heroku is pointing at. This is an example:
"scripts": {
"client-install": "npm install --prefix client",
"start": "node server.js",
"server": "nodemon server.js",
"client": "npm start --prefix client",
"dev": "concurrently \"npm run server\" \"npm run client\"",
"heroku-postbuild":
"NPM_CONFIG_PRODUCTION=false npm install --prefix client && npm run build --prefix client"
Add that heroku-postbuild line.
You have to play with the commands in your dev environment, in your computer. Make sure it works in your computer, then push up.
Secondly and this is kinda hacky, however it works for me.
Got to Settings of your app in Heroku, click on Reveal Config Vars button and add this env variable:
DANGEROUSLY_DISABLE_HOST_CHECK=true
This helped me. Hope it helps you.

Laravel & Vue - separate assets for admin and public page

I'm new to Vue but I really like it. Right now I have my own CMS based on Laravel. I want to build new CMS as SPA in Vue. But one thing is not clear to me. How should I separate assets for frontend and admin?
For example I would like to have COMPONENTS folder with another folder ADMIN - there will be only admin components.
I also don't want to have webpack building everything together.
I was thinking about solution like having multiple webpack commands:
npm run dev
npm run dev admin
But maybe I'm completely wrong...
If you want to have 2 different commands - you just need to specify different configuration files to webpack --config option
like:
package.json
{
"scripts": {
"dev": "webpack-dev-server --inline --progress --config build/webpack.dev.conf.js",
"dev-admin": "webpack-dev-server --inline --progress --config build/webpack.dev-admin.conf.js",
}
}
Another option is to use webpack`s "multiple pages" option. It would allow you to build 2 entry .js files and all of the chunks for both of your apps.
Take a look here: https://webpack.js.org/concepts/entry-points/#multi-page-application
And if you use Vue-cli - https://cli.vuejs.org/config/#pages

Is it possible to deploy a React Native app to Heroku?

Is was wondering if its possible to deploy a React Native app to Heroku? The reason I ask is because then I can retrieve the url and place it in an iframe to mimic an iPhone where the user can then tryout the app without actually having to install it on to the iPhone via iTunes.
This is possible using react-native-web (sources).
There are few things that you have to do to set this up on heroku:
in the settings tab of your your heroku app dashboard
set the buildpack as heroku/nodejs,
in package.json set the build script to build your web version from RN sources, for example, if you are using expo: expo build:web,
create a Procfile in the root directory to serve the web
version: for example, if you used expo, the build directory is web-build and therfore the command should be npx serve web-build,
Additionally, if you use expo, make sure to add the expo-cli as a dev dependency: npm install -D expo-cli.
You will then simply need to push to heroku the usual way. By default, heroku will run yarn build (or npm run build depending on wether you used one or the other to generate your lock file).
In the end, here is what the package.json file might look like (using expo again):
{
"main": "node_modules/expo/AppEntry.js",
"scripts": {
"start": "expo start",
"android": "expo start --android",
"ios": "expo start --ios",
"web": "expo start --web",
"eject": "expo eject",
"test": "jest --watchAll",
"build": "expo build:web"
},
"jest": {
"preset": "jest-expo"
},
"dependencies": {
"#expo/vector-icons": "^12.0.0",
"#react-native-community/masked-view": "0.1.10",
"#react-navigation/bottom-tabs": "^5.11.1",
"#react-navigation/native": "^5.8.9",
"#react-navigation/stack": "^5.12.6",
"expo": "~40.0.0",
"expo-asset": "~8.2.1",
"expo-constants": "~9.3.0",
"expo-font": "~8.4.0",
"expo-linking": "~2.0.0",
"expo-splash-screen": "~0.8.0",
"expo-status-bar": "~1.0.3",
"expo-web-browser": "~8.6.0",
"react": "16.13.1",
"react-dom": "16.13.1",
"react-native": "https://github.com/expo/react-native/archive/sdk-40.0.1.tar.gz",
"react-native-gesture-handler": "~1.8.0",
"react-native-safe-area-context": "3.1.9",
"react-native-screens": "~2.15.0",
"react-native-web": "~0.13.12"
},
"devDependencies": {
"expo-cli": "^4.0.16",
"#babel/core": "~7.9.0",
"#types/react": "~16.9.35",
"#types/react-native": "~0.63.2",
"jest-expo": "~40.0.0",
"typescript": "~4.0.0"
},
"private": true
}
And the Procfile simply consists of a single line:
web: npx serve web-build
You could probably achieve similar results using reactxp instead of reac-native-web, but I never tried it myself.
Client side routing
Configuring Heroku for client side routing
If you use client side routing (react navigation for example), you will have to setup a few more things to make sure linking works. With the previous build alone, client side routing will fail (404 errors) because heroku will try to route requests on its own, but your app needs everything to end up at index.html so it can perform routing tasks on its own (client side routing).
We will thus prevent any Heroku routing by adding a second buildpack heroku-community/static next to heroku/nodejs. This second buildpack is configured via a /static.json file (default values):
{
"root": "web-build/",
"clean_urls": false,
"routes": {
"/**": "index.html"
}
}
Configuring webpack for client side routing
You probably already have this part setup because otherwise you would have 404 errors even locally. To allow client side routing it seems like we also need to configure webpack (output.publicPath and devServer.historyApiFallback), with expo this can be done by running expo customize:web and then editing /webpack.config.js with:
const createExpoWebpackConfigAsync = require('#expo/webpack-config');
module.exports = async function (env, argv) {
const config = await createExpoWebpackConfigAsync(env, argv);
config.output.publicPath = '/';
config.devServer = {
...config.devServer,
historyApiFallback: true,
};
return config;
};
There is a nice article about these routing issues you might have here: Fixing the 'cannot GET /URL'
Steps for deploying React native/expo app to heroku:
1:
set heroku buildpack as static: >heroku buildpacks:set heroku-community/static
2:
Add static.json for static buildtype:
{
"root": "web-build/",
"routes": {
"/**": "index.html"
}
}
More settings here: https://github.com/heroku/heroku-buildpack-static#configuration
3:
npm run build (package.json: "build": "expo build:web") --> Creates web-build folder
git add .
git commit
git push heroku master
heroku open

Cannot find module twilio when using heroku and meteor

I cannot figure out how to get the twilio npm module working on a heroku dyno using meteor js. It works great on localhost, but it crashes on heroku. This is how I built my heroku app:
heroku create meteorherokutwilio --stack cedar --buildpack https://github.com/oortcloud/heroku-buildpack-meteorite.git
heroku config:add ROOT_URL=http://meteorherokutwilio.herokuapp.com/
heroku labs:enable websockets -a meteorherokutwilio
git push heroku master
I've added twilio to my meteor project like this:
mrt add twilio
This is how I'm loading twilio:
var client = Npm.require('twilio')("key", "secret");
This is the error:
/app/.meteor/heroku_build/app/programs/server/boot.js:186
}).run();
^
Error: Cannot find module 'twilio'
at Function.Module._resolveFilename (module.js:338:15)
at Function.Module._load (module.js:280:25)
at Module.require (module.js:364:17)
at require (module.js:380:17)
at Object.Npm.require (/app/.meteor/heroku_build/app/programs/server/boot.js:88:18)
at app/meteor-heroku-twilio.js:18:24
at /app/.meteor/heroku_build/app/programs/server/boot.js:159:61
at Array.forEach (native)
at Function._.each._.forEach (/app/.meteor/heroku_build/app/programs/server/node_modules/underscore/underscore.js:79:11)
at /app/.meteor/heroku_build/app/programs/server/boot.js:159:5
Process exited with status 8
State changed from starting to crashed
I've also made a git repo with the minimum amount of code to demonstrate the problem: https://github.com/esromneb/meteor-heroku-twilio/
Npm.require works only for standard node packages (well, it works for packages it found installed, but you should only rely on it for standard packages, unless you want to manually add packages to your Heroku server and each server you'd like to run in the future).
For all other npm packages, there's npm meteorite package.
Add it to your project with mrt add npm command.
Then create packages.json file with a list of all required packages, for example:
{
"twilio": "1.5.0",
"oauth": "0.9.11"
}
Afterwards, include your package with Meteor.require:
var client = Meteor.require('twilio')("key", "secret");

Resources