How do I access Rails environment variables in a webpacker bundle? - ruby-on-rails

Is it possible to access my Rails environment variables from webpacker bundles? I know I can use dotenv, but the project uses Figaro and I would prefer not to change that. I would really like to pass the env vars from Rails to webpacker during compilation of the bundles.

I just ran into the same problem. If you put your .env file in config/webpack and then add this code to your config/webpack/application.js file, you should be good:
const dotenv = require('dotenv')
dotenv.config({path: __dirname + '/.env'})
environment.plugins.insert(
"Environment",
new webpack.EnvironmentPlugin(process.env)
)

I'm using webpacker 5.4.3 and I use dotenv-webpack to solve this problem.
yarn add -D dotenv-webpack
Put the ".env*" files in your Rails project root directory, then edit environment.js:
// config/webpack/environment.js
const { environment } = require('#rails/webpacker')
const Dotenv = require('dotenv-webpack');
environment.plugins.prepend('Dotenv', new Dotenv());
// your other settings...
module.exports = environment
Then you can access the environments through process.env
# .env
ABC=123
//packs/application.js
console.log(process.env.ABC)
// => 123

Related

Gatsby .env.production variables - undefined

When building a Gatsby project I'm getting all env variables undefined in production environment.
In development everything is fine.
I have 2 similar .env.development and .env.production files.
In my gatsby-config.js I have
require('dotenv').config({
path: `.env.${process.env.NODE_ENV}`,
});
and if I console.log(process.env.NODE_ENV) during gatsby build it gives production and the variables can be accessed and logged out.
But later in code something like
return request.post(`${process.env.GEOCODING_CF_URL}/latlng`, {...});
gives request to http://localhost:9000/ru/undefined/latlng.
What am I doing wrong and how this issue can be fixed?
UPDATE:
When I run gatsby build - process.env.NODE_ENV is production
When I run gatsby serve - process.env.NODE_ENV is undefined
If this can help in any way.
If you use environment variables in node you don't need a prefix (like in your gatsby-config.js). However, if you need to use them in a component or a page you must add GATSBY_ as a prefix, so GEOCODING_CF_URL should be GATSBY_GEOCODING_CF_URL
For me, NODE_ENV=production yarn gatsby serve did the trick.
https://www.gatsbyjs.com/docs/how-to/local-development/environment-variables/
Accessing Environment Variables in the browser.
By default, environment variables are only available in Node.js code and are not available in the browser as some variables should be kept secret and not exposed to anyone visiting the site.
To expose a variable in the browser, you must preface its name with GATSBY_. So GATSBY_API_URL will be available in browser code but API_KEY will not.
Variables are set when JavaScript is compiled so when the development server is started or you build your site.
src/pages/index.js
Copysrc/pages/index.js: copy code to clipboard
import React, { useState, useEffect } from "react"
function App() {
const [data, setData] = useState()
useEffect(async () => {
const result = await fetch(
`${process.env.GATSBY_API_URL}/users`
).then(res => res.json())
setData(result.data)
})
return (
<ul>
{data.map(user => (
<li key={user.id}>
<a href={user.url}>{user.name}</a>
</li>
))}
</ul>
)
}
export default App

Getting Cesium to work with Webpacker and Rails

I'm trying to follow these instructions to add cesium to my rails project with Webpack, but I can't figure out how to translate the instructions to work with the rails implementation of Webpack.
For example:
In webpack.config.js, we add the following above our configuration object:
// The path to the Cesium source code
const cesiumSource = 'node_modules/cesium/Source';
const cesiumWorkers = '../Build/Cesium/Workers';
I assume in a rails project we would do our file imports in app/javascript/packs/application.js like this:
import 'cesium/Source';
import 'cesium/Build/Cesium/Workers';
but that gives the error:
Failed to compile.
./app/javascript/packs/application.js
Module not found: Error: Can't resolve 'cesium/Build/Cesium/Workers' in '/Users/user/Developer/appName/app/javascript/packs'
# ./app/javascript/packs/application.js 15:0-37
# multi (webpack)-dev-server/client?http://localhost:3035 ./app/javascript/packs/application.js
I've double checked, and the path is correct.
The Cesium instructions also indicate that I need to add some configuration options, but I can't figure out where I would put those since the rails webpacker gem doesn't have a webpack.config.js file. Do I just add config to the same file as the imports?
You would rather add a new config file which resolve your libs custom paths.
You can get inspiration from Webpacker documentation here:
https://github.com/rails/webpacker/blob/master/docs/webpack.md#configuration
You could do this :
//config/webpack/cesium.js
module.exports = {
resolve: {
alias: {
cesiumSource: 'cesium/Source',
cesiumWorkers: 'cesium/Build/Cesium/Workers'
}
}
}
Then merge the config options either in environment.js (global) or in development|test|production.js if this is specific to a particular environment
// config/webpack/environment.js
const { environment } = require('#rails/webpacker')
const cesiumConfig = require('./cesium')
environment.config.merge(cesiumConfig)
Hope this help.
Regards

Expose Rails Env to Webpacker

I'm running Rails v5 with Webpacker v2. Everything's been smooth so far, but I've hit one hiccup: how to expose Rails helpers to my TypeScript.
I know Webpacker ships with rails-erb-loader, so I was expecting that I'd be able to add .erb to a TypeScript file, and then import that file elsewhere:
// app/javascript/utils/rails.ts.erb
export const env = "<%= Rails.env %>"
export function isEnv(envName: string) {
return env == envName
}
// app/javascript/packs/application.ts
import { env } from "../utils/rails"
But Webpack can't find the "rails" file even if I modify the typescript loader to include ERB files:
module.exports = {
test: /.ts(\.erb)?$/,
loader: 'ts-loader'
}
All I see is:
error TS2307: Cannot find module '../utils/rails'.
What's the best way to go about exposing Rails helpers and variables to my JavaScript?
Rails env comes from your environment variable. This means you configure it by setting (in bash for example) the variable in this way:
export RAILS_ENV=production
As a consequence, you don't need to deal with Rails at all.
// app/javascript/utils/rails.ts.erb
export const env = process.env.RAILS_ENV || "development"
export function isEnv(envName: string) {
return env == envName
}
This comes with a great advantage: you don't have to load the whole rails app just to compile your javascript. Rails can become really slow on first load if your app grows.
Since you won't have access to process.env on the frontend (browser), you also need a way to make it exist. In webpack, this is done through the DefinePlugin:
Update your webpack configuration to use the plugin (in plugins section): new webpack.DefinePlugin({ "process.env": { RAILS_ENV: process.env.RAILS_ENV } }) and you will get a process.env.RAILS_ENV available in the client
Rails Env can be accessed through:
process.env.RAILS_ENV

How do I set NODE_ENV=production on Electron app when packaged with electron-packager?

How do I make packaged releases of my Electron application set NODE_ENV=production when packaged with electron-packager?
UPDATE 2019/12
Use app.isPackaged: https://electronjs.org/docs/api/app#appispackaged-readonly
It returns true if the app is packaged, false otherwise. Assuming you only need a check if it's in production or not, that should do it. The env file solution detailed below would be more suitable if you had different environments/builds with different behaviors.
To my knowledge, you can't pass env vars to a packaged electron app on start (unless you want your users to always start it from the command line and pass it themselves). You can always set that env variable in your application like this: process.env.NODE_ENV = 'production'. You could integrate that with electron-packager by having an env file that gets set in your build and is required by your application to determine what environment it's in.
For example, have a packaging script that looks like:
"package": "cp env-prod.json src/env.json && npm run build"
and in your src/main.js file:
const appEnv = require('./env.json');
console.log(appEnv) //=> { env: "prod", stuff: "hey" }
//you don't really need this, but just in case you're really tied to that NODE_ENV var
if(appEnv.env === 'prod') {
process.env.NODE_ENV = 'production';
}
You can set it in 2 ways.
By command line with --no-prune see here in the usage guide
Or programmatically with this API
var packager = require('electron-packager');
var options = {
'arch': 'ia32',
'platform': 'win32',
'dir': './'
'prune': true //this set the enviroment on production and ignore dev modules
};
packager(options, function done_callback (err, appPaths) { /* … */ })
For more options see this guide

Setting Environment Variables in Rails 3 (Devise + Omniauth)

I've been trying to figure out how Ryan Bates, in his Facebook Authentication screencast, is setting the following "FACEBOOK_APP_ID" and "FACEBOOK_SECRET" environment variables.
provider :facebook, ENV['FACEBOOK_APP_ID'], ENV['FACEBOOK_SECRET']
There are similar-ish questions around, but no answers that I've been able to get to work on Rails 3.2.1.
UPDATE:
As of May 2013, my preferred way to handle ENV variables is via the Figaro gem
You could take a look at the comments:
You can either set environment variables directly on the shell where you are starting your server:
FACEBOOK_APP_ID=12345 FACEBOOK_SECRET=abcdef rails server
Or (rather hacky), you could set them in your config/environments/development.rb:
ENV['FACEBOOK_APP_ID'] = "12345";
ENV['FACEBOOK_SECRET'] = "abcdef";
An alternative way
However I would do neither. I would create a config file (say config/facebook.yml) which holds the corresponding values for every environment. And then load this as a constant in an initializer:
config/facebook.yml
development:
app_id: 12345
secret: abcdef
test:
app_id: 12345
secret: abcdef
production:
app_id: 23456
secret: bcdefg
config/initializers/facebook.rb
FACEBOOK_CONFIG = YAML.load_file("#{::Rails.root}/config/facebook.yml")[::Rails.env]
Then replace ENV['FACEBOOK_APP_ID'] in your code by FACEBOOK_CONFIG['app_id'] and ENV['FACEBOOK_SECRET'] by FACEBOOK_CONFIG['secret'].
There are several options:
Set the environment variables from the command line:
export FACEBOOK_APP_ID=your_app_id
export FACEBOOK_SECRET=your_secret
You can put the above lines in your ~/.bashrc
Set the environment variables when running rails s:
FACEBOOK_APP_ID=your_app_id FACEBOOK_SECRET=your_secret rails s
Create a .env file with:
FACEBOOK_APP_ID=your_app_id
FACEBOOK_SECRET=your_secret
and use either Foreman (starting your app with foreman start) or the dotenv gem.
Here's another idea. Define the keys and values in provider.yml file, as suggested above. Then put this in your environment.rb (before the call to Application.initialize!):
YAML.load_file("#{::Rails.root}/config/provider.yml")[::Rails.env].each {|k,v| ENV[k] = v }
Then these environment variables can be referenced in the omniauth initializer without any ordering dependency among intializers.

Resources