loading env variables in react app using vite - javascript

I´ve been through all the docs from vite, react.js and dev blogs, but I'm not getting it to work
I have a .env file which contains the following
VITE_API_KEY = XXX
inside my firebase.js file I'm loading it like :
const firebaseConfig = {
apiKey: import.meta.env.API_KEY,
.....
.....
}
// Initialize Firebase
const app = initializeApp(firebaseConfig);
but it appears as null, I've restarted the dev server, reinstalled node_modules (just in case) changed var prefixes to REACT_APP_XX, tried using process.env.XX global object, basically gone through all different ways to read vars from a .env file in react
I´ve also tried to clog it from a component but it has the same result
any suggestions/methods to solve this problem?

The environment variable name used in code must match the name set in the .env file:
// .env
VITE_API_KEY=abcd1234
👆
// firebase.js
const firebaseConfig = { 👇
apiKey: import.meta.env.VITE_API_KEY,
⋮
}
demo

finally solved this problem,
the thing was that:
import.meta.env.VITE_XX
this env variable are statically replaced during production, not development, at least in my case I solved this by checking the mode by doing
if(import.meta.env.MODE === "development"){
//use dev keys
}
else{
//use .env variables
}
when in production mode
import.meta.env.VITE_XX
variables will load correctly, so you can add them as env variables in your deployment service and it will work fine. I've tested it with vercel and it worked

it's works if all variables start with VITE_

Related

Package path ./standalone is not exported from package

I'm trying to use the firebase admin SDK, heres my code:
import * as admin from 'firebase-admin';
var firebaseAdminAccount = require("../serviceAccount.json");
var app : admin.app.App = null;
if(!admin.apps.length)
{
app = admin.initializeApp({
credential: admin.credential.cert(firebaseAdminAccount)
})
}
if(app === null)
{
app = admin.apps[0];
}
export default app;
the idea behind this is that whenever used, it will check if the firebase admin SDK is initialized or not, if it's not, then it will initialize it, then export it.
My problem however is when I try to run this, it gives me the following error:
error -
./node_modules/firebase-admin/lib/app/firebase-namespace.js:106:0
Module not found: Package path ./standalone is not exported from
package D:\NewRepos\1d3a\node_modules#firebase\database-compat (see
exports field in
D:\NewRepos\1d3a\node_modules#firebase\database-compat\package.json)
Import trace for requested module:
./node_modules/firebase-admin/lib/default-namespace.js
./node_modules/firebase-admin/lib/index.js ./lib/firebaseAdminSdk.ts
./middleware.ts
https://nextjs.org/docs/messages/module-not-found\
I just installed everything so it should be on the latest version, anyone have an idea why this is happening?
Seems like I didn't realize that Next.js middleware runs on V8, and therefor, firebase-admin cannot run on it. Back to the drawing board.

How to load environment variables from .env file using Vite

I want to load environment variables from the .env file using Vite
I used the import.meta.env object as mentioned in Docs
.env file:
TEST_VAR=123F
when trying to access this variable via the import.meta.env -> import.meta.env.TEST_VAR it returns undefined.
so, how can I access them?
According to the docs, you need to prefix your variables with VITE_:
To prevent accidentally leaking env variables to the client, only
variables prefixed with VITE_ are exposed to your Vite-processed code.
If you are trying to access env vars outside your app source code (such as inside vite.config.js), then you have to use loadEnv():
import { defineConfig, loadEnv } from 'vite';
export default ({ mode }) => {
// Load app-level env vars to node-level env vars.
process.env = {...process.env, ...loadEnv(mode, process.cwd())};
return defineConfig({
// To access env vars here use process.env.TEST_VAR
});
}
For svelteKit
// vite.config.js
import { sveltekit } from '#sveltejs/kit/vite';
import { defineConfig, loadEnv } from 'vite';
/** #type {import('vite').UserConfig} */
export default ({ mode }) => {
// Extends 'process.env.*' with VITE_*-variables from '.env.(mode=production|development)'
process.env = {...process.env, ...loadEnv(mode, process.cwd())};
return defineConfig({
plugins: [sveltekit()]
});
};
if you want to access your env variable TEST_VAR you should prefix it with VITE_
try something like
VITE_TEST_VAR=123f
you can access it with
import.meta.env.VITE_TEST_VAR
Here are three mistakes/gotchas that tripped me up.
Ensure the .env files are in the root, not the src directory. The filename .env and/or .env.development will work when running locally.
Restart the local web server for the variables to appear: npm run dev
Prefix the variables with VITE_ (as already mentioned by Mahmoud and Wonkledge)
Another solution that worked for me is to manually call dotenv.config() inside the vite.config.js. That will load variables from .env (all of them!) into process.env:
import { defineConfig } from 'vite'
import dotenv from 'dotenv'
dotenv.config() // load env vars from .env
export default defineConfig({
define: {
__VALUE__: process.env.VALUE
},
//....
}
where .env file could be:
VALUE='My env var value'
As stated in docs, you can change the prefix by mdoify envPrefix.
Env variables starting with envPrefix will be exposed to your client source code via import.meta.env.
So changing it to TEST_ will also work.
export default defineConfig({
...
envPrefix: 'TEST_',
...
})
You can change this option whatever you want except for empty string('').
envPrefix should not be set as '', which will expose all your env variables and cause unexpected leaking of sensitive information. Vite will throw an error when detecting ''.
So overriding the dotenv config directly to remove prefix completely could be an inappropriate action as all fields written in env would send directly into the client.
I had the same issue and solved it by running
pnpm add dot-env
pnpm add -S dotenv-webpack.
Lastly I made sure that I added VITE_ before the name I had for my environment variable, that is from MAP_API_KEY to VITE_MAP_API_KEY.

overwrite config file in nodejs - best practice?

Wondering what would be the best practice for my case.
I have a variable I need to set its value on app load and access this value many times across my code. what is the best way to get this value?
Right now I'm just overriding a config file property. Does a global variable is better? Is there another way to do this?
The priority standard for configs IMHO is:
command line parameter
environment var
local config file
global config file
if no cli parameter found, fall to look into environment vars, then local config file, then global
I do this.
Put the variable in .env file:
# .env
APP_PORT=4000
In my app source code, I create a file named constants.js:
// constants.js
import { load as loadEnvVars } from 'dotenv'; // run `npm i dotenv` to install
// load the .env file content to process.env
loadEnvVars();
// export the variables I need
export const APP_PORT = process.env.APP_PORT || 3000;
I import that file when I need it like this:
// server.js
import Express from 'express';
// import the constant
import { APP_PORT } from './constants';
const app = Express();
app.listen(APP_PORT, () => console.log('server deployed');

firebase.storage() takes either no argument or a Firebase App instance

Actually, the title is more or less the whole explanation of the problem.
I am trying to use Firebase inside my React app, which also uses NextJS and the problem is that I cannot get storage to work.
import firebase from 'firebase'
import uuid from 'uuid/v4'
// Init
try {
firebase.initializeApp({
apiKey: 'apiKey',
authDomain: 'authDomain',
databaseURL: 'dbUrl',
projectId: 'projID',
storageBucket: 'storageBucket',
messagingSenderId: 'id'
})
} catch (err) {
if (!/already exists/.test(err.message)) {
console.error('Firebase initialization error', err.stack)
}
}
console.log(firebase.app().name) // <- name
// References
const database = firebase.database()
const storage = firebase.storage().ref() // <- the problem
const documentImageStorage = storage.child('images/')
const documentsRef = database.ref('/documents/')
const documentsRequestsRef = database.ref('/requests/')
So, as I run the code I can confirm that the app works as the database works properly and the name ([default]) is returned correctly, but the line in which the storage reference is defined returns an error:
Firebase: firebase.storage() takes either no argument or a Firebase App instance. (app/invalid-app-argument).
Any ideas why this might happen? How can I solve it?
(Firebase Storage JS dev)
I was able to reproduce your error in Next.js. I'm not super familiar with it, but I understand Next.js does React-y server-side rendering, so the code you write for your page will generally be executed in the node server.
Unfortunately, Storage isn't supported in node right now, which includes server-side rendering contexts (feel free to leave a comment in the Github issue about your use case).
It should work in normal React apps (i.e. client-side code) though.
EDIT: found a (barely) workaround
The code appears to not crash in Next.js if you add an import at the top of the file:
import firebase from 'firebase'
import _s from 'firebase/storage'
import uuid from 'uuid/v4'
...
Regardless, the Storage library still isn't supported in node. Most anything interesting (uploading objects, getting object metadata) won't work, so unless all you wanted to do was call storage.toString() somewhere this probably doesn't solve your problem.
Firebase docs states that you save storage service reference to variable, then save storage reference to different variable.
https://firebase.google.com/docs/storage/web/create-reference
So I would do this like so:
const storage = firebase.storage();
const storageRef = storage.ref();
You can also put path to your storage folder to get reference for it, like this:
const documentImageStorage = storage.ref('/images/');
Ok, so I figured out how to make it work!
export const storage = process.browser ? firebase.storage().ref() : undefined
This way, storage part, which is unavailable on the backend isn't loaded, but on the frontend it is and everything works perfectly!
Thanks for both answers!

How can I use a config file in React?

Let's say I have 5 jsx files and each file uses some config parameter.
My index.js file imports all of these 5 jsx files.
Instead of having my config data spread accross 5 files, is there a way for my jsx files to get the data from a global JS object which has loaded the data from a config file?
I've seen some examples, but I've not been able to get them to work.
JS6 import function | Example using webpack
Assuming ES6:
config.js
export const myConfig = { importantData: '', apiUrl: '', ... };
Then:
jsxFileOne.js, jsxFileTwo.js, ...
import { myConfig } from 'config.js';
There are other ways to import & export things globally leveraging webpack, but this should get you started.
If your project is built using Webpack, consider using node-env-file.
Example config file snippets:
development.env
API_SERVER_URL=https://www.your-server.com
webpack.config.js
const envFile = require('node-env-file');
...
const appSettingsFile = isDevBuild ? '/settings/development.env' : '/settings/production.env';
try {
envFile(path.join(__dirname + appSettingsFile));
} catch (error) {
console.log("Failed to read env file!: " + __dirname + appSettingsFile);
}
...
plugins: [
new webpack.DefinePlugin({
"process.env": {
API_SERVER_URL: JSON.stringify(process.env.API_SERVER_URL)
}
})
...
]
Inside your js/jsx code, you can now access process.env.API_SERVER_URL variable which will contain the required value.
It seems dotenv package is more popular, you can try this out as well.
Very old problem, that nobody took the time to solve, until now. I leave this for future readers because this is a top search result for configuration in React.
I created wj-config to deal exactly with this. Be sure to pay close attention to the React notes as you will need to enable top-level awaits in webpack, either by ejecting or using the #craco/craco NPM package.
You may also read this blog post that explains its use.

Categories

Resources