Access environment variables from client [duplicate] - javascript

This question already has answers here:
next.js environment variables are undefined (Next.js 10.0.5)
(8 answers)
Dynamic access of environment variables in NextJS not working
(1 answer)
Closed last year.
I'm making a lot of API calls from within my components using fetch. Everytime I had to write this logic to determine which environment I'm in So, I created a Utils class which returns the correct base url:
export default class Utils {
static get baseUrl() {
const inDev = process.env.NODE_ENV !== 'production';
const { NEXT_PUBLIC_DEV_URL, NEXT_PUBLIC_PROD_URL } = process.env;
return inDev ? NEXT_PUBLIC_DEV_URL : NEXT_PUBLIC_PROD_URL;
}
}
But now I'm getting this error when my component loads:
ReferenceError: process is not defined
I looked around and found that I need to mark my variables as NEXT_PUBLIC so I did but the problem still persists. What's the ideal way to handle this?

If you want to expose ENV variables to the client you can use publicRuntimeConfig inside your NextJS configuration (next.config.js). Here is how you could do it:
publicRuntimeConfig: {
myEnvVar: process.env.MY_ENV_VAR
}
And then in the file you would like to use your ENV variable:
import getConfig from 'next/config';
const { publicRuntimeConfig } = getConfig();
const envVar = publicRuntimeConfig.myEnvVar // store in it a 'const' or do whatever you want with it,;

Your class can actually look like this :-
export default class Utils {
static get baseUrl() {
return process.env.NEXT_PUBLIC_URL;
}
}
The NEXT_PUBLIC prefix should work well for inlining the values which are replaced at build time and sent to the browser as per docs.
In your .env.development (or whatever your dev environment file is called) file, you can have NEXT_PUBLIC_URL pointing to http://localhost:8000 and in your production you will probably have production env variables setup using a GUI (like in Netlify or Vercel), so there NEXT_PUBLIC_URL can be https://blablasite.com.
Either way, NEXT_PUBLIC prefix will ensure that at build time those values are picked up and inlined before sending the same to browser.

Related

Electron/Angular : How to use typescript component functions/variables in main.js

I am new to angular , electron.
I am trying to use type script component functions/variables in main.js.
I have LicesneController component which holds emailId, I want to call some methods at the time of tool closure which required emailId(stored in loginCompoenent).
I tried several ways to achieve this :
Local and session storage: Not worked as they cannot be used at client side. : giving error as localStorage is not defined
Include LicesneController module in main.js const { LicenseController } = require('./src/lib/LicenseController'); : giving Exception as Cann't find module
Question is :
why #2 is not working any reason (all the paths are correct) ?
Is there any other way to achieve this scenario ?
If we are using node local storage , how we can hold values set in ts file and use in js file for node local storage.
I have resolved this scenario by using win.webContents.send and ipc renderer.
I was trying to call typescript methods from main.js
in main.js:
win.webContents.send('On Close');
in typeScript :
app.component.ts :
ipcr: IpcRenderer;
ngOnInit() {
this.ipcr = window.ipcRenderer;
this.ipcr.on('On Close', (event, arg) => {
// Do Some stuff here
});
}

nestjs issue with variable in .env file

Im using NestJS framework to build a rest api, i have a issue getting the environment variables.
I have a .env with a variable "SMB_SHARE" with a path string, when i pass this variable to a class constructor of a smb2 libray, this throw an error, the string provided by the environment variable is invalid.
The environment variable is this:
SMB_SHARE=\\10.00.0.000\some_path
When i use console log in the code the variable is ok, is a string and has the correct string value. But when i pass it to the constructor, it throw the error.
I pass the string directly to the constructor, and it work fine, the others environment variables of the constructor are setted correctly (like the username and password). Only the SMB_SHARE variable is throwing the error.
I dont have idea what is the problem here. Can someone help me with this issue?
I show some examples:
constructor(private config: ConfigService) {
console.log('VAR', config.get<string>('SMB_SHARE'));
//This show the correctly string variable value
const share = config.get<string>('SMB_SHARE');
this.sambaClient = new SMB2({
share: '\\\\10.00.0.000\\some_path', //WORK
//share: share, FAIL
//share: config.get<string>('SMB_SHARE'), FAIL
//share: process.env.SMB_SHARE, FAIL
domain: '',
username: config.get<string>('SMB_USERNAME'),
password: config.get<string>('SMB_PASSWORD'),
debug: true,
autoCloseTimeout: 0,
})
}
The .env file is like this:
SMB_SHARE=\\\\10.00.0.000\\some_path
SMB_USERNAME=user
SMB_PASSWORD=secret
More than likely, what is happening is JavaScript is escaping the extra \. This is unescaped when the print happens, so it looks proper (i.e. console.log(process.env.SMB_SHARE) will print \\\\10.0.0.0\\some_path, but in reality, the variable is now \\\\\\\\10.0.0.0\\\\some_path). I ended up creating a mock of this using a text file called ./temp/.env and making use of the fs module from Node (which is what dotenv uses, which is what #nestjs/config uses. You can see below the cat (print) of the file, and the two different methods while using node to read the file
~/Documents/code
▶ cat ./temp/.env
HOST=\\\\127.0.0.1:3000\\path
~/Documents/code
▶ node
Welcome to Node.js v12.18.2.
Type ".help" for more information.
> const { readFileSync } = require('fs');
undefined
> readFileSync('./temp/.env').toString()
'HOST=\\\\\\\\127.0.0.1:3000\\\\path\n\n'
> console.log(readFileSync('./temp/.env').toString())
HOST=\\\\127.0.0.1:3000\\path
The solution here, would be to change your .env file to be the exact string you're wanting to pass on to the configuration (probably \\10.0.0.0\some_path)
you have to implement the config module.
start with
npm i --save #nestjs/config
then add the configModule in your appModule:
import { ConfigModule } from '#nestjs/config';
#Module({
imports: [ConfigModule.forRoot()],
})
export class AppModule {}

process.env.FOO transformed into {}.FOO and throwing error "expected expression, got "."

I wrote a TypeScript module that interacts with a specific RESTful API. The module never refers to process.env anywhere (target is browser, possibly Node down the line as well).
I use Rollup to transpile to a single JS file. From there, going into Node and require('./build/index') is successful, and I can even run the functions and get expected results. So Rollup itself appears to work.
But the file contains many references to things like process.env.DEBUG. (I suspect Rollup is doing something to create loggers that can work in both Node and browser.)
Now I import this into a Gatsby UI project that will need to connect to the API using this module:
import { api } from 'my-api'
api.someApiCall()
Problem is that when Gatsby compiles all this (using Webpack?) into commons.js (some big JS file with a lot of combined code from different libraries, including my API module), it appears to transform the module's process.env.DEBUG (for example) into {}.DEBUG. Then the browser complains that "expected expression, got '.'". Which makes sense. You cannot access {}.DEBUG. It would have to be ({}).DEBUG or const o = {}; o.DEBUG.
Now I have been off in the world of other languages for a while. Rollup is fairly new to me. Gatsby is very new to me. What is the way forward? Do I tell Rollup via a config to replace process.env with ({}) so that way ? But then that precludes the library from ever being used in Node.js and taking advantage of process.env.
Do I need to change something about Gatsby to have it replace process.env with ({})?
Edit For example, here is some output showing up in my browserin commons.js:
function save(namespaces) {
if (null == namespaces) {
// If you set a process.env field to null or undefined, it gets cast to the
// string 'null' or 'undefined'. Just delete instead.
delete {}.DEBUG;
} else {
{}.DEBUG = namespaces;
}
}
/**
* Load `namespaces`.
*
* #return {String} returns the previously persisted debug modes
* #api private
*/
function load() {
return {}.DEBUG;
}
In my module, those are process.env.DEBUG.
Edit 2 I've also tried putting a gatsby-node.js containing this:
exports.onCreateWebpackConfig = ({
plugins,
actions,
}) => {
const { setWebpackConfig } = actions;
setWebpackConfig({
plugins: [
plugins.define({
'process.env': "({})",
'{}.DEBUG': '({}).DEBUG',
})
]
})
}
No effect.

When using dynamic import in a function, how can I specify type info in global variable?

My simplified server code looks like below.
server.ts
import google from "googleapis";
const androidPublisher = google.androidpublisher("v3");
app.use('something', function(req, res, n){
...
})
...(only one of the dozens of other methods use androidPublisher)
I am importing googleapis library in order to setup androidpublisher variable. However, this googleapis library is big and it takes 400ms~700ms to fully import file, when it takes 10ms~30ms to import other library files.
Because my environment is serverless architecture (firebase functions), AND because approximately 1 out of 100 requests actually need androidPublisher, I want to take advantage of dynamic import to import googleapis when it is necessary. Otherwise, above setup actually adds 400ms/700ms latency to every request that spins up new serverless instance, even when androidPublisher is not needed.
So I have made changes like below.
server.ts
let androidPublisherInstance:any;
async function getAndroidPublisher() {
const googleapis = await import("googleapis");
if (androidPublisherInstance === undefined) {
const ap = googleapis.google.androidpublisher("v3");
androidPublisherInstance = ap;
}
return androidPublisherInstance;
}
...(one of methods use getAndroidPublisher() to get androidPublisher instance)
with above setup where I am using global variable & helper function to initialize androidPublisher only when needed. This works as intended and 400ms~700ms latency gets added when androidPublisher is needed for the first time. However, I ended up with type of androidPublisherInstance to be any. I couldn't correctly define the type because type definition is available inside of googleapis and that is residing inside of getAndroidPublisher function.
Thus, I lose all benefit of using typescript and have to play guess games while using methods/properties when I use androidPublisherInstance.
And I think I must use global variable, because I do not want to initialize androidPublisher multiple times (googleapis.google.androidpublisher("v3")) whenever a function calls getAndroidPublisher()
Am I missing something? Is there a way to use dynamic import & let client to be initialized only once without needing to use global variable?
You can just import the type. As long as you use it only in type definitions, not in value expressions, the compiled JavaScript will never load the module:
import { androidpublisher_v3 } from "googleapis";
let androidpublisher: androidpublisher_v3 | undefined;
Alternatively, to make sure you don't accidentally reference it in the wrong place, use only import types:
let androidpublisher: import("googleapis").androidpublisher_v3 | undefined;

How to determine if JEST is running the code or not?

I am creating a JS test on my react-native project. I'm specifically using firebase for react native, in which I would like to replace firebase instance with a mockfirebase instance if JS is running the code of my class.
For example I have class setup like below.
import firebase from 'react-native-firebase';
class Database() {
/// use the firebase instance
}
I'd like to have a check if jest is the running environment then I'd replace the import line with appropriate mock class.
jest sets an environment variable called JEST_WORKER_ID so you check if this is set:
function areWeTestingWithJest() {
return process.env.JEST_WORKER_ID !== undefined;
}
I also see that if NODE_ENV is not set the jest CLI sets it to the value 'test'. This might be another way to check.
I usually have NODE_ENV=development set globally on my shell. This works for me:
typeof jest !== 'undefined'
(note that global.jest and 'jest' in global don't work, as this doesn't seem to be a global variable, just a value made available on all modules much like node's require or __filename)
you could add parameter to global for example global.isJest and check on the front end if it is defined
For me best way is checking two things - 0 and undefined:
[0, undefined].includes(process.env.JEST_WORKER_ID)
so it's based on https://stackoverflow.com/a/52231746/3012785

Categories