Laravel environment variable with React: is this a good practice? - laravel

I have a React app which makes API requests to a Laravel backend.
My app is hosted on Heroku (I do not know if it changes something for my question).
I would like to differentiate a production and a local environment for these requests. I do it as follows.
In my "welcome.blade.php", I add this meta tag:
<meta name="app_env" content="<?php echo env("APP_ENV") ?>" />
The APP_ENV contains either "production" or "local".
In my React app, I have this script:
export let urlApi = (document.querySelector("[name=app_env]").content === "production" ) ?
"https://laravel-react.herokuapp.com/api"
:
"http://localhost/laravel_react/public/api"
;
And I import this function in each component which needs it:
import { urlApi } from './../findUrlApi';
// .....
return fetch(`${urlApi}/products`,{
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer "+localStorage.getItem("token")
}
})
It works fine.
But my question is, is it a good practice? (I am a beginner in React).

I don't think that it is a good practice. Environment variables (like APP_ENV and API URLs) should not reside in the source code.
However, you could store them like usual in Laravel .env file but by prefixing the key with MIX_. For example: MIX_API_URL=http://localhost. Every MIX_* variables in .env file will be exposed to your React application. Then, you could get MIX_API_URL value from your React application by calling process.env.MIX_API_URL.
Updated Laravel .env file
...
MIX_APP_ENV=production (or local) # Should be same as APP_ENV
MIX_API_LOCAL_URL=http://localhost/laravel_react/public/api
MIX_API_PRODUCTION_URL=https://laravel-react.herokuapp.com/api
In React components that need it
const { MIX_APP_ENV, MIX_API_LOCAL_URL, MIX_API_PRODUCTION_URL } = process.env;
const apiUrl = MIX_APP_ENV === 'local'? MIX_API_LOCAL_URL: MIX_API_PRODUCTION_URL;
return fetch(apiUrl + '/products', { ... });
If calling process.env.MIX_API_URL does not work and you are running npm run watch, try restarting npm run watch and hard reload your browser.
Reference
Laravel Documentation - Compiling Assets (Mix) - Environment
Variables

Related

Laravel Vite: Assets blocked/Mixed Content issues in production environment

I'm hosting my App on an EC2-instance behind an Elastic Load Balancer which manages my SSL-Certificate. On this EC2-Instance my nginx-configuration is redirecting all http-Requests to https.
I recently switched to Vite which caused me a lot of trouble. When I push my app to the server after calling npm run build my assets are blocked. In the browser console I get:
Mixed Content: The page at 'example.com' was loaded over HTTPS, but requested an insecure ...
My Setup:
vite.config.js
export default defineConfig({
server: {
host: 'localhost',
},
plugins: [
laravel([
'resources/assets/sass/app.sass',
// etc...
]),
vue({
template: {
transformAssetUrls: {
base: null,
includeAbsolute: false,
},
},
}),
],
});
Setting "https: true" in the server-block didn't help me.
.env
APP_ENV=production
APP_URL=https://example.com
ASSET_URL=https://example.com
In my blade template I'm using the Vite-directive:
#vite('resources/assets/sass/app.sass')
I tried the following solutions:
Setting $proxies = '*' in TrustProxies.php, which doesn't have any effect.
Setting URL::forceScheme('https'); in AppServiceProvider.php, which will load the assets but lead to a lot of other issues.
Somehow the #vite-directive is not resolving my assets as secure assets. With Laravel Mix I could just call secure_asset.
How can I fix this?
In the end I used the TrustedProxies-middleware. However back then I forgot to register it as global middleware.
import fs from 'fs';
const host = 'example.com';
server: {
host,
hmr: {host},
https: {
key: fs.readFileSync(`ssl-path`),
cert: fs.readFileSync(`ssl-cert-path`),
},
},
you should add this to vite.config.js file along with ASSET_URL to your .env file

Vercel/NextJS: How to access serverless functions from frontend during local development?

My React/NextJS front end has a Button component that fetches data via a serverless function when the button is clicked. I want to test this functionality during local development with the Vercel dev/CLI tools. I am getting a 404 result when attempting to access my lambda functions. Here are the approximate steps that I've gone through so far:
Create package.json with a dev script:
...
"scripts": {
"dev": "yarn codegen && next --hostname=0.0.0.0 --port=3001",
}
...
Link to deployed vercel project
Create vercel.json to specify builds and routes:
...
"builds": [
{ "src": "*.html", "use": "#now/static" },
{ "src": "pages/api/*.py", "use": "#now/python" },
],
"routes": [
{ "src": "/api/validate", "dest": "/pages/api/validate.py" }
]
...
Create my test Lambda function (in python):
from http.server import BaseHTTPRequestHandler
from datetime import datetime
class handler(BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'text/plain')
self.end_headers()
self.wfile.write(str(datetime.now().strftime('%Y-%m-%d %H:%M:%S')).encode())
return
Create my Button component:
...
<Button
variant="contained"
color="secondary"
onClick={() => {
fetch('api/validate')
.then(response => { console.log(response)
response.json() })
.then(data => console.log(data))
}}
>
Generate sample dataset
</Button>
...
Run vercel dev
Access website at localhost:3001 (next dev server address)
Click button
Result:
I'm receiving a 404 response
Note: I can access the lambda function from localhost:3000/pages/api/validate.py (vercel dev server address). This appears to manually kickstart the lambda function build and serve process. I thought that it should have been built and served already from the vercel.json specification and be available at localhost:3001/api/validate. This seems to agree with the Vercel documentation.
Note 2: Next dev/CLI tools build and serve javascript/typescript files just fine. I'm using python and Go functions as well, which are supported by Vercel dev/CLI but not Next
My solution was to use vercel dev instead of next dev or yarn dev, and to use an environment variable in a .env file that points to the function url. This env variable should be prepended with NEXT_PUBLIC_ so that it is registered by next.js and passed to process.env during the build process.
# .env
NEXT_PUBLIC_FUNCTIONS_BASE_URL="http://localhost:3000" # 3000 is vercel port
# component.js
...
fetch(process.env.NEXT_PUBLIC_FUNCTIONS_BASE_URL + '/api/function-name')
...
You need to pass the port from vercel dev to the upstream CLI, in this case next dev.
{
"scripts": {
"dev": "yarn codegen && next dev --port=$PORT",
}
}
Now when you run vercel dev, the ephemeral port will be proxied from the dev server.
You can also remove vercel.json if you rename /pages/api to /api.

How to access Heroku environment variables with Nuxt.JS app

I have deployed my app on Heroku and on the start of my app I check a config file and in there I want to access a config var I have created on Heroku API_KEY to define my Firebase config:
module.exports = {
fireConfig: {
apiKey: process.env.API_KEY,
authDomain: "my-app.firebaseapp.com",
databaseURL: "https://my-app.firebaseio.com",
projectId: "my-project-id",
storageBucket: "my-app.appspot.com",
messagingSenderId: "my-messaging-sender-id"
}
};
this process.env.API_KEY is undefined. Should I use a different way to access it?
You can define environment variables in your nuxt.config.js file, e.g.
export default {
env: {
firebaseApiKey: process.env.API_KEY || 'default value'
}
}
Here we use the API_KEY environment variable, if it's available, and assign that to firebaseApiKey.
If that environment variable isn't set, e.g. maybe in development (you can set it there too if you want), we fall back to 'default value'. Please don't put your real API key in 'default value'. You could use a separate throwaway Firebase account key here or just omit it (take || 'default value' right out) and rely on the environment variable being set.
These will be processed at build time and then made available using the name you give them, e.g.
module.exports = {
fireConfig: {
apiKey: process.env.firebaseApiKey, # Not API_KEY
// ...
};

how to access vue.js api key in laravel application

hello there i am trying to access my youtube api key located in the .env file from within this code:
<template>
<div class="YoutubeDash__wrapper">
<video-group :videos="videos"></video-group>
</div>
</template>
<script>
import VideoGroup from './VideoGroup.vue';
import Search from './Search';
export default {
components: {
VideoGroup
},
created(){
Search({
apiKey: process.env.VUE_APP_SECRET,
term: 'laravel repo'
}, response => this.videos = response);
},
data(){
return {
videos: null
}
}
}
</script>
According to the documentation using env variables with vue.js. Everything seems to be correct. In my .env file i say: VUE_APP_SECRET=xxxxxxxxxxxxxxx, what am i missing here ?
I get this error message:
app.js:37809 Error: YouTube search would require a key
Any tips are welcome! Thanks a lot!
We need to work with a small amount of information here so I am going to make a few assumptions (based on the tags) mostly that you are using laravel and laravel-mix to compile your resources.
For laravel(-mix) to make your .env variables accessible by JS you need to prefix them with MIX_ i.e. MIX_VUE_APP_SECRET. This will make your variable accessible as process.env.MIX_VUE_APP_SECRET.
I prefer excluding laravel-mix from this process.
Usually, in my blade entry-point I use meta tags:
<meta name="myVal" content="{{ config('<any-config-key>') }}">
<any-config-key> can be any laravel configuration key including those taken from .env.
Then, in my javascript I do something like:
const setVueGlobal = (metaHeaderName, vueGlobalName) => {
let value = document.head.querySelector('meta[name="' + metaHeaderName + '"]').content;
if (!value) {
console.error('some error msg');
return null;
}
Vue.prototype[vueGlobalName] = value;
return value;
};
setVueGlobal('myVal', '$myVal');
Finally, accessing using this.$myVal

laravel 4 environment setting in fortrabbit with getenev()

Hi I deploy my application based on laravel 4 to fortrabbit. I try setting local and production environment
in bootstrap/start.php I modify
$env = $app->detectEnvironment(function () {
return getenv('LARAVEL_ENV') ?: 'local';
});
on fortrabbit i define env_var
LARAVEL_ENV to prod
but if i try in fortrabbit
php artisan env
i obtain local instead of prod
what is wrong in my code?
After setting the environment variable in your Fortrabbit's dashboard, you need to write this in your start.php file:
$env = $app->detectEnvironment(function () {
return isset($_SERVER['LARAVEL_ENV'])
? $_SERVER['LARAVEL_ENV']
: 'prod';
});
Note that it is better to fallback to the production environment in case there is no environment variable, since you don't want to mistakenly show debug logs on your production app.

Resources