Change configuration values post webpack build - javascript

In a static folder I have config.js
module.exports = {
config: {
urls: {
auth: localhost
}
}
}
I run npm run build and send the output (dist folder) to the client to deploy in their production environment. I want the client to be able to edit the value of auth.
config is currently configured as a external file in webpack:
const config = require(path.join(paths.STATIC, 'config.js'))
externals: [{
appsetting: JSON.stringify(config)
}]
How do I make config.js recognize changes post webpack build?

How about something like this, using axios:
function readConfig () {
return axios.get('./static/config.js').then((response) => {
return response.data
});
}
readConfig().then((config) => {
// Do stuff
});
And make sure config.js is copied to the static/ folder.

Create an entry file in webpack.config for config.js and import/require config.js in other files where you consume the config.

Related

writeToDisk with create-react-app not displaying work files

I am trying to configure webpack in my react app so that during development, the files are visible in the dist folder (or wherever).
So I tried react-app-rewired with the following config
module.exports = function override(config, env) {
config.devServer = {
devMiddleware: {
writeToDisk: true
}
}
return config;
}
But it doesn't seem to work. I've been looking for how to make writeToDisk work, and it seems to have changed at some point, because I can't find anything online that works.
How can I get writeToDisk to work so that it writes the hot-reload files to a visible folder when running react-scripts start?
I just ended up going with craco instead, which worked.
craco.config.js:
module.exports = {
devServer: (devServerConfig, { env, paths, proxy, allowedHost }) => {
devServerConfig.devMiddleware.writeToDisk = true;
return devServerConfig;
},
};

Exclude directory from webpack copy in vue CLI

I have a Vue3 project made with Vue CLI 5.0.1
My setup has a public folder where I have static assets that I need to serve, but it is very heavy (1GB of assets) so when I launch the npm run serve command I get the build stuck on [92%] sealing (asset processing copy-webpack-plugin).
I need so to exclude the public/resources directory from the copy-webpack-plugin.
I tried with the following config added in my vue.config.js:
chainWebpack: (config) => {
config.plugin("copy").tap(([options]) => {
options[0].ignore.push("resources/**");
return [options];
});
}
But I get this error:
ERROR TypeError: Cannot read property 'ignore' of undefined
This has been answered on Github.
The options format has changed so you need to modify your code as follows:
chainWebpack: (config) => {
config.plugin("copy").tap(([options]) => {
options.patterns[0].globOptions.ignore.push("resources/**");
return [options];
});
}

Webpack React: Conditionally load json config files

I have WebPack React project which I'm testing on my "staging" server.
Now its time to release it on "production" server.
I'm using server.json file which consists with server info such as api keys, api address, and so on.
What I want is to use different server.json for "production" and "staging".
And when I use production-server.json, there would be no traces of staging-server.json in my bundle.
src
- config
-- config.js
-- production-server.json
-- staging-server.json
maybe something like: yarn build-staging, yarn build-production
You should use environment variables and webpack's DefinePlugin. Additionally, you can use node-config to automatically load a json configuration file based on your NODE_ENV.
package.json
"scripts": {
"build:dev": "NODE_ENV=development start-something",
"build": "NODE_ENV=production start-something"
}
project config structure
config
default.json
{ "api": "https://api.mysite.com/v1" }
staging.json
{ "api": "http://localhost:8000/v1" }
webpack config
// node-config will load your staging.json or default.json file here
// depending on what NODE_ENV is
const config = require('config');
plugins: [
// inject window.CONFIG into your app
new webpack.DefinePlugin({
CONFIG: JSON.stringify(config)
})
]
Then in your react code you will have access to environment-specific config
componentDidMount() {
// in prod: https://api.mysite.com/v1/user/some-user-id
// in staging: http://localhost:8000/v1/user/some-user-id
return axios(`${CONFIG.api}/user/${this.props.userId}`).then(whatever...)
}
If you're on windows use cross-env to set your environment variable.
Using node-config isn't the only way to do this, there are several, but I find it pretty easy, unless you're working with electron.
edit
Since node-config uses nodejs it is typically used in front end projects in conjunction with webpack. If you are unable to to integrate it with webpack you don't need to use node-config at all, I would do something like this:
project structure
config
default.json
development.json
test.json
index.js
src
...etc
config files
// default.json, typically used for production
{
"api": "https://api.mysite.com/v1"
}
// development.json
{
"api": "http://localhost:8000/v1"
}
// index.js
// get process.env via babel-plugin-transform-inline-environment-variables
import production from './default.json';
import development from './development.json';
const { NODE_ENV: env } = process.env;
const config = {
production,
development
};
export default config[env];

node dotenv won't work with pm2

I have an application where locally (without pm2) all the environment variables in the .env file work just fine using dotenv.
But on the server where I'm using pm2 to run the app, the environment variables remain undefined.
The pm2 commands I'm using to run the app on server are:
pm2 start myapp/app.js
pm2 startup
pm2 save
dotenv will read .env file located in the current directory.
When you call pm2 start myapp/app.js it won't search for myapp/.env.
.env // It will try to load this, which doesn't exist
myapp/
app.js
So you have two solutions
use path option:
const path = require('path');
require('dotenv').config({ path: path.join(__dirname, '.env') });
Or call your script from inside myapp/
pm2 start app.js
A good pattern here is to remove dotenv from your code and "require" it on the command line. This makes your code nicely transportable between any environment (including cloud-based) - which is one of the main features of environment variables.
Note: you will still need to install dotenv in your project via npm when running it on a server.
a) code up your .env file alongside your script (e.g. app.js)
b) to run your script without pm2:
node -r dotenv/config app.js
c) in pm2.config.js:
module.exports = {
apps : [{
name : 'My Application',
script : 'app.js',
node_args : '-r dotenv/config',
...
}],
}
and then
pm2 start pm2.config.js
note: the use of dotenv/config on the command line is one of the best practices recommended by dotenv themselves
edit 2021: for completeness - as my answer has got some ticks, I wanted to add a 4th option to the list:
d) combined pm2/env config
module.exports = { apps : [{
name : 'My Application',
script : 'app.js',
env : {
PORT: 5010,
DB_STRING: 'mongodb://localhost:27017',
...
},
}]};
This will be useful if you are treating your pm2.config as environmental configuration and outside of git etc. It just negates the need for a separate .env, which may suit you. It negates the need for dotenv completely as pm2 injects the env variables into your script's process
you have kill you pm2 process first
try
pm2 kill
then restart pm2 using
pm2 start app.js
I had the same problem but it wasnt explained clearly so here is the solution based on
github user vmarchaud comment.
This also fixes the issue people had with #Andy Lorenz solution.
In my case i wanted to create an ecosystem file for multiple apps but i was keep getting
Error: Cannot find module 'dotenv/config'
The solution was easy.
You have to declar cwd, aka the project folder where the dotenv/config will be read from.
module.exports = {
apps: [{
name: 'app1 name',
script: 'app1.js',
cwd: '/path/to/folder/',
exec_mode: 'fork_mode',
node_args: '-r dotenv/config',
}, {
name: 'app2 name',
script: 'app2.js',
cwd: '/path/to/folder/',
instances: 'max',
exec_mode: 'cluster',
node_args: '-r dotenv/config',
}],
};
You can parse .env using dotenv lib end set them manually in ecosystem.config.js
ecosystem.config.js:
const { calcPath, getEnvVariables } = require('./helpers');
module.exports = {
apps: [
{
script: calcPath('../dist/app.js'),
name: 'dev',
env: getEnvVariables(),
},
],
};
helpers.js:
const path = require('path');
const dotenv = require('dotenv');
const fs = require('fs');
function calcPath(relativePath) {
return path.join(__dirname, relativePath);
}
// this function will parce `.env` file but not set them to `process.env`
const getEnvVariables = () => {
const envConfig = dotenv.parse(fs.readFileSync(calcPath('.env')));
const requiredEnvVariables = ['MODE'];
for (envVariable of requiredEnvVariables) {
if (!envConfig[envVariable]) {
throw new Error(`Environment variable "${envVariable}" is not set`);
}
}
return envConfig;
};
None of this worked for me because I was using cluster mode.
I installed dotenv as dev dependency at the root (I was using yarn workspaces too).
Then I did this:
require('dotenv').config({ path: 'path/to/your/.env' })
module.exports = {
apps: [
{
name: 'app',
script: 'server/dist/index.js',
instances: 2,
exec_mode: 'cluster',
instance_var: 'APP_INSTANCE_SEQ',
// listen_timeout: 10000,
// restart_delay: 10000,
}
]
}
I use a much simpler version of #Marcos answer:
.env
app.js
for example we need to store token in .env file and pass it right to app.js:
inside .env
token=value
inside app.js:
require('dotenv').config();
console.log(process.env.token)
Also, don't forget. If you add .env file to .gitignore and then git pull you repo on VPS or smth, you need to copy .env file manually, otherwise your app won't work.
And in some cases it's important in what area you are using your config, so make sure that NODE_ENV=production string is added to your .env file.
After all you could use pm2 start app.js right from your app's folder.
This was my project setup..
/src/app.ts
which than compiled into dist folder.
/dist/app.js
my .env file was outside dist folder so it wasn't accessible.
this is the command i tried.
pm2 start app.js --env=.env

Setting environment variables in Gatsby

I used this tutorial: https://github.com/gatsbyjs/gatsby/blob/master/docs/docs/environment-variables.md
Steps I followed:
1) install dotenv#4.0.0
2) Create two files in root folder: ".env.development" and ".env.production"
3) "follow their setup instructions" (example on dotenv npm docs)
In gatsby-config.js:
const fs = require('fs');
const dotenv = require('dotenv');
const envConfig =
dotenv.parse(fs.readFileSync(`.env.${process.env.NODE_ENV}`));
for (var k in envConfig) {
process.env[k] = envConfig[k];
}
Unfortunately, when i run gatsby develop, NODE_ENV isn't set yet:
error Could not load gatsby-config
Error: ENOENT: no such file or directory, open 'E:\Front-End Projects\Gatsby\sebhewelt.com\.env.undefined'
It works when I set it manually:
dotenv.parse(fs.readFileSync(`.env.development`));
I need environment variables in gatsby-config because I put sensitive data in this file:
{
resolve: `gatsby-source-contentful`,
options: {
spaceId: envConfig.CONTENTFUL_SPACE_ID,
accessToken: envConfig.CONTENTFUL_ACCESS_TOKEN
}
}
How to make it work?
PS: Additional question - As this made me think, I know I shouldn't put passwords and tokens on github, but as netlify builds from github, is there other safe way?
I had a similar issue, I created 2 files in the root ".env.development" and ".env.production" but was still not able to access the env file variables - it was returning undefined in my gatsby-config.js file.
Got it working by npm installing dotenv and doing this:
1) When running gatsby develop process.env.NODE_ENV was returning undefined, but when running gatsby build it was returning 'production' so I define it here:
let env = process.env.NODE_ENV || 'development';
2) Then I used dotenv but specify the filepath based on the process.env.NODE_ENV
require('dotenv').config({path: `./.env.${env}`});
3) Then you can access your variables for your config:
module.exports = {
siteMetadata: {
title: `Gatsby Default Starter`,
},
plugins: [
`gatsby-plugin-react-helmet`,
{
resolve: `gatsby-source-contentful`,
options: {
spaceId: `${process.env.CONTENTFUL_ID}`,
accessToken: `${process.env.CONTENTFUL_TOKEN}`,
},
},
],
}
You should only use env files when you're comfortable checking those into git. For passwords/tokens/etc. add them to Netlify or whatever build tool you use through their dashboard.
These you can access in gatsby-config.js & gatsby-node.js via process.env.ENV_VARIABLE.
You can't access environment variables added this way in the browser however. For this you'll need to use .env.development & .env.production.
I really dislike the .env.production file pattern, our build system sets up and uses env variables and having extra build steps to write those into a file is weird. But Gatsby only whitelists GATSBY_ of the env vars, with no obvious way of adding your own.
But doing that isn't so hard, you can do it by adding something like this in the gatsby-node.js file:
exports.onCreateWebpackConfig = ({ actions, getConfig }) => {
const config = getConfig();
// Allow process.env.MY_WHITELIST_PREFIX_* environment variables
const definePlugin = config.plugins.find(p => p.definitions);
for (const [k, v] of Object.entries(process.env)) {
if (k.startsWith("MY_WHITELIST_PREFIX_")) {
definePlugin.definitions[`process.env.${k}`] = JSON.stringify(v);
}
}
actions.replaceWebpackConfig(config);
};
After doing a few searches, I found that we can set environment variables through netlify website, here are the steps:
Under your own netlify console platform, please go to settings
Choose build & deploy tab (can be found on sidebar)
Choose environment sub-tab option
Click edit variables and add/put your credentials in
Done!

Categories

Resources