Getting Started

This section will show you how to create your MapStore standard downstream project and setup the development environment.

Note: ensure to install all the needed tools, see documentation for more info https://mapstore2.readthedocs.io/en/latest/developer-guide/developing/

The aim of the section is to have a MapStore project running locally:

Default homepage of the MapStore project

Create Project

Clone the MapStore2 repository in the local workspace to generate the downstream project and install all the dependencies

git clone https://github.com/geosolutions-it/MapStore2 -b <branch-version>
# e.g.
git clone https://github.com/geosolutions-it/MapStore2 -b v2022.01.00
cd MapStore2
npm install

Create the new project by running the following script from the MapStore2 folder

node ./createProject.js

the command line will prompt some information to create the project that needs to be filled as following (the default value, between parenthesis, will be used if you press enter)

Project Type (standard):
Project Name: MyMapStoreProject
Project Version (1.0.0):
Project Description (Project Name): A sample project for the training
Repository URL:
Output folder: ../MyMapStoreProject

This process will create the new project called MyMapStoreProject in the Output folder indicated (../MyMapStoreProject). Navigate to the new MyMapStoreProject folder to see the files created and start working with it.

cd ../MyMapStoreProject
npm install

Note

If initially, you have cloned the project from master tag, but you want to align mapstore to a specific release like v2022.01.00 , then we suggest to do also the following steps, otherwise the branch used during project creation is maintained in the submodule

To change the version of the MapStore2 submodule in the project to match the current stable branch

navigate inside the MapStore2 submodule

cd ./MapStore2

fetch all the available branches/tags from the origin remote

git fetch origin

switch to the stable branch

git checkout <branch-version or tag>
# e.g.
git checkout v2022.01.00

after the checkout we can return to the project folder

cd ..

Now we should add an initial commit to the repository because the hash of the commit will be used by the build script in next steps

git add -A
git commit -m "setup training project"

Note

Now you can remove the MapStore2 you cloned, that is not needed anymore.

Include print module

The Print plugin will work only if the plugin module is included correctly. Here the steps to add the backend printing module

modify the build.sh file to include the -Pprinting profile

#!/bin/bash
set -e

export GITREV=`git log -1 --format="%H"`
export VERSION="SNAPSHOT-$GITREV"

npm install
npm run compile
npm run lint

if [ $# -eq 0 ]
then
-  mvn clean install -Dmapstore2.version=$VERSION
+  mvn clean install -Dmapstore2.version=$VERSION -Pprinting
else
-  mvn clean install -Dmapstore2.version=$1
+  mvn clean install -Dmapstore2.version=$1 -Pprinting
fi

create a printing directory and copy all the default configuration and image files

mkdir -p backend/resources/printing/
cp -a MapStore2/java/printing/resources/geoserver/print/. backend/resources/printing/

update the copy resource execution inside the web/pom.xml file to target the new configuration folder instead of the MapStore submodule one

<execution>
   <id>printing</id>
   <phase>process-classes</phase>
   <goals>
      <goal>copy-resources</goal>
   </goals>
   <configuration>
      <outputDirectory>${basedir}/target/MyMapStoreProject/printing</outputDirectory>
      <encoding>UTF-8</encoding>
      <resources>
            <resource>
-              <directory>${basedir}/../MapStore2/java/printing/resources/geoserver/print</directory>
+              <directory>${basedir}/../backend/resources/printing</directory>
               <includes>
                  <include>*</include>
               </includes>
            </resource>
      </resources>
   </configuration>
</execution>

Initial Setup

Compile the first build to verify the project setup and to run the resulted .war file in a tomcat container.

run the script build.sh

./build.sh

The build process will generate a .war webapp file that can be deployed inside a tomcat container. Below two alternative for the tomcat setup.

Develop with a local tomcat container

Once the build process is completed rename the web/target/MyMapStoreProject.war file to mapstore.war, download tomcat and move the mapstore.war to the tomcat/webapps folder then start the tomcat container (see https://mapstore2.readthedocs.io/en/latest/quick-start/#war-file for more info). The MapStore application should run at:

http://localhost:8080/mapstore

see the official documentation for additional information https://mapstore.readthedocs.io/en/latest/quick-start/#war-file

Develop with cargo maven3 plugin

This setups allows to run a tomcat container locally with an npm command using the cargo-maven3-plugin plugin. This process will rebuild the war file on every run of the command so latest changes will be included in the deployed temporary .war.

ensure that the web/pom.xml file include the cargo plugin, if not add the snippet below

<plugin>
   <groupId>org.codehaus.cargo</groupId>
   <artifactId>cargo-maven3-plugin</artifactId>
   <configuration>
         <container>
            <containerId>tomcat8x</containerId>
            <zipUrlInstaller>
               <url>https://repo.maven.apache.org/maven2/org/apache/tomcat/tomcat/8.5.69/tomcat-8.5.69.zip</url>
            </zipUrlInstaller>
         </container>
         <configuration>
            <type>standalone</type>
            <home>
               ${project.build.directory}/apache-tomcat-${tomcat.version}
            </home>
            <properties>
               <cargo.servlet.port>8080</cargo.servlet.port>
               <cargo.logging>low</cargo.logging>
            </properties>
         </configuration>
         <deployables>
            <deployable>
               <groupId>${project.groupId}</groupId>
               <artifactId>${project.artifactId}</artifactId>
               <type>war</type>
               <properties>
                     <context>/mapstore</context>
               </properties>
            </deployable>
         </deployables>
   </configuration>
</plugin>

edit the package.json file of the project and include following script to run correctly the backend

{
   ...
   "scripts": {
+       "build-backend": "mvn clean install -Pprinting",
+       "backend": "npm run build-backend && mvn cargo:run -f ./web/pom.xml",
         ...
   },
   ...
}

use the backend script to start a local instance of the compiled mapstore.war

npm run backend

The MapStore application should run at:

http://localhost:8080/mapstore

Run development environment locally

Now that we have a local instance of the MapStore project running locally we could configure the webpack dev server to target the local environment instead the demo one. Then we will use the dev environment to test our changes and customization on the MapStore project

add the proxy paths to the webpack.config.js file

const path = require("path");

const themeEntries = require('./MapStore2/build/themes.js').themeEntries;
const extractThemesPlugin = require('./MapStore2/build/themes.js').extractThemesPlugin;
const ModuleFederationPlugin = require('./MapStore2/build/moduleFederation').plugin;

module.exports = require('./MapStore2/build/buildConfig')(
   {
      'MyMapStoreProject': path.join(__dirname, "js", "app"),
      'MyMapStoreProject-embedded': path.join(__dirname, "js", "embedded"),
      'MyMapStoreProject-api': path.join(__dirname, "MapStore2", "web", "client", "product", "api"),
      'geostory-embedded': path.join(__dirname, "js", "geostoryEmbedded"),
      "dashboard-embedded": path.join(__dirname, "js", "dashboardEmbedded")
   },
   themeEntries,
   {
      base: __dirname,
      dist: path.join(__dirname, "dist"),
      framework: path.join(__dirname, "MapStore2", "web", "client"),
      code: [path.join(__dirname, "js"), path.join(__dirname, "MapStore2", "web", "client")]
   },
   [extractThemesPlugin, ModuleFederationPlugin],
   false,
   "dist/",
   '.MyMapStoreProject',
   [],
   {
      "@mapstore": path.resolve(__dirname, "MapStore2", "web", "client"),
      "@js": path.resolve(__dirname, "js")
   },
+  {
+     '/rest': {
+           target: "http://localhost:8080/mapstore"
+     },
+     '/pdf': {
+           target: "http://localhost:8080/mapstore"
+     },
+     '/mapstore/pdf': {
+           target: "http://localhost:8080"
+     },
+     '/proxy': {
+           target: "http://localhost:8080/mapstore"
+     }
+  }
);

alternatively it is possible to use an object as argument for the buildConfig function

const path = require("path");
const themeEntries = require('./MapStore2/build/themes.js').themeEntries;
const extractThemesPlugin = require('./MapStore2/build/themes.js').extractThemesPlugin;
const ModuleFederationPlugin = require('./MapStore2/build/moduleFederation').plugin;
module.exports = require('./MapStore2/build/buildConfig')({
   bundles: {
      'MyMapStoreProject': path.join(__dirname, "js", "app"),
      'MyMapStoreProject-embedded': path.join(__dirname, "js", "embedded"),
      'MyMapStoreProject-api': path.join(__dirname, "MapStore2", "web", "client", "product", "api"),
      'geostory-embedded': path.join(__dirname, "js", "geostoryEmbedded"),
      "dashboard-embedded": path.join(__dirname, "js", "dashboardEmbedded")
   },
   themeEntries,
   paths: {
      base: __dirname,
      dist: path.join(__dirname, "dist"),
      framework: path.join(__dirname, "MapStore2", "web", "client"),
      code: [path.join(__dirname, "js"), path.join(__dirname, "MapStore2", "web", "client")]
   },
   plugins: [extractThemesPlugin, ModuleFederationPlugin],
   prod: false,
   publicPath:"dist/",
   cssPrefix: '.MyMapStoreProject',
   prodPlugins: [],
   alias: {
      "@mapstore": path.resolve(__dirname, "MapStore2", "web", "client"),
      "@js": path.resolve(__dirname, "js")
   },
   proxy: {
      '/rest': {
            target: "http://localhost:8080/mapstore"
      },
      '/pdf': {
            target: "http://localhost:8080/mapstore"
      },
      '/mapstore/pdf': {
            target: "http://localhost:8080"
      },
      '/proxy': {
            target: "http://localhost:8080/mapstore"
      }
   }
});

Note

buildConfig is a utility function that creates webpack configurations for Webpack, including the default devServer settings. It is used by build/webpack.config.js and build/prod-webpack.config.js, that are the configuration files used by the dev and production build for webpack. You can modify the proxy by adding a last parameter to the call to buildConfig included i the webpack file

start the dev environment

npm start

The dev environment runs at:

http://localhost:8081/?debug=true#/

debug=true allows to enable debug mode and will enable redux dev tools to be used from the dev tools (F12) of the browser if you have installed it as extension

MapStore2 submodule update

Every project generated with createProject.js provides a MapStore2 submodule folder that has a reference to a specific commit or branch of mapstore. The submodule is used by the project similarly to a node_modules packages with the difference to be able to apply changes to the submodule and send fixes to the MapStore2 repository/fork where needed. This setup allows to switch to a new version of MapStore2 by following these steps:

navigate to the MapStore2 folder

cd ./MapStore2

fetch the origin to get all the updated branches/commits

git fetch

checkout to a specific branch/commit

git checkout origin/branch

Now the MapStore2 submodule is updated to a specific branch and the project will use it as new package. It could be necessary to check migration guideline after switching to new branch to ensure a working project:

Best practices

The project could have some misalignment with the default MapStore configuration in particular when migrating to new versions. Before to move on with next steps we suggests steps to check everything is aligned:

  • remove the MyMapStoreProject/package-lock.json and MyMapStoreProject/node_modules and install the packages again. This is needed when updating the version of the MapStore submodule
  • compare MyMapStoreProject/package.json with MyMapStoreProject/MapStore2/package.json in particular the devDependencies
  • compare MyMapStoreProject/web/pom.xml with MyMapStoreProject/MapStore2/product/web/pom.xml
  • compare MyMapStoreProject/configs/localConfig.json with MyMapStoreProject/MapStore2/web/client/configs/localConfig.json if it has been added to the project

The list above shows the most common checks but based on the complexity of the project customization we could have additional files to compare.