JS API with webpack

In the modern JS world, using the global library in your code is inconvenient. But the Javascript API is distributed only as the JS script and connected as the mappable global variable:

<head>
  <script src="https://js.api.mappable.world/v3/?apikey=YOUR_API_KEY&lang=en_US"></script>
</head>
<script>
  mappable.ready.then(() => {
    const {MMaps} = mappable;
    new MMaps({});
  });
</script>

Caution.

The script connects only the light loader. The API is fully available only after the mappable.ready is resolved.

Developers are used to working with npm packages. When working with the API in the code, the following method is convenient:

import {MMaps} from 'mappable';

new MMaps({});

You can use the webpack for it. If you configure it the right way, you can work with the API like with an ordinary JS npm package.

Below you will find methods to configure the webpack using the externals options for working with the API.

Method 1

The Javascript API is already connected on your page, which means the mappable global variable is available:

<head>
  <script src="https://js.api.mappable.world/v3/?apikey=YOUR_API_KEY&lang=en_US"></script>
</head>

Configure the following setting:

{
  "externals": {
    "mappable": "mappable"
  }
}

After this, you can perform the import:

import * as mappable from 'mappable';

mappable.ready.then(() => {
  const {MMaps} = mappable;
  new MMaps({});
});

Method 2

This method is very similar to method 1, but the API is connected by the webpack:

{
  "externalsType": "script",
  "externals": {
    "mappable": ["https://js.api.mappable.world/v3/?apikey=YOUR_API_KEY&lang=en_US", "mappable"]
  }
}

In the code, you also have to use mappable.ready:

import * as mappable from 'mappable';

mappable.ready.then(() => {
  const {MMaps} = mappable;
  new MMaps({});
});

Caution.

Using method 1 and method 2, you import the API that is not yet ready: you need to wait until the mappable.ready promise is resolved.

Method 3

As mentioned above, when working with an ordinary package, the code looks like this:

import {MMaps} from 'mappable';

new MMaps({});

To use the code that looks like this, you need to process the promise before the import. To do this, configure the following settings:

const config = {
  //...
  externalsType: 'script',
  externals: {
    mappable: [
      `promise new Promise((resolve) => {
          if (typeof mappable !== 'undefined') {
            return mappable.ready.then(() => resolve(mappable));
          }

          const script = document.createElement('script');
          script.src = "https://js.api.mappable.world/v3/?apikey=YOUR_API_KEY&lang=en_US";
          script.onload = () => {
            mappable.ready.then(() => resolve(mappable));
          };
          document.body.appendChild(script);
        })`
    ]
  }
};

In the code above, we connect the API loader, wait until it is fully loaded, and pass fully loaded modules to import.

In this case, you can use in your code the API modules that are ready for work.

Comparing the methods

Method 3 has an obvious drawback: no code is run in your module until the Javascript API fully loads.

For example, you can't show a loading animation or other components:

import * as mappable from 'mappable';
const reactify = mappable.reactify.bindTo(React, ReactDOM);
const {MMap} = reactify.module(mappable);

// ...

function App() {
  return (
    <div>
      <button>Button</button>
      <MMap />
    </div>
  );
}

Using method 1 or method 2, you can avoid this:

import * as mappable from 'mappable';
import React, {useState, useEffect} from 'react';

// ...

function Map() {
  const [loaded, setLoaded] = useState(true);

  useEffect(() => {
    mappable.ready.then(() => setLoaded(false));
  }, []);

  if (loaded) {
    return <div>Loading...</div>;
  }

  const reactify = mappable.reactify.bindTo(React, ReactDOM);
  const {MMap} = reactify.module(mappable);

  return <MMap />;
}

function App() {
  return (
    <div>
      <button>Button</button>
      <Map />
    </div>
  );
}

Example of a ready build