This shows a way to have "environment variables" working for both the webpack-dev-server (local development) and the Divshot server (to test a build locally).
Problem:
- Divshot server expects a
.env.json
file in the project directory, and uses it to serve a__/env.js
file - Webpack dev server can serve static files from the project directory, but we need to create the
__/env.js
file ourselves
A solution:
Your index.html
in the project root directory looks something like:
<!DOCTYPE html>
<html>
<!-- ... -->
<body>
<p>Loading app...</p>
<script type="text/javascript" src="/__/env.js"></script>
<script type="text/javascript" src="bundle.js"></script>
</body>
</html>
Create a .env.js
file that looks something like:
module.exports = {
API_URL: process.env.API_URL || 'http://localhost:8081'
};
Create a scripts/
directory with two files.
The first, scripts/buildenv.js
, will create __/env.js
for the Webpack dev server and .env.json
for the Divshot static server:
require('shelljs/global');
var util = require('util');
var output;
var env = require('../.env.js');
// Used for local development with webpack-dev-server
output = util.inspect(env, {depth: null});
output = 'window.__env = ' + output + ';\n';
output.to('__/env.js');
// Used to test build with divshot server
output = JSON.stringify(env, null, 2);
output = output + '\n';
output.to('.env.json');
The second, scripts/build.js
, will build the Webpack app ready for deployment in the dist/
directory:
require('shelljs/global');
console.log('Cleaning output directory "dist/"...');
rm('-rf', 'dist');
mkdir('-p', 'dist');
console.log('Bundling all the things...');
exec('webpack --colors --progress');
console.log('Copying "index.html"...');
cp('index.html', 'dist/index.html');
console.log('Build successfull');
Make sure to update your .gitignore
with the necessary things:
.divshot-cache
dist
__
.env.json
We can create npm scripts in our package.json
to easily call what we just created:
{
"scripts": {
"start": "npm run build-env && webpack-dev-server --devtool eval-source-map --cache --colors --progress",
"build-env": "node scripts/buildenv",
"build": "node scripts/build",
"server": "npm run build-env && divshot server -p 8080",
"deploy": "divshot push"
}
}
Now, if we want to work on the app, hitting a particular API, we can do:
$ export API_URL=http://localhost:3001
$ npm start
If we want to deploy, we'll first build the app:
$ npm run build
Then we can test our build, for example hitting a remote development API:
$ export API_URL=http://development-api.example.com
$ npm run server
If all seems to work, we can deploy!
$ npm run deploy
Yes you're right, it might be overkill. Plus, having support to
.env.js
really ties it to Node. Also, we could ask why not support.env.sh
, or.env.yml
? Probably best to pick a language-agnostic format, in your case.json
, and stick with it.Another thought, would be supporting some kind of templating language directly in the JSON? For example, using Lo-Dash templates, an
.env.json
could look like:Still might be a bit overkill, but would eliminate the need to support an extra file (
.env.js
). The value is not having to check in sensitive values to the repo, but still having that.env.json
present (not having to generate it like I am).The support for env variables as command line itself is definitely interesting! Only issue I find (in my case) is that if I need to add or remove an env variable, I now need to do it in two places (
package.json
which runs thedivshot server
command, and.env.js
which is used by my Webpack dev server).And the "piggyback" thing is cool too! I can see the benefit of the Divshot server being a layer for Single Page App things like "clean URLs" and "env variables", that you put on top of any other workflow...