2

I am trying to deploy a simple static app consisting of HTML, CSS, and Javascript files to Heroku. I have added "dummy" composer.json and index.php files as well, to allow the static file to reside in Heroku. When I go to the hosted page, I see a blank screen. The console window shows as shown below. The files are linked to my GitHub repo, so I am using a .gitignore file to exclude my API key, and saving the API key in Config Vars in Heroku. The app is not finding the API key and throwing the error.

Uncaught ReferenceError: MAPBOX_KEY is not defined                 logic.js:68
    at createMap (logic.js:68)
    at createFeatures (logic.js:56)
    at logic.js:9
    at d3.min.js:3
    at Object.<anonymous> (d3.min.js:7)
    at d.call (d3.min.js:4)
    at XMLHttpRequest.e (d3.min.js:7)

So far I have tried the following:

  • Added API key directly in Heroku under Settings/Config Vars

  • Used console window to add key heroku config:add MAPBOX_KEY=pk.eyJ1I.....

  • Disabled the cache the web page

  • Ran Empty Cache and Hard Reload on web page

  • Ran heroku config in the console and received following error:

    heroku config
    »   Error: Missing required flag:
    »     -a, --app APP  app to run command against
    »   See more help with --help
    

I have searched the documentation and stack overflow and can't find anything about API keys with Javascript in Heroku. Do I need to add additional code to my .js or .html file for the app to find the key on the Heroku server? Below is a portion of the .js code down to the line of the error.

// +++++ Leaflet Challenge +++++

// store API endpoint inside queryUrl
var queryUrl = "https://earthquake.usgs.gov/earthquakes/feed/v1.0/summary/all_week.geojson";

// make API call to USGS and perform a GET request to the query URL
d3.json(queryUrl, function(data) {
   // after a response, send the data.features object to the createFeatures function
   createFeatures(data.features);
});

// Circle radius function
function circleSize(magnitude) {
   return magnitude **2 * 2000 
};

// Circle color function by depth
function circleColor(depth) {
   switch (true) {
      case (depth > 90):
         return "#d73027"; //red
      case (depth > 70):
         return "#fc8d59"; //darkorange
      case (depth > 50):
         return "#fee08b"; //lightorange
      case (depth > 30):
         return "#d9ef8b"; //yellow
      case (depth > 10):
         return "#91cf60"; //yellowgreen
      default:
         return "#1a9850"; //green
   }
};

function createFeatures(earthquakeData) {

   // define a function and run once for each feature in the features array
   // give each feature a popup describing the place and time of the earthquake
   var earthquakes = L.geoJSON(earthquakeData, {
      onEachFeature: function(feature, layer) {
         layer.bindPopup("<h3>Magnitude: " + feature.properties.mag +"</h3><h3>Depth: " + feature.geometry.coordinates[2] + " km</h3><hr><h4>Location: " + feature.properties.place + "</h4><hr><p>" + new Date(feature.properties.time) + "</p>");
      },

      pointToLayer: function(feature, latlng) {
         return new L.circle(latlng, {
            radius: circleSize(feature.properties.mag),
            fillColor: circleColor(feature.geometry.coordinates[2]),
            color: "black",
            weight: .5,
            fillOpacity: 0.8
         })
      }
   });
  
   // send earthquakes layer to the createMap function
   createMap(earthquakes);
}

function createMap(earthquakes) {

   // define lightmap layer
   var lightmap = L.tileLayer('https://api.mapbox.com/styles/v1/{id}/tiles/{z}/{x}/{y}?access_token={accessToken}', {
      attribution: 'Map data &copy; <a href="https://www.openstreetmap.org/">OpenStreetMap</a> contributors, <a href="https://creativecommons.org/licenses/by-sa/2.0/">CC-BY-SA</a>, Imagery © <a href="https://www.mapbox.com/">Mapbox</a>',
      tileSize: 512,
      maxZoom: 18,
      zoomOffset: -1,
      id: "mapbox/light-v10",  
      accessToken: MAPBOX_KEY
   });

Thank you ahead of time for any help you can provide. This is my first experience deploying to Heroku, so it's all new to me.

Dave Damon
  • 21
  • 1

1 Answers1

2

Heroku config variables are the classic environment variables at operative system(linux, mac, windows) which are designed to be accessed from backend languages who has access to the operative system like: java, php, nodejs, ruby, python, etc

According to your snippets, you need to read this environment var in your vanilla javascript which is called from your html in some web browser, which is IMPOSSIBLE

Vanilla javascript or pure javascript is not allowed to access to some operative system resources like environment variables in this case.

Check this link to understand how variables works in vanilla javascript:

How to use variable substitution in Frontend js applications like backend applications?

Quick Solution

in your php code read this var before the web renderization at operative system layer, because php is able to do that:

Php is not my best skill but I am sure that it has several options to inject this var into the static html or javascript

If not, you could use a trivial string replacement in the static file:

im_your_file.js

zoomOffset: -1,
id: "mapbox/light-v10",  
accessToken: @@MAPBOX_KEY@@

another_php_file.php

replaceStringInFile("@@MAPBOX_KEY@@")

Dirty solution

Use this replace content in file in another php file and call it from some heroku step before the app startup

You could perform this file replacement using pure bash and call it in some heroku step

Elegant solution

Webapck variable injection

Best solution

Instead of read directly the var in your javascript, yo must publish a kind of rest endpoint in your php app like /settings.php. This endpoint must return this and other variables as json.

In you javascript file, instead to ise directly the variable, consume the /settings.php and you will havr the required variable in your javascript code.

JRichardsz
  • 14,356
  • 6
  • 59
  • 94