New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
How to use environment variables at runtime? #477
Comments
I second the motion for @alex2 claim, I just found out that it really really replaces the existing process.env because of that DefinePlugin, I need it NOT be overwritten too |
What I do is by breaking static analysis: let proc = process;
module.exports = proc.exports; Then |
I've personally struggled with this issue and spend several hours figuring out a solution to this issue. This is inherent to webpack compilation and not related to razzle it self. After looking into how create-react-app handles this, and porting some javascript and ruby code, across two projects, I've successfully deployed a razzle typescript react app in a docker container on heroku with the following solution: env.tsThis script is used as a module to handle runtime env. export interface EnvironmentStore {
NODE_ENV?: string;
[key: string]: string | undefined;
}
// Capture environment as module variable to allow testing.
let compileTimeEnv: EnvironmentStore;
try {
compileTimeEnv = process.env as EnvironmentStore;
} catch (error) {
compileTimeEnv = {};
// tslint:disable-next-line no-console
console.log(
'`process.env` is not defined. ' +
'Compile-time environment will be empty.'
);
}
// This template tag should be rendered/replaced with the environment in production.
// Padded to 4KB so that the data can be inserted without offsetting character
// indexes of the bundle (avoids breaking source maps).
/* tslint:disable:max-line-length */
const runtimeEnv = '{{RAZZLE_VARS_AS_BASE64_JSON__________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________________}}';
/* tslint:enable:max-line-length */
// A function returning the runtime environment, so that
// JSON parsing & errors occur at runtime instead of load time.
export const loadRuntimeEnv = (): EnvironmentStore => {
let env;
if (typeof env === 'undefined') {
if (compileTimeEnv.NODE_ENV === 'production') {
try {
env = JSON.parse((Buffer.from(runtimeEnv.trim(), 'base64').toString()));
} catch (error) {
env = {};
const overflowsMessage = runtimeEnv.slice(32, 33) !== null;
// tslint:disable-next-line no-console
console.error(
'Runtime env vars cannot be parsed. Content is `%s`',
runtimeEnv.slice(0, 31) + (overflowsMessage ? '…' : '')
);
}
} else {
env = compileTimeEnv;
}
}
return env;
};
export default loadRuntimeEnv; usage: import { loadRuntimeEnv, EnvironmentStore } from './env';
const env: EnvironmentStore = loadRuntimeEnv();
const serverHost: string =env.RAZZLE_SERVER_HOST || 'localhost'; docker-start.jsThis script is used as the entrypoint point instead of server.js and is used to inject {{RAZZLE_VARS_AS_BASE64_JSON___... }} placehoder with the actual runtime environment variables. require('newrelic');
const logger = require('heroku-logger');
const path = require('path');
const fs = require('fs');
const PLACEHOLDER = /\{\{RAZZLE_VARS_AS_BASE64_JSON_*?\}\}/;
const MATCHER = /^RAZZLE_/i;
const InjectableEnv = {
inject: function(file, ...args) {
const buffer = fs.readFileSync(file, { encoding: 'utf-8' });
let injectee = buffer.toString();
const matches = injectee.match(PLACEHOLDER);
if (!matches) {
return;
}
const placeholderSize = matches[0].length;
let env = InjectableEnv.create(args);
const envSize = env.length;
const newPadding = placeholderSize - envSize;
if (newPadding < 0) {
console.log('You need to increase your placeholder size');
process.exit();
}
const padding = Array(newPadding).join(' ');
env = InjectableEnv.pad(padding, env);
const injected = injectee.replace(PLACEHOLDER, env);
fs.writeFileSync(file, injected, { encoding: 'utf-8' });
},
create: function() {
const vars = Object.keys(process.env)
.filter(key => MATCHER.test(key))
.reduce((env, key) => {
env[key] = process.env[key];
return env;
}, {});
vars.NODE_ENV = process.env.NODE_ENV;
if (typeof process.env.HOST !== 'undefined' && typeof vars.RAZZLE_SERVER_HOST === 'undefined') {
vars.RAZZLE_SERVER_HOST = process.env.HOST;
}
if (typeof process.env.PORT !== 'undefined' && typeof vars.RAZZLE_SERVER_PORT === 'undefined') {
vars.RAZZLE_SERVER_PORT = process.env.PORT;
}
if (typeof process.env.REDIS_URL !== 'undefined' && typeof vars.RAZZLE_REDIS_URL === 'undefined') {
vars.RAZZLE_REDIS_URL = process.env.REDIS_URL;
}
return Buffer.from(JSON.stringify(vars)).toString('base64');
},
pad: function(pad, str, padLeft) {
if (typeof str === 'undefined')
return pad;
if (padLeft) {
return (pad + str).slice(-pad.length);
} else {
return (str + pad).substring(0, pad.length);
}
}
}
const root = process.cwd();
const serverBundle = path.resolve(path.join(root, '/build/server.js'));
if (fs.existsSync(serverBundle)) {
logger.info('Injecting runtime env');
InjectableEnv.inject(serverBundle);
logger.info('Launching server instance');
require(serverBundle);
} Dockerfile
References:Heroku Buildpack for create-react-app |
Not relevant to the issue but here is the Dockerfile for completeness: # You should always specify a full version here to ensure all of your developers
# are running the same version of Node.
FROM node:8.9.4
ENV NODE_ENV=production \
REACT_BUNDLE_PATH=/static/js/vendor.js \
PATH=/app/node_modules/.bin:$PATH \
NPM_CONFIG_LOGLEVEL=warn
RUN curl -o- -L https://yarnpkg.com/install.sh | bash
# use changes to package.json to force Docker not to use the cache
# when we change our application's nodejs dependencies:
COPY package.json yarn.lock /tmp/
RUN cd /tmp \
&& yarn install --production=false --pure-lockfile \
&& mkdir -p /app \
&& cp -a /tmp/node_modules /app \
&& yarn cache clean \
&& rm -rf *.*
# From here we load our application's code in, therefore the previous docker
# "layer" thats been cached will be used if possible
WORKDIR /app
ADD . /app
RUN yarn build
EXPOSE 3000
CMD ["node", "docker-start.js"] |
@jaredpalmer Can you have a look at this and see whether this solution can be used to solve #356, #394 and this issue in razzle or a child package? |
Hola! So here's the deal, between open source and my day job and life and what not, I have a lot to manage, so I use a GitHub bot to automate a few things here and there. This particular GitHub bot is going to mark this as stale because it has not had recent activity for a while. It will be closed if no further activity occurs in a few days. Do not take this personally--seriously--this is a completely automated action. If this is a mistake, just make a comment, DM me, send a carrier pidgeon, or a smoke signal. |
ProBot automatically closed this due to inactivity. Holler if this is a mistake, and we'll re-open it. |
if anyone want to use .env variables in client side in runtime, use this little package. |
I came across this during a google search for an issue related to this. Full disclosure: im not using razzle but I think this might be helpful. A way to circumvent webpack's replacement of process.env is to access the env vars in a different way. You can access it via
or by importing process... DefinePlugin only replaces free variables |
@albert-the-creator Razzle clear env variable's during development in browser area. |
I've just started using Razzle but it seems like a webpack
DefinePlugin
is stripping out all the environment variables at runtime and replacing them with pre-baked ones. Since environment variables are the standard way to configure applications in different environments (e.g. heroku, lambda, all 12-factor compatible hosting) I assume there's something I'm missing. Do you have any advice for how to stop razzle replacing everything inprocess.env
?Many thanks
The text was updated successfully, but these errors were encountered: