google is not defined
sofiane-abou-abderrahim opened this issue · comments
I built a NodeJS backend application and a Webpack frontend application.
I use MongoDB as a database and the Google Maps API.
My goal is to deploy my backend code to Heroku and my frontend code to GitHub Pages.
Before that, I wanted to protect my sensitive data from my both apps using .env
files and exclude them in .gitignore
.
For that, I had to install some webpack packages and dotenv to handle the access to my environment variables.
Then, I tweaked my code in several files, especially webpack.config.js
.
After that, I wanted to try my apps in development mode to see if they work.
As a matter of fact, I have an issue with the Google Maps API.
Indeed, I can get a location with the API and create a sharable link.
However, when I paste that copied link to a new page, I get an error message alert saying 'google is not defined'.
Here some of my frontend code:
Location.js:
const googleMapsApiKey = process.env.GOOGLE_MAPS_API_KEY;
// Function to initialize the Google Maps API
function loadGoogleMapsAPI() {
const script = document.createElement('script');
script.src = `https://maps.googleapis.com/maps/api/js?key=${googleMapsApiKey}&callback=Function.prototype`;
script.defer = true;
script.async = true;
document.head.appendChild(script);
// console.log(googleMapsApiKey);
}
// Call the loadGoogleMapsAPI function to start loading the Google Maps API
loadGoogleMapsAPI();
export async function getAddressFromCoords(coords) {
const response = await fetch(
`https://maps.googleapis.com/maps/api/geocode/json?latlng=${coords.lat},${coords.lng}&key=${googleMapsApiKey}`
);
if (!response.ok) {
throw new Error('Failed to fetch address. Please try again!');
}
const data = await response.json(); // extracts the response data
if (data.error_message) {
throw new Error(data.error_message);
} // it could also fail without using an error status code, so without making it to the if (!response.ok) {} (it's a Google specific thing)
// console.log(data);
const address = data.results[0].formatted_address;
return address; // since we're using async/await, this is in the end what this invisibly created promise will resolve to
}
export async function getCoordsFromAddress(address) {
const urlAddress = encodeURI(address); // translated into a URL-friendly encoding: we get a URL-friendly string back
// we could use axios here or then() and catch() as well
const response = await fetch(
`https://maps.googleapis.com/maps/api/geocode/json?address=${urlAddress}&key=${googleMapsApiKey}`
);
if (!response.ok) {
throw new Error('Failed to fetch coordinates. Please try again!');
}
const data = await response.json(); // extracts the response data
if (data.error_message) {
throw new Error(data.error_message);
} // it could also fail without using an error status code, so without making it to the if (!response.ok) {} (it's a Google specific thing)
// console.log(data);
const coordinates = data.results[0].geometry.location;
return coordinates;
}
Map.js:
export class Map {
constructor(coords) {
// this.coordinates = coords;
this.render(coords);
}
render(coordinates) {
if (!google) {
alert('Could not load maps library - please try again later!');
return;
}
// if (typeof google === 'undefined') {
// alert('Could not load maps library - please try again later!');
// return;
// }
const map = new google.maps.Map(document.getElementById('map'), {
center: coordinates,
zoom: 16
});
new google.maps.Marker({ position: coordinates, map: map });
}
}
I shared this 2 files because I think the problem comes from them.
Location.js
is responsible of getting the coordinates.
And Map.js
is responsible of setting up Google Maps parameters.
I think the issue comes from Location.js
because it seems like I should use a callback funtion that would be linked to Map.js
.
Anyone has a solution?
I fixed the issue. I wanted to protect my sensitive data from frontend and backend. So, I stored it in .env files as variables and tried to access it in my code.
But, a quick solution was to create a key.js
file for example, where I stored my Google Maps API key in a key
constant.
export const key = 'my-api-key';
Then, I imported this key
in the files that use this API key, which are:
MyPlace.js
and SharePlace.js
:
import { key } from '../key';
document.querySelector('script').src =`https://maps.googleapis.com/maps/api/js?key=${key}&callback=Function.prototype`;
Location.js:
import { key } from '../../key';
export async function getAddressFromCoords(coords) {
const response = await fetch(
`https://maps.googleapis.com/maps/api/geocode/json?
latlng=${coords.lat},${coords.lng}&key=${key}`
);
...
}
export async function getCoordsFromAddress(address) {
const urlAddress = encodeURI(address);
const response = await fetch(
`https://maps.googleapis.com/maps/api/geocode/json?
address=${urlAddress}&key=${key}`
);
...
}
Then, in my HTML code, I removed the src
attribute and left <script defer></script>
:
dist/index.html
:
<link rel="stylesheet" href="assets/styles/app.css" />
<link rel="stylesheet" href="assets/styles/share-place.css" />
<script defer></script>
<script src="assets/scripts/SharePlace.js" defer></script>
dist/my-place/index.html
:
<link rel="stylesheet" href="../assets/styles/app.css" />
<link rel="stylesheet" href="../assets/styles/my-place.css" />
<script defer></script>
<script src="../assets/scripts/MyPlace.js" defer></script>
For the backend, I protect my sensitive data with environment variables set up in Heroku.
Now, my sensitive data are protected. However, it is still possible to see the frontend data when I push it online with GitHub Pages for example. And I don't think there is a way to change this.