How to pass webpack env into nodejs application? - node.js

I compile my nodejs application with webpack.
And I want to pass variable to my application say version.
so after I run this command:
webpack --env.VERSION=1.2.2
I run my application but I got undefined on console.log({ v: process.env.VERSION });.
How to pass webpack env into nodejs application?
I can't use cross-env or something like that. I want to compile with webpack and having the env variables in my application.

Read the docs for the --env flag (here):
The webpack command line environment option --env allows you to pass in as many environment variables as you like. Environment variables will be made accessible in your webpack.config.js.
You can use the DefinePlugin plugin to have webpack replace strings with the value of your environment variables.
For example, to replace the use of process.env.VERSION in your application code to the value of the environment variable you have set using the --env flag at build time:
plugins: [
new webpack.DefinePlugin({
"process.env.VERSION": JSON.stringify(process.env.VERSION)
})
]

According to documentation on webpack, the env variable will be available in your webpack.config.js like this
const path = require('path');
module.exports = env => {
// Use env.<YOUR VARIABLE> here:
console.log('NODE_ENV: ', env.NODE_ENV); // 'local'
console.log('Production: ', env.production); // true
return {
entry: './src/index.js',
output: {
filename: 'bundle.js',
path: path.resolve(__dirname, 'dist'),
},
};
};
See here for more details :
https://webpack.js.org/guides/environment-variables/

Related

NodeJS + WebPack setting client static data

I have a NodeJS/React/WebPack application that I'm trying to take environment variables that are present at build time and export them as variables that are available to the client without having to request them with AJAX.
What is currently setup is a /browser/index.js file with a method that is exported however the variables are not getting expanded when webpack runs.
function applicationSetup()
{
const config = JSON.parse(process.env.CONFIG);
const APPLICATION_ID = process.env.APPLICATION_ID;
.........
}
During the build process we run node node_modules/webpack/bin/webpack.js --mode production with npm.
What do I need to do in order to expand the environment variable to be their actual values when webpack creates the .js file?
Edit 8/23
I've tried adding it in the webpack.DefinePlugin section of the webpack.config.js file however it's still doesn't seem to be available in the client side code. What am I missing?
Edit #2 (webpack.config.js)
const getClientConfig = (env, mode) => {
return {
plugins: [
new webpack.DefinePlugin({
__isBrowser__: 'false',
__Config__: process.env.CONFIG,
__ApplicationID__:process.env.APPLICATION_ID
})]
}
module.exports = (env, options) => {
const configs = [
getClientConfig(options.env, options.mode)
];
return configs;
};

How do I make Vite not convert process.env to specific value during build?

Background
I use Vite to build my project from esModule to CommonJS, and I will run the result in NodeJS.
One problem that bothers me is that process.env has been converted to a specific value, but I just want process.env to stay the way it is because I will pass in the concrete value when NodeJS runs the result.
Although it is built using Vite, I think this should be a problem with Rollup.
UPDATE: It should be vite's problem.
Detail
My code looks something like this:
useVariable(process.env.ROOT)
The result of the build is something like this:
useVariable({}.ROOT)
The build result I expect:
useVariable(process.env.ROOT) // Keep it as it is
It's my config:
export default defineConfig({
build: {
outDir: '../../dist',
lib: {
entry: path.resolve(__dirname, './index.ts'),
name: 'main',
formats: ['cjs']
},
rollupOptions: {
plugins: [
autoExternal({ packagePath: './package.json' })
]
}
}
})

How to handle different .env files in Next?

What I want
I have created a new Next project, and I want to manage app behavior according to the NODE_ENV variable. The application must load different variables located in different .env files. eje. if I load NODE_ENV=development, the application should to load the variables located in .env.development file. What is the most efficient and safe way to do it in Next.
What I have
package.json
In the dev script I pass the environment type:
"scripts": {
"dev": "cross-env NODE_ENV=development next",
"build": "next build",
"start": "next start",
},
next.config.js
In the next configuration I load environment variables from correct .env file with dotenv library according to NODE_ENV variable pass in devscript in package.json.
const path = require('path');
const withOffline = require('next-offline');
const webpack = require('webpack');
require('dotenv').config({
path: path.resolve(
__dirname,
`.env.${process.env.NODE_ENV}`,
),
});
module.exports = withOffline({
webpack: (config) => {
// Returns environment variables as an object
const env = Object.keys(process.env).reduce((acc, curr) => {
acc[`process.env.${curr}`] = JSON.stringify(process.env[curr]);
return acc;
}, {});
// Allows you to create global constants which can be configured
// at compile time, which in our case is our environment variables
config.plugins.push(new webpack.DefinePlugin(env));
return config;
},
});
.env.development
TITLE=modo development
pages/index.js
function HomePage() {
return <div>{process.env.TITLE}</div>
}
export default HomePage
With this aproach...
This is the most efficient and safe way to handle diferent .env files in Next?
Nextjs supports env by default without the need to use of webpack.DefinePlugin, just pass it to the env property of next.config.js.
So your code will become:
// next.conf.js
const path = require('path');
const withOffline = require('next-offline');
const webpack = require('webpack');
require('dotenv').config({
path: path.resolve(
__dirname,
`.env.${process.env.NODE_ENV}`,
),
});
module.exports = withOffline({
env: {
VAR_1: process.env.VAR_1
...
// List all the variables that you want to expose to the client
}
});
PAY ATTENTION: these env variables may be exposed to the client side (if you use them in one of your app page).
For example, if your process.env is containing secrets, and by mistake you are using one of them in one of the pages / components that are used by pages, they will be inside js files that are downloaded to the client side.
Since Next.js 9.4, there is a built in .env loading functionality, read about it here https://nextjs.org/docs/basic-features/environment-variables
Agree with the #felixmosh that Nextjs supports env by default without the need to use of webpack.DefinePlugin, but...
It may be seen as limited and confused while loading different configurations on each environment. You can see common problem here
enter link description here
You can solve this problem easily by following these small steps.
You’ll need to create a folder config on the root, with all environment stages you’d like to have.
You can add the initial/common configuration in default.js like this.
API: {
API_URL: process.env.API_URL || '<http://localhost:4000>',
ENDPOINT: '********',
IS_MOCKING_ENABLED: false,
},
}```
Include above config files in the Next.config.js file by publicRuntimeConfig. If you’d like to have it just on the server-side use just serverRuntimeConfig like this.
const APIConfig = config.get('API')
const nextConfig = {
publicRuntimeConfig: {
APIConfig,
},
}
module.exports = nextConfig ```
Usage in any file.
const { publicRuntimeConfig } = getConfig()
const APIConfig = publicRuntimeConfig.APIConfig
[...] ```
Finally, in your package.json. You can inject the environment variables to load the appropriate configuration.
"start:local": "NODE_ENV=development run-p dev"
Reference: enter link description here for detail explanation.

Set NODE_ENV from Grunt task

I would like to set the NODE_ENV variable at the beginning of a Grunt task, to development or production, but it looks it's not as simple as I thought.
The reason, why I would like this is that I use grunt-webpack, which expects NODE_ENV to be set correctly to "development" or "production". But I also would like to initialize my tasks exclusively from grunt, if possible.
I created the following test Gruntfile, using the grunt-shell and cross-env modules:
function log(err, stdout, stderr, cb, e) {
if (err) {
cb(err);
return;
}
console.log(process.env.NODE_ENV);
console.log(stdout);
cb();
}
module.exports = function(grunt) {
grunt.initConfig({
shell: {
dev: {
command : 'cross-env NODE_ENV="development"',
options: {
callback: log
}
},
dist: {
command : 'cross-env NODE_ENV="production"',
options: {
callback: log
}
}
}
});
grunt.loadNpmTasks('grunt-shell');
};
Line 6 of log() should echo the actual value of process.env.NODE_ENV, but it constantly says undefined, even if I check it manually in the node console.
If I set it manually from the terminal, like set NODE_ENV=production (set is for Windows), everywhere echoes the value production, as I would like it to.
Your test won't work because grunt-shell runs a child_process and your callback runs after it ends and under the main process.
Same thing would happen with cross-env.
If you want to pass an environment variable to grunt-shell, you should use the options configuration according to the documentation.
For example:
grunt.initConfig({
shell: {
dev: {
command : 'echo %NODE_ENV%', //windows syntax
options: {
execOptions: {
env: {
'NODE_ENV': 'dev'
}
},
callback: log
}
}
}
});
This will still print undefined for process.env.NODE_ENV, but the value of NODE_ENV will be available in the stdout because of the echo.
On a side note, it sounds like you're trying to run a process (grunt-shell), which runs a process (cross-env), which runs a process (webpack or grunt-webpack).
Why not just use the cross-env example usage? It looks pretty close to what you need.
Or you can just define the variable in the task config itself and lose all of these wrappers.
LifeQuery's answer helped me a lot to find out what the problem actually was. I first realized that webpack.DefinePlugin() actually doesn't change anything on process.env.NODE_ENV (and it would be too late anyway, as it transforms code parsed by webpack after all loaders).
After this I created a solution, which does what I want. This is how my customized Gruntfile.js begins:
'use strict';
const path = require('path');
const webpack = require('webpack');
module.exports = function (grunt) {
// Setting the node environment based on the tasks's name or target
let set_NODE_ENV = function () {
const devTasks = ['webpack-dev-server', 'dev', 'hmr', 'watch'],
devTargets = [':dev'],
task = grunt.cli.tasks[0], // The name of the (first) task we initialized grunt with ('webpack-dev-server' if started 'grunt webpack-dev-server)
target = ':'+grunt.option('target'),
devEnv = (devTasks.indexOf(task) > -1 || devTargets.indexOf(target) > -1);
process.env.NODE_ENV = devEnv ? 'development' : 'production';
}();
const webpackConfig = require('../assets/webpack.config');
grunt.initConfig({
// ...usual Gruntfile content
});
};
I created a whitelist of grunt task names and targets when I set the process.env.NODE_ENV. As it is placed before the grunt.initConfig(), the configuration object can use process.env.NODE_ENV with the desired state.
It will set NODE_ENV to "development" if starting definitely webpack-dev-server, dev, hmr or watch tasks, or any other tasks with the :dev target.

How to use the Node debug module with Grunt?

How can I use Node's debug module with Grunt?
I know that to use the module I need to set the DEBUG env var in the command line like so:
$ DEBUG=* node app.js
But, I am struggling to figure out how to do it with Grunt.
I used grunt-env to help set env variable in grunt as below:
grunt.loadNpmTasks('grunt-env');
// Define the configuration for all the tasks
grunt.initConfig({
// Env-specific configuration
env: {
options: {
//Shared Options Hash
},
dev: {
NODE_ENV: 'development',
DEBUG: 'wukong:*,loopback:security:role,-not_this'
},
test: {
NODE_ENV: 'test',
DEBUG: 'wukong:*,-not_this'
}
},
// ...
}
However, it doesn't work because debug module load and save process.env.DEBUG at the very beginning of module initialization: https://github.com/visionmedia/debug/blob/master/node.js#L209
Thus, I played a trick to load the DEBUG variable again via its "hidden" public API - enable as:
const debug = require('debug');
debug.enable(process.env.DEBUG);
module.exports = debug;
When this debug wrapper is used instead, grunt could print out debug message as expected.
Hope this workaround works for you as well. ;)

Resources