Environment variables in Typescript with Webpack - javascript

I am having trouble declaring globals in Typescript, using Webpack's DefinePlugin. I was hoping to get some input on what I am doing wrong.
I created an environment variable in my .bash_profile:
export API_KEY_GOOGLE_MAPS=xxxxxxxxxxxxxxxx
In my webpack.config.js, I have the following lines:
...
plugins: [
new webpack.DefinePlugin({
API_KEY_GOOGLE_MAPS: JSON.stringify(process.env.API_KEY_GOOGLE_MAPS),
}),
],
...
Inside index.tsx (I am using React), I do the following:
declare var API_KEY_GOOGLE_MAPS: string;
console.log(API_KEY_GOOGLE_MAPS)
This produces the following error, at the line containing console.log:
ReferenceError: API_KEY_GOOGLE_MAPS is not defined
Does anybody have any leads?

The other answers require create-react-app so I will offer mine.
First, add the plugin to your Webpack configuration:
const webpack = require("webpack");
module.exports = {
// ...
plugins: [
new webpack.DefinePlugin({
MY_ENV_VAR: JSON.stringify(true),
}),
],
};
Next, declare the variable in TypeScript:
declare var MY_ENV_VAR : string | undefined;
Finally, you can access the variable in your code:
console.log(MY_ENV_VAR);

create-react-app environment variables should be prefixed with REACT_APP_:
Note: You must create custom environment variables beginning with REACT_APP_. Any other variables except NODE_ENV will be ignored to avoid accidentally exposing a private key on the machine that could have the same name. Changing any environment variables will require you to restart the development server if it is running.
from the "Adding Custom Environment Variables" documentation.
You should be adding these environment variables to your .env file(s) in place of adding these to your .bash_profile file. The appropriate file will be picked up depending on the build (i.e. start or build), and the application will be easier to share and deploy.

The way I do it is to have a .env file(add it to .gitignore) in the root of my project files.
Within that file I define my project environment variables(additional variables can be separated by adding each to it's own line):
NODE_ENV=development
Then using the dotenv npm module I can access the values in any webpack file(or server side expressJS file for example).
// in the command line
$ npm install --save dotenv
// at the top of the webpack config file
require('dotenv').config();
// in the plugins of the webpack config
plugins: [
new webpack.DefinePlugin({
'NODE_ENV': JSON.stringify(process.env.NODE_ENV)
})
],
Now I can reference it within my app being transpiled by webpack:
console.log(NODE_ENV); // development

Answering my own question: my project was generated using create-react-app, and according to its documentation, environment variables are accessed this way:
console.log(process.env.API_KEY_GOOGLE_MAPS)
webpack.DefinePlugin() is not required.

Related

Could not find a declaration file for module '#editorjs/image'

I am using editorjs in my project and there are no typescript files in my project.
Could not find a declaration file for module '#editorjs/image'. 'node_modules/#editorjs/image/dist/bundle.js' implicitly has an 'any' type.
Try npm i --save-dev #types/editorjs__image if it exists or add a new declaration (.d.ts) file containing declare module '#editorjs/image';ts(7016)
No quick fixes are available. The typescript package is not available and when I am creating .d.ts file in the project
declare module "#editorjs/image"
but it is not referring to the editorjs/image package for the usage.
The problem is that the .d.ts file you've created in the project should also be listed as a part of your project in your tsconfig.json:
"include": [
"**/*.ts",
"**/*.tsx",
"global.d.ts" // << specify your file here
],

How to use environment variables in a node config file?

Given I have an environment variable $KEY
I am running
KEY=$KEY babel-node build.js //with webpack I make a bundle of my code
My problem is that in js files that webpack bundles there is import to a config.js file.
the config.js looks like this:
export default {
key: process.env.KEY;
};
When the value is used in the bundle the key is undefined.
How can I achieve this kind of behaviour. (something like actually overwriting the value config.js with the environment variables and then bundle them with webpack) ?
You can achieve that by using the DefinePlugin which exposes for the bundle the specified env variables.
new webpack.DefinePlugin({
KEY: JSON.stringify('process.env.KEY')
});

webpack issue when trying to run development environment

Before you read this sorry for splitting my code into separate documents, it wat too long for Stackoverflow editor.
I get this error when i run my development environment:
Configuration file found but no entry configured.
Use --help to display the CLI options.
This is my webpack.config.js:
let config;
if (/development/.test(process.env.NODE_ENV.indexOf('development'))) {
config = require('./config/webpack.dev')({env: 'development'});
}
else if (/production|staging/.test(process.env.NODE_ENV)) {
config = require('./config/webpack.prod')({env: 'production'});
}
module.export = config;
This is my config/webpack.dev.js:
https://docs.google.com/document/d/1oudL50sL84FQDGB7vmuYcr2yVll44UlLr5DPPuZ2-kk/edit?usp=sharing
This is my webpack.common.js:
some code that i reuse for production and development environment
https://docs.google.com/document/d/1JMQPxMbLGsOGddohkZyhbvYE1CSXWImxJll3JVQ4rQA/edit?usp=sharing
This is my package.json:
https://docs.google.com/document/d/1uk5yXCjMbBCnhGqKzrQRAEUDewwPWd_UeW3Zld4oV7w/edit?usp=sharing
I print my screen to show the console.log i did for the config inside my webpack.config file when i run the npm run dev:
http://up416.siz.co.il/up3/eqho2ydz2j2t.png
This is my app structure:
http://up416.siz.co.il/up2/y2tni0ny11mt.png
I think Webpacks' error makes sense. It finds the configuration file, webpack.config.js, but there's no 'entry' property on the value that's exported.
Firstly, module.export should be module.exports. In your example, nothing will be exported, hence there being no entry property.
Once that's fixed, I think there's another issue; looks like the below condition is wrong:
/development/.test(process.env.NODE_ENV.indexOf('development'))
Should it be this instead?
/development/.test(process.env.NODE_ENV)
Since no conditions evaluate to true, config will be exported as undefined, which will probably give you the same error.

Is it possible to use dotenv in a react project?

I am trying to set some environment variables (for making API calls to dev/prod endpoints, keys depending on dev/prod, etc.) and I'm wondering if using dotenv will work.
I've installed dotenv, and I am using webpack.
My webpack entry is main.js, so in this file I've put require('dotenv').config()
Then, in my webpack config, I've put this:
new webpack.EnvironmentPlugin([
'NODE_ENV',
'__DEV_BASE_URL__' //base url for dev api endpoints
])
However, it is still undefined. How can I do this correctly?
Sorry for picking up old question, but
react-scripts actually uses dotenv library under the hood.
With react-scripts#0.2.3 and higher, you can work with environment variables this way:
create .env file in the root of the project
set environment variables starting with REACT_APP_ there
access it by process.env.REACT_APP_... in components
.env
REACT_APP_BASE_URL=http://localhost:3000
App.js
const BASE_URL = process.env.REACT_APP_BASE_URL;
See docs for more details.
The short answer is no. A browser cannot access local or server environment variables so dotenv has nothing to look for. Instead, you specify ordinary variables in your React application, usually in a settings module.
Webpack can be made to take environment variables from the build machine and bake them into your settings files. However, it works be actually replacing strings at build-time, not run-time. So each build of your application will have the values hard-coded into it. These values would then be accessible through the process.env object.
var nodeEnv = process.env.NODE_ENV;
Additionally, you could use the DefinePlugin for webpack which lets you explicitly specify different values depending on your build target (dev, prod, etc.). Note that you have to JSON.stringify all values passed into it.
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV || 'development')
}),
This is fine for any sort of public details but should never be used for any sort of private keys, passwords or API secrets. This is because any values baked in are publicly accessible and could be used maliciously if they contain sensitive details. For those sorts of things, you need to write some server-side code and build a simple API which can authenticate with the 3rd party API using the secrets, then pass the relevant details along to your client-side application. Your server-side API acts as an intermediary, protecting your secrets while still getting the data you need.
Create .env file
API_URL=http://localhost:8000
Install dotenv npm package
$ npm install --save-dev dotenv
Config webpack to add env variables
const webpack = require('webpack');
const dotenv = require('dotenv');
module.exports = () => {
// call dotenv and it will return an Object with a parsed key
const env = dotenv.config().parsed;
// reduce it to a nice object, the same as before
const envKeys = Object.keys(env).reduce((prev, next) => {
prev[`process.env.${next}`] = JSON.stringify(env[next]);
return prev;
}, {});
return {
plugins: [
new webpack.DefinePlugin(envKeys)
]
};
Great job! Enjoy React and dotenv.
Actually, you can use dotenv in your React app with webpack. Moreover, there are several ways of doing it. However, keep in mind that it's still a build-time configuration.
A similar way to the answer above. You import dotenv in your webpack config and use DefinePlugin to pass the variables to your React app. More complete guide on how you can inject your .env files depending on current configuration could be found in this blog.
Using a dotenv-webpack plugin. I personally find it really convenient. Let's say you have environments: dev, staging and prod. You create .env file for each environment (.env.dev, .env.staging, etc). In your webpack configuration you need to pick a correct file for the environment:
const Dotenv = require('dotenv-webpack');
module.exports = (env, argv) => {
const envPath = env.ENVIRONMENT ? `.env.${env.ENVIRONMENT}` : '.env';
const config = {
...
plugins: [
new Dotenv({
path: envPath
})
]
};
return config;
};
When you build the app for a particular environment, just pass the environment name to webpack:
webpack --config webpack.config.js --env.ENVIRONMENT=dev
I Just created a config.json in the source folder:
{
"api_url" : "http://localhost:8080/"
}
then required it in the file I needed it
const config = require('./config.json');
and used config.api_url

Uncaught ReferenceError: process is not defined

I am using node.js to create a web application. When I run the application (either by opening index.html on the browser or using the command "npm start" on the terminal) I get two errors:
Uncaught ReferenceError: process is not defined
Uncaught ReferenceError: require is not defined
I solved the "require is not defined" error by specifically including in my index.html head tag the link to this script, where the require function is defined.
However, I cannot find something similar for the process function.
My question is doublefold:
Why do built-in node.js modules need to be re-defined? Why are they not recognized as they are, that is "built-in modules"? Doesn't the term "built-in module" mean that a module need not be redefined externaly/second-handedly?
Is there a way to solve this problem? My script is very simple, I am just trying to use a basic function of node.js, so I cannot figure out what errors I might have done.
If anyone has come about this problem and has found a way around it or a reason this happens, you would be of great help.
Node.js code must be run by the node process, not the browser (the code must run in the server).
To run the code, you must run the command:
node server.js
And then you can access your server from a browser by typing "http://localhost:8080", for example. You must have a file server.js (or whatever) with the server code you want (in this case, creating a web server in port 8080).
You can follow this easy example, using express as http server module: http://expressjs.com/starter/hello-world.html
Webpack can inject environment variables into the "client side" .js code (very useful in case of SPA/PWA). You should define them as plugins in webpack.config.js
webpack.config.js
module.exports = {
plugins: [
new webpack.DefinePlugin({
'process.env.NODE_ENV': JSON.stringify(process.env.NODE_ENV),
'process.env.MY_ENV': JSON.stringify(process.env.MY_ENV),
... and so on ...
})
],
}
Now you can access it on client side:
app.js
// Something like that
if(process.env.NODE_ENV === 'debug'){
setDebugLevel(1)
}
If you are facing this problem and you are using webpack, you can get the desired process data injected into the client bundle by using DefinePlugin within your webpack.config.js.
In the example below, I show how to add several things to process.env object to make available within the browser:
all the environment variables inside .env using the library
dotenv
the value of NODE_ENV, which is either 'development' or 'production'
Working example
# .env
API_KEY=taco-tues-123
API_SECRET=secret_tacos
// webpack.config.js
const dotenv = require('dotenv').config({ path: __dirname + '/.env' })
const isDevelopment = process.env.NODE_ENV !== 'production'
module.exports = {
plugins: [
new webpack.DefinePlugin({
'process.env': JSON.stringify(dotenv.parsed),
'process.env.NODE_ENV': JSON.stringify(isDevelopment ? 'development' : 'production'),
}),
].filter(Boolean),
}
// Within client side bundle (React)
// src/App.jsx
console.log(process.env) // {API_KEY: "taco-tues-123", API_SECRET: "secret_tacos"}
console.log(process.env.NODE_ENV) // development
Notice that console.log(process.env) only has the values from the .env file, and that NODE_ENV is not a part of the process.env object.
In the example below, I show how I was trying to inject the process.env object which led me to this stack overflow. I also include a highlight from the webpack documentation on why the code below was not working.
Broken example
module.exports = {
plugins: [
new webpack.DefinePlugin({
'process.env': {
...dotenv.parsed,
'NODE_ENV': JSON.stringify(isDevelopment ? 'development' : 'production')
}
}),
].filter(Boolean),
}
// Within client side bundle (React)
// src/App.jsx
console.log(process.env) // Uncaught ReferenceError: taco is not defined
console.log(process.env.NODE_ENV) // development
From the webpack DefinePlugin docs:
Warning When defining values for process prefer
'process.env.NODE_ENV': JSON.stringify('production')
over
process: { env: { NODE_ENV: JSON.stringify('production') } }
Using the latter
will overwrite the process object which can break compatibility with
some modules that expect other values on the process object to be
defined.
!Warning!
Injecting dotenv.parsed into the client bundle as described will expose these secrets to the client. For development purposes, not a big deal, but in a deployed production environment, any passwords or private api keys will be visible to anyone that goes looking for them.
I had the same problem solved it by going into my .eslintrc.js file
to configure my globals variables, adding require and process to the globals variable and setting the corresponding value equal to "writable". Hope it works for you.
this link really helped
https://eslint.org/docs/user-guide/configuring#specifying-globals
I had same problem when I tried to do this node js app: https://www.youtube.com/watch?v=mr9Mtm_TRpw
The require in html was reached from a < script> and was undefined, like
<script> require('./renderer.js');</script>
I changed it to:
<script src="./renderer.js"></script>
The process in html script was also undefined. I included the webPreferences: nodeIntegration in the js file:
win = new BrowserWindow({
width: 800,
height:600,
icon: __dirname+'/img/sysinfo.png',
webPreferences: {
nodeIntegration: true
}
});
I hope it helped.
You can add the following to your package.json file
{
"name": "mypackage",//default
"version": "0.0.1", //default
"eslintConfig": {
"env": {
"browser": true,
"node": true
}
}}
More Explanation
I was just getting this error (Uncaught ReferenceError: process is not defined) in a local hot-reloading Quasar (Vue) app when calling a particular endpoint. The fix for me ended up being to just restart the hot-reloading server (I hadn't reloaded it since adding the process.env.MY_VARIABLE code).
If you are using the npm module dotenv-webpack with Webpack 3, it might be because you are using destructuring, like so:
const { ENV1, ENV2 } = process.env;
This is a known issue.
Ugly workaround is:
const { ENV1 } = process.env;
const { ENV2 } = process.env;
If you followed all answers here but still have same error then try this.
The error is caused by the react-error-overlay package which has dependencies that were updated to support webpack v5 and are not compatible with react-scripts v4.
So to solve the Uncaught ReferenceError: process is not defined in React, open your terminal in your project's root directory and update the version of your react-scripts package by running npm install react-scripts#latest and re-install your dependencies if necessary.
You can find more detailed answers in here
I had this issue, and for some reason no amount of fiddling around with the webpack.config.js using the other suggestions would resolve it. I suspect some packages I'm using are written incorrectly for the browser, or there might be something wrong with my environment.
I ended up "fixing" it by adding the following code to my HTML file above all other <script> file references. .
<script>
// Required by some npm packages
window.process = { browser: true, env: { ENVIRONMENT: 'BROWSER' } };
</script>

Categories