The First Attempt
If you tried this on your own, you likely ran into the following error message:
Error [ERR_REQUIRE_ESM]: Must use import to load ES Module: …
require() of ES modules is not supported.
… is an ES module file as it is a .js file whose nearest parent package.json contains
“type”: “module” which defines all .js files in that package scope as ES modules.
Instead rename FeatureLayer.js to end in .cjs, change the requiring code to
use import(), or remove “type”: “module” from …
ECMAScript modules on Node are still relatively new. Therefore, ESMs are not currently supported on the server for NextJS nor NuxtJS (two of the most popular SSR frameworks for React and Vue respectively). The SSR frameworks use CommonJS modules instead, which are not included in @arcgis/core
. The omission of CommonJS modules cuts the package size roughly in half.
As suggested in the error message, I started changing file extensions to cjs
(CommonJS) or mjs
(ECMAScript). However, it quickly diverged into a game of whack-a-mole. I came across another solution for using ES modules in SSR frameworks: transpiling the dependencies with babel.
NuxtJS has a built in method for transpiling dependencies, documented here. Transpiling @arcgis/core
will take several minutes on the first build, so have patience! You will also see a few errors (below) concerning file size.
@arcgis/core
is transpiled, you will be able to import the ES modules. That should solve the issue if your application does not render a map. I included an example of a no-map solution using module transpilation in the NuxtJS sample.However, most of us like maps in our apps. And this is where we run into the second error message:
ReferenceError: Element is not defined
Forgoing SSR for the ArcGIS Component
The solution for getting @arcgis/core
working on a SSR framework is disabling server side rendering for the map component. I know, I know, that sounds like cheating right? It’s actually a viable option. The rest of your application will still reap the benefits of SSR. How much information for Search Engine Optimization (SEO) lives in the map component anyway?
import dynamic from "next/dynamic";
const EsriMapWithNoSSR = dynamic(() => import("../components/EsriMap"), {
ssr: false,
});
export default () => <EsriMapWithNoSSR />
That’s it. Now you can use the EsriMapWithNoSSR
component and the map will render!
Article Discussion: