Créez des widgets dans Mendix avec React Partie 4 - Cartes ArcGIS | Mendix

Passer au contenu principal

Créez des widgets dans Mendix avec React Partie 4 – Cartes ArcGIS

Créer des widgets dans Mendix - partie 4

Dans ce blog, nous allons créer des cartes dans notre widget, en utilisant l'API Javascript d'ArcGIS et une petite leçon d'histoire en cours de route.

Mendix est la plateforme low-code numéro un, et l'un de ses principaux atouts est l'extensibilité qu'elle offre. Vous pouvez utiliser React pour intégrer des bibliothèques tierces intéressantes et étendre votre application.

Il s'agit du blog 4 d'une série en plusieurs parties, les blogs précédents peuvent être trouvés ici : Créez des widgets dans Mendix avec React — Partie 1 — Compteur de couleursCréer des widgets dans Mendix avec React Partie 2 — Minuterie et Créer des widgets dans Mendix avec React Partie 3 — Kanban.


Que construisons-nous

Récemment, Ivo Sturm j'ai écrit un blog sur la conversion d'un widget ArcGIS existant de Dojo vers React.

J'ai pensé que ce serait intéressant de créer une version simple du widget de carte ArcGIS à partir de zéro.

Commencer

Comme pour tous les blogs de widgets enfichables jusqu'à présent, nous commençons par échafaudage de notre widget en exécutant yo @mendix/widget arcGISMap et mise en place d'un test Mendix Projet.

Commençons par installation du paquet npm pour l'API Javascript d'ArcGIS

npm install @arcgis/core

ArcGIS est un système d'information géographique en ligne qui vous permet d'afficher des cartes et d'ajouter des couches pour afficher toute une gamme d'informations.

Afin d'accéder au service complet vous devez vous inscrire et créer un jeton d'accès mais nous pouvons continuer sans en utiliser un pour notre exemple simple.

Premiers pas

Examen du Documentation nous pouvons mettre à jour notre code pour avoir deux fichiers :

Un parent

importer { ReactElement, createElement } depuis "react"; importer { MapComponent } depuis "./components/Map"; importer { ArcGISMapBlogContainerProps } depuis "../typings/ArcGISMapBlogProps"; importer "./ui/ArcGISMapBlog.css";
fonction d'exportation ArcGISMapBlog(props: ArcGISMapBlogContainerProps): ReactElement { retour ; }

Et un enfant

importer { ReactElement, createElement, useEffect, useRef } depuis "react"; importer Map depuis "@arcgis/core/Map"; importer MapView depuis "@arcgis/core/views/MapView"; importer la légende depuis "@arcgis/core/widgets/Légende";
interface d'exportation MapProps { basemap: chaîne; }
fonction d'exportation MapComponent({ basemap }: MapProps): ReactElement { const mapDiv = useRef(null);
useEffect(() => { if (mapDiv.current) { MountMap(carte de base); } }, [carte de base]);
const MountMap = (basemap: string): MapView => { const legend = new Legend(); const map = new Map({ basemap }); const view = new MapView({ map, center: [0.029, 51.256], // Longitude, latitude zoom: 10, // Niveau de zoom conteneur: mapDiv.current comme inconnu comme HTMLDivElement });
        legend.view = vue; view.ui.add(légende, "en bas à droite"); return view; };
retour ; }

Se importer également la feuille de style depuis ArcGIS afin que nous puissions rendre notre widget plus joli, changez votre UI/{widgetName}.css en :

@import "https://js.arcgis.com/4.24/@arcgis/core/assets/esri/themes/dark/main.css";

Nous construisons maintenant notre widget avec npm run build et… nous obtenons une erreur :

[!] Erreur : valeur non valide pour l'option « output.file » - lors de la création de plusieurs blocs, l'option « output.dir » doit être utilisée, et non « output.file ». Pour intégrer des importations dynamiques, définissez l'option « inlineDynamicImports ».

Alors comment résoudre ce problème ? Pour l’expliquer, il faut revenir quelques pas en arrière…

Une brève histoire de Javascript

Cette section suivante est une brève histoire de Javascript, pour donner un contexte à la solution, si cela ne vous intéresse pas, n'hésitez pas à sauter et à continuer avec l'exemple

Au début…

Javascript a été inventé par Brendan Eich en 1995 et, pendant les premières années de son développement, il était principalement utilisé pour des tâches de script isolées. À mesure que JS a commencé à être davantage utilisé dans les applications, il est devenu plus difficile de gérer le code. JS a été utilisé de manière plus complexe, souvent dans plusieurs scripts, ce qui a inévitablement conduit à des conflits de fonctions et de noms.

C'est ainsi qu'a été introduit le concept de module, ce qui signifie que le code pouvait être écrit dans un endroit fermé pour une utilisation interne sans crainte de conflits ailleurs et permettait également aux développeurs de diviser de grandes bases de code en petites parties séparées, ce qui le rendait beaucoup plus facile à écrire et à maintenir.

La première tentative pour résoudre ce problème a été avec Expressions de fonction appelées immédiatement (IIFE), qui consistait essentiellement à envelopper chaque fichier dans une fonction, en conservant les variables et les fonctions dans un fichier, dans cette portée au lieu de la portée globale.

(function() {// Your code }) ();

Cette approche présente encore de nombreux problèmes, notamment un manque de résolution des dépendances et pollution de l'espace de noms global.

Au fil du temps, 3 spécifications de modules distinctes (et concurrentes) ont émergé :

  • CommonJS — encore largement utilisé dans Node pour le JS côté serveur, et facilement reconnaissable par son require() et module.exports syntaxe
  • AMD — Définition de module asynchrone, séparée de CommonJS au début. La principale différence est qu'AMD permet aux modules qui ne dépendent pas les uns des autres d'être chargés de manière asynchrone (tout est dans le nom !)
  • UMD — Définition de module universelle, prend en charge les deux autres spécifications de module ainsi que la définition de variable « globale » « à l'ancienne »

Tout cela est très compliqué… alors voici quelques bonnes nouvelles. Depuis 2015 et la sortie d’ES6, les modules ont été pris en charge dans le langage Javascript. Cela nous donne le joli et simpleimport et export syntaxe que nous avons utilisée dans notre code.

Alors pourquoi cette leçon d'histoire ? Eh bien, nous devons être capables de gérer tous ces types de modules lorsque nous écrivons notre code, et c'est là qu'interviennent les bundlers.

Bundle

Les bundlers vous permettent de compilez votre code au moment de la construction, traiter vos dépendances et fournir un fichier concaténé compatibleLes solutions courantes pour cela incluent Webpack (utilisé dans Mendix 8 widgets) et Cumulatif (utilisé dans Mendix 9 widgets)

Cela vous permet d'écrire votre code de manière modulaire en utilisant les fonctionnalités ES6 modernes (et même Typescript si vous le souhaitez), puis de produire un fichier optimisé (ou un ensemble de fichiers) à diffuser au navigateur.

C'est génial, mais certains navigateurs ne prennent pas encore en charge ES6, ils ne pourront donc rien faire avec ces fichiers bien compilés. Pour résoudre ce problème nous pouvons utiliser un Transpiler comme Babel pour le servir à la page Web dans un format dans lequel il peut être lu.

Revenons donc à nos widgets…


Le framework Pluggable Widget nécessite tous les outils dont vous avez besoin pour développer des composants React pour Mendix applications. Cela comprend :

  • NPM — Un gestionnaire de paquets pour installer et gérer facilement des paquets tiers
  • Cumulatif — Un bundler, qui vous permet d'écrire votre code de manière modulaire, puis de le regrouper dans de petits packages
  • babel — Un transpilateur qui convertit le JS en un format lisible par les anciens navigateurs (et Studio Pro)

Alors, quelle est la signification de notre erreur ?

[!] Erreur : valeur non valide pour l'option « output.file » - lors de la création de plusieurs blocs, l'option « output.dir » doit être utilisée, et non « output.file ». Pour intégrer des importations dynamiques, définissez l'option « inlineDynamicImports ».

Pour chaque projet de widget, nous utilisons la configuration cumulative fournie par la bibliothèque @mendix/pluggable-widget-tools.

Cela peut être trouvé dans: node_modules/@mendix/pluggable-widget-tools/configs.rollup.config.js.

Dans cette configuration, nous sommes dire à notre widget de cracher notre JS compilé dans un seul fichier. Pendant ce temps, le Bibliothèque ArcGIS npm nous utilisons fournit importations dynamiques en morceaux, qui par défaut rollup veut cracher sous forme de fichiers séparés dans un répertoire.

Pour résoudre ce problème, il suffit de faire ce qui est indiqué dans l'erreur et définir l'option inlineDynamicImports, qui rassemblera tout dans un seul fichier. Nous pourrions modifier le fichier rollup.config.js dans la bibliothèque Pluggable Widgets, mais c'est une très mauvaise idée car il n'est pas maintenable et crée un code très difficile à lire et à déboguer. Heureusement Mendix dispose d'une fonctionnalité intégrée pour définir notre propre configuration de cumul.

Nous devons le faire créer un fichier appelé rollup.config.js dans le répertoire racine du widget. Nous ajoutons ensuite le code JS suivant pour modifier la façon dont notre widget est construit :

export default args => { const result = args.configDefaultConfig; console.warn ('Regroupement personnalisé') return result.map((config) => { config.output.inlineDynamicImports = true console.warn ("Définir les importations dynamiques") return config; }); };

Alors nous courons npm run build encore une fois, et j'obtiens une nouvelle erreur :

ERREUR FATALE : limite de tas atteinte Échec de l'allocation - Le tas JavaScript manque de mémoire

Il s'avère que le processus de construction nécessite plus de mémoire. Je peux mettre à jour cela en exécutant

export NODE_OPTIONS=--max_old_space_size=5120

Si nous reconstruisons, notre widget est désormais compilé.


Notre bundler peut nous aider à créer des fichiers uniques afin qu'ils puissent être facilement lus par le navigateur.

Rollup fait également quelque chose d'autre de très intelligent, appelé Arbre secouant:il s'agit de construire une image de la arbre de dépendance dans votre code et en incluant uniquement le code réellement nécessaire. Ceci est particulièrement utile lors de l'utilisation de grandes bibliothèques et évite de charger de grandes quantités de code inutilisé dans le navigateur. Ce changement d'arbre est l'un des facteurs clés Mendix j'ai fait le passage de webpack à rollup entre Mendix 8 et 9.

Les bundlers sont également livrés avec toute une série d'autres fonctionnalités, en roll-up, sous forme de plugins. La dernière chose que je veux faire dans ce blog est de couvrir un cas d'utilisation très courant pour avoir à modifier la configuration de votre rollup pour votre widget

Fournir les fichiers dont votre widget a besoin

ArcGIS fournit les fichiers nécessaires à la création de votre carte via un Réseau de distribution de contenu (CDN) . Cependant, il peut y avoir les cas où vous souhaitez conserver et gérez ces fichiers dans votre widget, peut-être en raison des paramètres de pare-feu de votre organisation. Heureusement, l'API Javascript d'ArcGIS rend cela possible.

La première chose à faire est de mettre à jour notre code, pour dire à l'API que nous serons gérer nos actifs localementPour ce faire, nous mettons simplement à jour notre composant conteneur pour qu'il contienne :

importer esriConfig depuis "@arcgis/core/config.js";
fonction d'exportation ArcGISMapBlog(props: ArcGISMapBlogContainerProps): ReactElement { esriConfig.assetsPath = "./widgets/mendix/arcgismapblog/assets"; ; }

Ensuite, nous devons Mise à jour nos Cumulatif à récupérer les fichiers que nous besoin de nos modules de nœuds et mettez-les dans notre widget mk.

Pour ce faire, nous pouvons utiliser le plugin de copie de cumul (il existe des plugins pour tout), il faut d'abord l'installer

npm i rollup-plugin-copy —save-dev 

Nous utilisons les —save-dev car il s'agit d'une dépendance requise uniquement lors du développement. Ensuite, nous mettons à jour notre rollup.config.js vers :

importer une copie depuis "rollup-plugin-copy" ; exporter les arguments par défaut => { const result = args.configDefaultConfig; console.warn ('Regroupement personnalisé') return result.map((config) => { config.output.inlineDynamicImports = true console.warn ("Définir les importations dynamiques") const plugins = config.plugins || [] config.plugins = [ ...plugins, copy({ cibles : { src : "node_modules/@arcgis/core/assets", dest : "dist/tmp/widgets/mendix/arcgismapblog" }]
}), ] retourner config; }); };

Ce prend les « actifs » dossier du package ArcGIS npm et le dépose dans notre dossier dist/tmp qui est ce qui est finalement zippé pour créer notre mpk. Ensuite, lorsque nous exécutons notre application, le contenu du widget mpk est servi à ./widgets/{votreNomOrganisation}/{votreNomWidget}.

Pour voir cela en action, exécutons la commande pour créer notre widget

construction d'exécution npm

Nous pouvons ensuite réexécuter notre application.

Si nous ouvrons notre répertoire de déploiement, nous pouvons voir que le widget sert le dossier des ressources, et si nous vérifions nos sources de page dans nos outils de développement Chrome, nous pouvons voir que le fichier d'assemblage Web ArcGIS est servi au navigateur pour garantir que notre carte fonctionne

Nous n'avons pas mis à jour notre CSS pour utiliser les fichiers locaux. Pour ce faire, nous mettons simplement à jour notre fichier comme suit :

@import "../assets/esri/themes/dark/main.css";

Simple… en quelque sorte…

Si vous utilisez le outils de widgets enfichables de 9.13.2 ou inférieur et vous utilisez Windows, alors votre les polices ne seront pas importées correctementLe code suivant est requis dans votre rollup.config.js pour corriger les importations :

importer postcssUrl depuis "postcss-url" ;
const cssUrlTransform = asset => { const outWidgetDirForwardSlash = outWidgetDir.replace(/\\/g, "/") return asset.url.startsWith(`${assetsDirName}/`) ? `${outWidgetDirForwardSlash}/${asset.url}` : asset.url; }
export default args => { const result = args.configDefaultConfig; console.warn ('Regroupement personnalisé') return result.map((config) => { config.output.inlineDynamicImports = true console.warn ("Définir les importations dynamiques") const plugins = config.plugins || [] config.plugins = [ ...plugins, postcssUrl (cssUrlTransform)
] retourner config; }); };

Ensuite, courez npm install postcss-url --save-dev Votre widget s'affichera désormais avec des icônes.


Et nous avons terminé!

L'API ArcGIS regorge de fonctionnalités étonnantes, je vous encourage à les explorer. Pour voir un excellent exemple de ce qu'elle peut faire, consultez le widget d'Ivo Sturm : GitHub – ivosturm/ArcGIS-React : Un nouveau widget ArcGIS amélioré basé sur ReactLe dépôt de mon widget ArcGIS se trouve ici : GitHub – joe-robertson-mx/arcGISMapBlog.

Choisissez votre langue