Vue & Webpack: Global development and production variables - javascript

I'm using vue-cli to build my web app. My app uses an api in a number of places like so:
axios.post(API + '/sign-up', data).then(res => {
// do stuff
});
The API variable is a constant containing the beginning of the address, e.g., https://example.com.
How would I detect whether this is a dev or prod build and set that variable accordingly? For now, I have a script tag in my index.html document and I am manually changing it for dev and prod:
<script>var API = 'https://example.com'</script>
Is there a better way to handle this?

If you're using the vue-cli webpack template, within the config folder you'll see two files: dev.env.js and prod.env.js.
Both files contain an object that is globally available throughout your Vue app:
dev.env.js
module.exports = merge(prodEnv, {
NODE_ENV: '"development"'
})
prod.env.js
module.exports = {
NODE_ENV: '"production"'
}
Note that string values require the nested single and double quotes. You can add your own variables like so:
dev.env.js
module.exports = merge(prodEnv, {
NODE_ENV: '"development"',
API: '"http://localhost:8000"'
})
prod.env.js
module.exports = {
NODE_ENV: '"production"',
API: '"https://api.example.com"'
}
Now the variable can be accessed within any Vue method from the process.env object:
process.env.API

Related

How do I setup environment variables for multiple environments?

I have a Next.js application and I have currently got this next.config.js setup to access my .env file when working locally, which works fine:
// Initialize doteenv library
require("dotenv").config();
module.exports = {
webpack: config => {
// Fixes npm packages that depend on `fs` module
config.node = {
fs: "empty"
};
/**
* 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;
}
};
However when the app is built on the live (platform.sh) environment I need to access platform.sh variables instead of my .env variables. Platform.sh provide this code snippet as an example:
function read_base64_json(varName) {
try {
return JSON.parse(new Buffer(process.env[varName], 'base64').toString());
} catch (err) {
throw new Error(`no ${varName} environment variable`);
}
};
// A simple variable.
let projectId = process.env.PLATFORM_PROJECT;
// A JSON-encoded value.
let variables = read_base64_json('PLATFORM_VARIABLES');
However I am unsure where to use this and how to it working so that locally it uses my .env file and on the live environment to use the platform.sh variables. What is the best way to do this?
In your webpack.config you can reconfigure plugin section like this
plugins: [
new webpack.DefinePlugin({
VARIABLE_NAME:
process.env.NODE_ENV === "production"
? VARIABLE_PRODUCTION_VALUE
: VARIABLE_LOCAL_VALUE
})
]
You can use VARIABLE_NAME anywhere in your app and it will change depending on the environment.
dotenv overrides your environment variables with the contents of the file. You probably want to rm .env in your build hook.

Keys defined in dev.env.js are not accessible with webpack in vuejs

The template is based on vuejs-webpack, and the build, config files are here, I have not modified any of these files.
Based on Environment Variables the keys defined in dev.env.js file must be accessible when running npm run dev in the app.
This is the content of my dev.env.js:
'use strict'
const merge = require('webpack-merge')
const prodEnv = require('./prod.env')
module.exports = merge(prodEnv, {
NODE_ENV: '"development"',
SAMPLE: '"XX"',
AUTH_URL: '"http://localhost:3030"'
})
And when I try to access AUTH_URL in App.vue like this process.env.AUTH_URL, I receive undefined.
It seems to me whatever is defined in dev.env.js file will never become accessible when running npm run dev
Use the webpack.DefinePlugin to define the variables you wish to share with your front end. Webpack its self does not expose process to the browser as this is a node js function.
const dev_env = require('dev.env.js)
plugins: [
new webpack.DefinePlugin({
'process.env' : {
NODE_ENV: JSON.stringify(dev_env.NODE_ENV)
}
})
]
Some variation of the above should work for you.
If your run "npm run dev", then your new environment variable is only available after a restart of npm (Ctrl + C and again 'npm run dev').

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!

webpack expose object as global

I have a coffeeScript file 'app.coffee'
root = exports ? this
class DefipsyApplication extends Marionette.Application
user_is_superuser: () ->
app_config.is_superuser
app = new DefipsyApplication
app.addRegions {
modalRegion: '#modal-region'
}
unless root.App
root.App = app
I want to expose the App function in the browser
so here is my webpack config
module.exports = {
entry: {
app: './coffee/app.coffee',
},
output: {
path: './build/',
filename: '[name].bundle.js',
libraryTarget: "var",
library: ["MyProject", "[name]"],
},
module: {
loaders: [
{ test: './coffee/app.coffee', loaders: ['expose?App', 'coffee'] },
]
},
};
SO whene I test in browser I found that webpack was exposed my object to the browser, but this object is englobed by an other Object
so to call my method I should do
App.App
I Want to expose my function without this global var
I need to access directely with
App
here is a scree to show the object structur
In general, to expose Global Variables, Methods, and Modules in JavaScript, you can use several methods.
You could add it manually to the browser's window object by
window.app = app
or build a new object by
window.app = { func1, func2,...}
The expose-loader is an addon to Webpack, which adds modules to the global object. If you are using yarn for dependency management, you can install the expose-loader package via
yarn add expose-loader --dev
Alternatively, you can use the npm installer (Node Package Manager) via
npm i expose-loader --save
You can expose any function with
require("expose-loader?package!functionName");
If you need more information, have a look at my post here

Environment Variables in an isomorphic JS app: Webpack find & replace?

I'm using webpack to bundle an isomorphic JS app (based on this example) so that the browser runs the same code as the server. Everything is running smoothly except I have a config.js with some settings which are pulled in from environment variables on the server:
module.exports = {
servers:
auth: process.env.AUTH_SERVER_URL,
content: process.env.CONTENT_SERVER_URL
}
}
On the server this is grand, but when webpack renders this for the client process is empty and this doesn't work.
I'm hoping there's a kind of 'find and replace' webpack plugin that will replace them with their content in that file alone?
"…config.js content…".replace(/process\.env\.([a-z0-9_]+)/, function(match, varName) {
return process.env[varName];
})
Note that using the DefinePlugin as suggested in the accepted answer is potentially a dangerous action as it completely exposes process.env. As Tobias commented above there's actually a plugin EnvironmentPlugin that does exactly this with an added whitelisting ability, using DefinePlugin internally.
In your webpack.config.js:
{
plugins: [
new webpack.EnvironmentPlugin([
'NODE_ENV',
'WHITELISTED_ENVIRONMENT_VARIABLE'
])
]
}
In your webpack.config.js,
use the following preLoaders (or postLoaders),
module: {
preLoaders: [
{ test: /\.js$/, loader: "transform?envify" },
]
}
Another way using the webpack.DefinePlugin:
plugins: [
new DefinePlugin({
'process.env': Object.keys(process.env).reduce(function(o, k) {
o[k] = JSON.stringify(process.env[k]);
return o;
}, {})
})
]
NOTE: The old method using envify-loader was deprecated:
DEPRECATED: use transform-loader + envify instead.
Yeah; looks like envify-loader was the easy solution.
I just added the following to my webpack loaders:
{
test: /config\.js$/, loader: "envify-loader"
}
And the config.js (and only that file) is modified to include any referenced environment variables statically :)
I needed a way to use the env variables set on the machine that is running the code, no the env variables of the machine building the app.
I do not see a solution for this yet. This is what I did.
In publicEnv.js:
// List of the env variables you want to use on the client. Careful on what you put here!
const publicEnv = [
'API_URL',
'FACEBOOK_APP_ID',
'GA_ID'
];
const isBrowser = typeof window !== 'undefined';
const base = (isBrowser ? window.__ENV__ : process.env) || {};
const env = {};
for (const v of publicEnv) {
env[v] = base[v];
}
export default env;
In the HTML template file of the page I have:
import publicEnv from 'publicEnv.js';
...
<script>
window.__ENV__ = ${stringify(publicEnv)};
// Other things you need here...
window.__INITIAL_STATE__ = ${stringify(initialState)};
</script>
So now I can get the value of the env variable on both frontend and backend with:
import publicEnv from 'publicEnv.js';
...
console.log("Google Analytic code is", publicEnv.GA_ID);
I hope it can help.

Categories

Resources