I have a large web application used by most of our department that I've been maintaining since the early versions of the ArcGIS API / Maps SDK for JavaScript. Along with looking into the Widget to Component transition, there is one really important concept for which I need clarification and guidance. Will my dojoConfig.js file (entire code pasted below) continue to work after 4.x? (I'm currently on 4.27...you guys move too fast for some of us!)
I realize Dojo framework itself has long been removed, but this piece continues to work and appears to be supported through the last 4.x version (4.34). As I understand, it’s basically a Require.js remnant that I still need to use for defining custom paths in the AMD structure in order to break up large amounts of code and for having separate classes and HTML templates. Either it will become unsupported altogether in 5.x (immediately or within a few versions) or maybe there no good way to weave this into Web Components…in either case it would leave me scrambling to find a way to reference all my files in the Visual Studio (.NET Framework) project. I asked the Community about this a couple of years ago but never got a good answer. This will take a substantial amount of time for me to re-write, when converting to Components alone, so I don't want to waste any time with my approach over the next 6 months.
Do I need to re-arrange my code altogether, and if so how best to accomplish in today's modern JS design (preferably without relying on React/Angular/Vue frameworks)? I don't have much time to research these things, having just finished overseeing a double UN deployment and loaded with many other projects. I'm only knowledgeable in so many directions.
dojoConfig.js
let locationPath = location.pathname.replace(/\/[^/]+$/, '');
window.dojoConfig = {
async: true, parseOnLoad: false, packages: [
{ name: "appJavascript", location: locationPath + "/js" },
{ name: "appJavascriptClasses", location: locationPath + "/js/classes" },
{ name: "appJavascriptChartJS", location: locationPath + "/js/chart_js" },
{ name: "appHtml", location: locationPath + "/html" }
],
has: {
"esri-native-promise": true
}
}
This is used to call Javascript files from the "appJavascript/..." path
define(["esri/config", "esri/geometry/SpatialReference", "esri/geometry/Extent", "esri/Map", "esri/views/MapView",
"appJavascript/buttonHandlers", "appJavascript/layersLegend", "appJavascript/measure", "appJavascript/redline",
], function (esriConfig, SpatialReference, Extent, Map, MapView,
appButtonHandlers, appLayersLegend, appMeasure, appRedline
) {
Here's a portion of my file structure to get an idea of the size:
Here's what else I know:
It seems like only a short matter of time before Dojo Loader is obsolete.
Solved! Go to Solution.
I don't know for certain how long Esri will continue to support AMD, but I do think you're right to be thinking along the lines of it coming to an end. For my part, the main product I support currently consists of 445 JS modules, and has been maintained and kept up to date since the very early days of 3.x. Between the 4.33 and 4.34 releases, I have undertaken migrating these modules from AMD to ESM, (a module format native to modern browsers, so no additional frameworks necessary), and it's actually gone very well. I would recommend you making that transition first before moving on to web components. This article doesn't address every single detail I've run into along the way, but I found it to be a great starting point (and a good read). The $arcgis.import function introduced with 4.33 also played a key role in my migration efforts as well.
I don't know for certain how long Esri will continue to support AMD, but I do think you're right to be thinking along the lines of it coming to an end. For my part, the main product I support currently consists of 445 JS modules, and has been maintained and kept up to date since the very early days of 3.x. Between the 4.33 and 4.34 releases, I have undertaken migrating these modules from AMD to ESM, (a module format native to modern browsers, so no additional frameworks necessary), and it's actually gone very well. I would recommend you making that transition first before moving on to web components. This article doesn't address every single detail I've run into along the way, but I found it to be a great starting point (and a good read). The $arcgis.import function introduced with 4.33 also played a key role in my migration efforts as well.
Thanks, Joel. After talking to my colleagues and reading your post I realized it's probably going to work out once I get moving into ESM. I was mixing a few things together in my mind. If I can do something like this below to replace AMD then I should be fine.
import appPrintPDF from "./js/printPDF";
appPrintPDF.initialize();
import identifyPopupHTML from './html/identifypopup.html';
The website you provided will be a helpful reference, too.
Unfortunately, you won't be able to use the import statement to retrieve text (i.e. html) files; it currently only works with js and css files. Instead, I've worked around this by using the native fetch method.
Otherwise, you're on the right track 👍
Oh yes. Funny, I would have eventually realized this after digging through all of my own code, because I actually already use fetch() in all cases for retrieving HTML elements and JSON objects. Apparently, I wasn't actually relying on the "appHtml" path in my dojo loader file for some time.
In case anyone else comes across this discussion, here's what I mean. You have a separate HTML file in your project (in this case under the /html folder) that you want to leverage for constructing a custom interface.
fetch('html/redlineAttributes.html')
.then(function (response) {
return response.text();
})
.then(function (htmlRedlineAttributes) {
createRedlineAttributesfDialog(htmlRedlineAttributes);
});
A function to create the dialog, while querying HTML elements by ID or class name...
function createRedlineAttributesfDialog(htmlRedlineAttributes) {
const parser = new DOMParser();
const renderedHtml = parser.parseFromString(htmlRedlineAttributes, 'text/html').documentElement;
const redlineAttributesDialogAttachNode = document.getElementById("redlineAttributesDialogAttachNode");
const redlineAttributesDialogContainer = document.getElementById("redlineAttributesDialogContainer");
const dialogRedlineAttributes = renderedHtml.querySelector(".dialogRedlineAttributes");
....etc.
In my case I display the dialog in a separate function.
this.showRedlineAttributesDialog = function (curGraphic) {
appAttributes.graphicID = curGraphic.graphicPairID;
const redlineAttributesDialogContainer = document.getElementById("redlineAttributesDialogContainer");
const redlineAttributesDialogAttachNode = document.getElementById("redlineAttributesDialogAttachNode");
redlineAttributesDialogContainer.style.visibility = "hidden";
redlineAttributesDialogContainer.style.display = "block";
if (redlineAttributesDialogAttachNode.offsetHeight) {
redlineAttributesDialogAttachNode.style.top = "5px";
}