next.js environment variables are undefined (Next.js 10.0.5) - javascript

I am coding a website with Next.js and I tried to add google Tag Manager.
I followed the tutorial on the Next.js Github example but for some reasons I can't access to my environment variables.
It says my variable is undefined.
I created a file .env.local on my project folder (at the same level as components, node_modules, pages, etc)
In this file I created a variable like this (test purpose) :
NEXT_PUBLIC_DB_HOST=localhost
And on my index page I tried this code :
console.log("test ", process.env.NEXT_PUBLIC_DB_HOST);
But in my console I get a "test undefined".
I tried to put my variable into an .env file instead, without success.
What I am doing wrong ?

This envs just works in Server Side. To access this envs in Client Side, you need declare in the next.config.js
This way:
module.exports = {
reactStrictMode: true,
env: {
BASE_URL: process.env.BASE_URL,
}
}

Create .env (all environments), .env.development (development environment), and .env.production (production environment).
Add the prefix NEXT_PUBLIC to all of your environment variables.
NEXT_PUBLIC_API_URL=http://localhost:3000/
Use with prefix process.env
process.env.NEXT_PUBLIC_API_URL
Stop the server and restart it:
npm run dev
I hope it works.
This solution for latest version of nextJs (above 9)

Restarting the server worked for me.
Edit & save .env.local
Stop the server and restart it, npm run dev
You should get an output on the next line like this:
> klout#0.1.0 dev
> next dev
Loaded env from [path]/.env.local

For those using NextJS +9 and looking for environment variables in the browser, you should use the NEXT_PUBLIC_ prefix. Example:
NEXT_PUBLIC_ANALYTICS_ID=123456789
See documentation for reference.

After spending countless hours on this, I found that there is a tiny little paragraph in both the pre and post nextjs 9.4 documentation:
(Pre-9.4) https://nextjs.org/docs/api-reference/next.config.js/environment-variables (same as this answer)
Next.js will replace process.env.customKey with 'my-value' at build time.
(^9.4) https://nextjs.org/docs/basic-features/environment-variables
In order to keep server-only secrets safe, Next.js replaces process.env.* with the correct values at build time.
Key words being BUILD TIME. This means you must have set these variables when running next build and not (just) at next start to be available for the client side to access these variables.

This is my next.config.js file.
/** #type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
env: {
BASE_URL: process.env.NEXT_PUBLIC_SITE_URL,
},
};
module.exports = nextConfig;
Restart the server and it worked fine. using Nextjs 12.1.0 with typescript

In my case, Im pasting REACT_APP_API_URL instead of NEXT_PUBLIC_API_URL.

Adding with the most recent version of the documentation on this, v12+.
Using the next.config.js file you can specify server and client variables:
module.exports = {
serverRuntimeConfig: {
// Will only be available on the server side
mySecret: 'secret',
secondSecret: process.env.SECOND_SECRET, // Pass through env variables
},
publicRuntimeConfig: {
// Will be available on both server and client
staticFolder: '/static',
},
}
You can still use an env.local file, and pass the variable in to the next.config.js file. For example:
publicRuntimeConfig: {
DB_URL: process.env.DB_URL
}
And then you can access the variable like this:
import getConfig from 'next/config';
const { publicRuntimeConfig } = getConfig();
publicRuntimeConfig.DB_URL;

Related

Change .page URL based on environment I need to run the suite in

We have been building our automation suite using our staging environment, but are going live soon and want to be ready to tell the project where to run (staging, production).
The only difference between the sites in the environments is the URL. My question is, from start to finish, how can I set the .page URL via a CLI option?
Right now, I have created an environment config file that holds our staging and production URLS and then I call the data into my test files. This is fine for now, but I will need to create a script with an option to set the environment at runtime without having to do a manual find and replace before kicking it off.
I've looked around online and find, what I believe, to be code snippets and general instructions, but I'm not a dev at heart and go crossed eyed. If I could get an ELI5 for this, that would be awesome.
Example of what I'm doing now:
const env = require('../environment_variables.json')
fixture `blog`
.page `${env.production}`
And then I change production to staging or vice versa manually before kicking off the suite.
Since the project will run from CICD, I would like to be able to do something like this in my CLI and script:
testcafe env=production
The env value will then be set where the .page call is for every test file.
Thanks!
There are different ways of doing this. I've used environment variables successfully in this situation, so I'll share this solution since it will solve your problem.
I create config.json in the root of the project:
{
"baseUrl": {
"dev": "https://dev.com/",
"staging": "https://staging.com/",
"prod": "https://prod.com/"
}
}
Then I create two helper functions somewhere like Helpers/env.js:
import config from '../config';
function getEnv () {
return process.env.TESTCAFE_ENV;
}
function getBaseUrl () {
return config.baseUrl[getEnv()];
}
export { getEnv, getBaseUrl };
Then in my test files in Tests/:
import { getBaseUrl } from '../Helpers/env';
const baseUrl = getBaseUrl();
fixture `Test Suite`
.page(baseUrl);
And that's it. Then when I need to run tests on the dev, I execute:
$ TESTCAFE_ENV=dev testcafe
for staging:
$ TESTCAFE_ENV=staging testcafe
and for production:
$ TESTCAFE_ENV=prod testcafe
In v1.20.0 and later, TestCafe offers a way to specify the baseUrl in the test run configuration. You can use this approach along with environment variables, see the following example:
.testcaferc.js
const BASE_URL_MAP = {
dev: 'https://dev.com/',
staging: 'https://staging.com/',
prod: 'https://prod.com/'
};
module.exports = {
baseUrl: BASE_URL_MAP[process.env.TESTCAFE_ENV]
};
Alternatively, you can use different configuration files for each of the required setups using the --config-file option.

npm-config Environment Variables

I saw that best way to store some secret strings is using config package and environment variables. This is how I set it up.
Created a config folder with 2 files (default.json, custom-environment-variables.json)
In default.json I created this:
{
"passPrivateKey": ""
}
In custom-environment-variables.json I created this:
{
"passPrivateKey": "nodeProject_passPrivateKey"
}
After I set the variable in terminal with this command:
npm config set nodeProject_passPrivateKey=randomKey
When I am reading the variable from terminal with command below it works fine and shows the correct value
npm config get nodeProject_passPrivateKey
However in code I have these lines:
if (!config.get("nodeProject_passPrivateKey")) {
console.error("nodeProject_passPrivateKey has not been set");
}
So yeah the problem is this method config.get() is not reading the value and I am getting the error not set from above. I tried doing everything in vs code as admin, and using config.get on "nodeProject_passPrivateKey" and "passPrivateKey" but the method is still not reading any value.
Why not use dotenv?
You create an .env file where you store all your secrets and you access them through
process.env.myvar

Electron store my app datas in 'userData' path

I'm building and trying do deploying a packaged electron app. FOr the packaging i used
electron-packager
electron-installer-debian
electron-installer-dmg
electron-winstaller
and I'm facing a little issue where I have to store tha appa datas somewhere in my user computer.
I saw that the good practice is to use the the folder in the path that is returned by the electron method app.getPath('userData').
from the docs
It is The directory for storing the app's configuration files, which by default it is the appData directory appended with the app name.
%APPDATA% on Windows
$XDG_CONFIG_HOME or ~/.config on Linux
~/Library/Application Support on macOS
By my tests sometimes this folder is not created automatically when the app is installed and other times yes and I'm wondering if i should create it or not.
Right now i'm quitting the app if this folder isn't present in the pc with the following code
var DatasPath = app.getPath('userData')
if (!fs.existsSync(DatasPath)){
process.exit()
}
So the question is
should i create the DatasPath folder with fs.mkdirSync(DatasPath); when it is not present or it is 'bad practice to do so', and if I can create the folder i have to warning the user the i have just added that folder?
(Expanding my reply from a "comment" to an "answer")
i don't know if i'm supposed to create it or not so i automatically
make the app quit if there is not that folder
It seems you are taking "userData" too literally? It is not an actual "folder" named "userData – it is a path to where the operating system stores data for that application. Electron currently runs on 3 operating systems and each one does things differently. For our convenience, Electron hides those differences by creating the wrapper method app.getPath(name) so the same code will work on each OS.
Try this: put the line below in your main.js script:
console.log(app.getPath('userData'));
/Users/*********/Library/Application Support/MyCoolApp
(the "*********" will be your user account name.)
UPDATED:
Run the code below in main.js and then look in the folder specified by the "userData" path
const fs = require("fs");
const path = require('path');
var datasPath = app.getPath('userData')
var data = "I am the cheese"
var filePath = path.join(datasPath, "savedData.txt")
fs.writeFileSync(filePath, data)
At pathConfig.js
function getAppDataPath() {
switch (process.platform) {
case "darwin": {
return path.join(process.env.HOME, "Library", "Application Support", "myApp");
}
case "win32": {
return path.join(process.env.APPDATA, "myApp");
}
case "linux": {
return path.join(process.env.HOME, ".myApp");
}
default: {
console.log("Unsupported platform!");
process.exit(1);
}
}
}
const appPath = __dirname;
const appDataPath =
!process.env.NODE_ENV || process.env.NODE_ENV === "production"
? getAppDataPath() // Live Mode
: path.join(appPath, "AppData"); // Dev Mode
if (!fs.existsSync(appDataPath)) {
// If the AppData dir doesn't exist at expected Path. Then Create
// Maybe the case when the user runs the app first.
fs.mkdirSync(appDataPath);
}
In each operating system the appData folder has a different path and the perfect way of getting this path is by calling app.getPath('userData') in the main process.
But there is a package that can handle this for you, it stores data in a JSON file and update it in every change.
In my opinion this package is much better than handling everything by your self.
Read more :
https://www.npmjs.com/package/electron-data-holder

Config.get() Not Getting Configuration From File: "custom-environment-variables.json" Nodejs, JavaScript

I am learning how to configure my Node.js App environment. For this I am using config module.
Below is my index.js file:
`
const config=require('config');
const express=require('express');
const app=express();
app.use(express.json()); //BUILT-IN EXPRESS MIDDLEWARE-FUNCTION
//CONFIGURATION
console.log('Current Working Environment:',process.env.NODE_ENV);
console.log('Name is:', config.get('name'));
console.log('Server is:', config.get('mail.host'));
console.log('Password is:', config.get('mail.password'));
`
I set NODE_ENV to production by the power shell command: $env:NODE_ENV="production".
My production.json file inside the config folder is:
`{
"name":"My Productoin Environmet",
"mail":{
"host": "Prod-Environment"
}
}`
And custom-environment-variables.json file is:
`{
"mail":{
"passwrod":"app_password"
}
}`
I set app_password to 12345678 by the power shell command : $env:app_password="12345678"
config.get() is supposed to look at various sources to look for this configurations including, json files, configuration files and also environment variables. But whenever I run my app, I get the following error:
`throw new Error('Configuration property "' + property + '" is not defined'); Error: Configuration property "mail.password" is not defined`
If I remove the line : console.log('Password is:', config.get('mail.password')); everything goes well. Please, guide me what is the solution?
Firstly you have a lot of syntactical errors for example in
custom-environment-variables.json
{
"mail":{
"password":"app_password"
}
}
Now if u need to store the password of your mail server in the environment variables
On windows
$env:app_password=12345
On Linux and OSX:
export app_password=12345
how to run ?
app.js
const config = require("config");
console.log("Mail Password: " + config.get("mail.password"));
i had the same problem because i didn't define an environment variable for storing the password of the mail server. So, my suggestion will be define your environment variable for storing the password using the below command line (mac) and then your code should work.
export app_password=/* the password you want to set */
how to define an environment variable for storing the password of the mail server.
While defining environment variables in command_prompt don't put space on either side of '=' sign.....
eg:
set app_password = 123456 -----> is wrong way
set app_password=123456 -----> will work
The issue in 99% of cases is in the name of the file in the config folder, storing your custom variables
To add on: make sure your file has .json extension.

npm global packages: Reference content files from package

I'm in the process of building an npm package which will be installed globally. Is it possible to have non-code files installed alongside code files that can be referenced from code files?
For example, if my package includes someTextFile.txt and a module.js file (and my package.json includes "bin": {"someCommand":"./module.js"}) can I read the contents of someTextFile.txt into memory in module.js? How would I do that?
The following is an example of a module that loads the contents of a file (string) into the global scope.
core.js : the main module file (entry point of package.json)
//:Understanding: module.exports
module.exports = {
reload:(cb)=>{ console.log("[>] Magick reloading to memory"); ReadSpellBook(cb)}
}
//:Understanding: global object
//the following function is only accesible by the magick module
const ReadSpellBook=(cb)=>{
require('fs').readFile(__dirname+"/spellBook.txt","utf8",(e,theSpells)=>{
if(e){ console.log("[!] The Spell Book is MISSING!\n"); cb(e)}
else{
console.log("[*] Reading Spell Book")
//since we want to make the contents of .txt accesible :
global.SpellBook = theSpells // global.SpellBook is now shared accross all the code (global scope)
cb()//callBack
}
})
}
//·: Initialize :.
console.log("[+] Time for some Magick!")
ReadSpellBook((e)=>e?console.log(e):console.log(SpellBook))
spellBook.txt
ᚠ ᚡ ᚢ ᚣ ᚤ ᚥ ᚦ ᚧ ᚨ ᚩ ᚪ ᚫ ᚬ ᚭ ᚮ ᚯ
ᚰ ᚱ ᚲ ᚳ ᚴ ᚵ ᚶ ᚷ ᚸ ᚹ ᚺ ᚻ ᚼ ᚽ ᚾ ᚿ
ᛀ ᛁ ᛂ ᛃ ᛄ ᛅ ᛆ ᛇ ᛈ ᛉ ᛊ ᛋ ᛌ ᛍ ᛎ ᛏ
ᛐ ᛑ ᛒ ᛓ ᛔ ᛕ ᛖ ᛗ ᛘ ᛙ ᛚ ᛛ ᛜ ᛝ ᛞ ᛟ
ᛠ ᛡ ᛢ ᛣ ᛤ ᛥ ᛦ ᛧ ᛨ ᛩ ᛪ ᛫ ᛬ ᛭ ᛮ ᛯ
If you require it from another piece of code, you will see how it prints to the console and initializes by itself.
If you want to achieve a manual initalization, simply remove the 3 last lines (·: Initialize :.) and use reload() :
const magick = require("core.js")
magick.reload((error)=>{ if(error){throw error}else{
//now you know the SpellBook is loaded
console.log(SpellBook.length)
})
I have built some CLIs which were distributed privately, so I believe I can illuminate a bit here.
Let's say your global modules are installed at a directory called $PATH. When your package will be installed on any machine, it will essentially be extracted at that directory.
When you'll fire up someCommand from any terminal, the module.js will be invoked which was kept at $PATH. If you initially kept the template file in the same directory as your package, then it will be present at that location which is local to module.js.
Assuming you edit the template as a string and then want to write it locally to where the user wished / pwd, you just have to use process.cwd() to get the path to that directory. This totally depends on how you code it out.
In case you want to explicitly include the files only in the npm package, then use files attribute of package.json.
As to particularly answer "how can my code file in the npm package locate the path to the globally installed npm folder in which it is located in a way that is guaranteed to work across OSes and is future proof?", that is very very different from the template thingy you were trying to achieve. Anyway, what you're simply asking here is the global path of npm modules. As a fail safe option, use the path returned by require.main.filename within your code to keep that as a reference.
When you npm publish, it packages everything in the folder, excluding things noted in .npmignore. (If you don't have an .npmignore file, it'll dig into .gitignore. See https://docs.npmjs.com/misc/developers#keeping-files-out-of-your-package) So in short, yes, you can package the text file into your module. Installing the module (locally or globally) will get the text file into place in a way you expect.
How do you find the text file once it's installed? __dirname gives you the path of the current file ... if you ask early enough. See https://nodejs.org/docs/latest/api/globals.html#globals_dirname (If you use __dirname inside a closure, it may be the path of the enclosing function.) For the near-term of "future", this doesn't look like it'll change, and will work as expected in all conditions -- whether the module is installed locally or globally, and whether others depend on the module or it's a direct install.
So let's assume the text file is in the same directory as the currently running script:
var fs = require('fs');
var path = require('path');
var dir = __dirname;
function runIt(cb) {
var fullPath = path.combine(__dirname, 'myfile.txt');
fs.readFile(fullPath, 'utf8' , function (e,content) {
if (e) {
return cb(e);
}
// content now has the contents of the file
cb(content);
}
}
module.exports = runIt;
Sweet!

Categories