'Rendering problem with React app inside Docker container

The React app described below is built in VS Code with React v18.0.0, node v.14.15.4 and npm v8.4.1. It also imports modules from a 3rd party mapping API called the ArcGIS JavaScript API and I'm running v4.18 of that.

I've used this mapping API to create many vanilla JS web apps over the years. I reference its JS and CSS via CDN. The current need is to leverage it within a React app that's deployed in a Docker container running NGINX.

I can launch the app from VS Code using 'npm start'. It runs at localhost:3000 and everything works as expected. The map renders within the correct div and it shows the gray canvas basemap tiles. The CSS is also loading correctly and the zoom +/- buttons render correctly. All of this correct behavior happens when the app is launched locally. I can deploy it IIS or I can just run 'npm start' in VS Code and it runs without issues. This is how it displays:

enter image description here

Code within the React app that creates the map and map view:

import logo from './logo.svg';
import './App.css';
import { useEffect, useState, useRef } from "react";
import esriConfig from "@arcgis/core/config";
import Map from "@arcgis/core/Map";
import MapView from "@arcgis/core/views/MapView";
import FeatureLayer from "@arcgis/core/layers/FeatureLayer";

function App() {
  const mapRef = useRef();

  esriConfig.apiKey = "REMOVED";

  const initMap = () => {
    const map = new Map({
      basemap: "arcgis-light-gray",
      layers: []
    });
  
    const view = new MapView({
      map: map,
      center: [-82.354, 27.895],
      zoom: 9,
      container: mapRef.current,
    });
  };

  useEffect(() => {
    initMap();
  }, []);

  return (
    <div className="App">
      <div id="map-div" ref={mapRef}>
        
      </div>
    </div>
  );
}

export default App;

All of the above works when hosted locally or builT and deployed to IIS.

But the ultimate goal is to deploy this app within a Docker container running NGINX. The docker image builds successfully and also runs successfully, but when I browse the app running inside the container the basemap tiles don't render. CSS and JS are both being loaded, I get 200 responses for both. The 3rd party content is loading but for some reason the images tiles in the map don't render and all I get is a map with a blank background.

enter image description here

I get the same result in Chrome and Edge. There are no errors or exception thrown in the browser's console. It's as if the JS API is loading successfully but somehow the image tiles aren't rendering and I can't see any reason why this would fail only inside a Docker container.

Dockerfile

FROM node:latest as build

WORKDIR /app

COPY package*.json ./

RUN npm install

COPY . .

RUN npm run build

FROM nginx:latest

COPY ./nginx/default.conf /etc/nginx/conf.d/default.conf
COPY --from=build /app/build/ /usr/share/nginx/html/

.dockerignore file

node_modules
Dockerfile
.git

default.conf for NGINX

server {
    listen 80;
    listen [::]:80;

    root /usr/share/nginx/html;
    index index.html index.htm index.nginx-debian.html;

    server_name localhost;

    location / {
        try_files $uri $uri/ =404;
    }
}

Because I have other React apps with ArcGIS JS maps working perfectly, I believe the problem has to have something to do with Docker and/or NGINXand how it is failing to handle the image tiles correctly.

I also noticed some differences in the requests being made by each version of this app. In the network tab of Chrome's developer tools it looks like the app makes an extra call when running locally that is not made when it's running in a docker container.

Locally it makes two calls to LightGray:Base and LightGray:Labels, and also World_Basemap_v2 further down.

enter image description here

I see fewer calls for the light gray basemap resource in the Docker container and no request for World_Basemap_v2 at all.

enter image description here

Unfortunately I don't know if the above differences are significant at all.

Has anyone else had any issues along these lines? I've already called for help on the ArcGIS forum but I sense that almost nobody is trying to run this API within Docker.

Thanks

Update & Work-Around

Uninstalling @arcgis/core and installing esri-loader instead resulted in correct rendering of the basemap I'm using.

import logo from "./logo.svg";
import "./App.css";
import { loadModules } from "esri-loader";

function App() {

  loadModules(['esri/config', 'esri/views/MapView', 'esri/Map']).then(([esriConfig, MapView, Map]) => {
    esriConfig.apiKey = "REMOVED";
    
    const map = new Map({
      basemap: 'arcgis-light-gray'
    });

    const mapView = new MapView({
      map: map,
      zoom: 10,
      center: [-82.5, 28],
      container: "map-div"
    });
  });

  return (
    <div className="App">
      <div id="map-div"></div>
    </div>
  );
}

export default App;


Solution 1:[1]

I found two work-arounds.

The problem seems to be with the esriConfig module, specifically defining an API key within a React app. A key is required to use the premium set of basemaps which includes the one I'm using, "arcgis-light-gray". I have always defined my developer API key in my ArcGIS JS apps and I've done so in this React app as well. But this module appears to be broken in React. Either that or I need to reference the module differently than I currently am. If so, it's not covered in any documentation I could find.

Work-around #1 - use a non-premium basemap like "gray" or "gray-vector". These basemaps lack the same level of detail at higher zoom levels, making this approach unacceptable if you want to zoom in to larger scales and see detail on individual parcels.

Work-around #2 - uninstall @arcgis/core and install esri-loader instead. This set of modules appears to be the better way to use the ArcGIS JS API in React. With esri-loader the modules are imported with the loadModules function instead of require or import. After refactoring the app to use esri-loader I am now able to define my API key and the premium "arcgis-light-gray" basemap renders correctly. I'll put updated code in the original post.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 LinuxConvert