（メモ）webpackを使ってMapbox GL JS (又はMapLibre GL JS)のプラグインを使った地図をつくる

# 1．はじめに
先日、「[ベクトルタイル地図のウェブアプリを作るには（Mapbox GL JSやMapLibre GL JSのプラグインの実装）](https://qiita.com/T-ubu/items/d68c08f74fd96797c800)」という記事で、どうやってMapbox GL JSやMapLibre GL JSのプラグインを入れていくかを書きました。

プラグインのスクリプトのURLがすぐわかる場合はいいのですが、プラグインがnpmのパッケージになっている場合など、簡単にするために今回はwebpackをつかってmodules.jsファイル（あるいはbundle.js）を作る方法を紹介します。
（自分用のメモで時間をかけずに作成したので、読みずらかったらすみません。）

# 2．Mapbox GL JS やMapLibre GL JSでウェブ地図を作る基本的な方法

まず、準備体操として、以下の様な地図を作る場合を考えます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/a9e7de45-366f-4df2-8f85-53bd13c2e074.png)

一般的に、ベクトルタイル地図を作るときには、
　1)　ライブラリを読み込んで、
　2)　参照するスタイルを指定したあと、
　3)　addControlでいろいろな操作を加えていく、
ということをしています。

## 簡単なhtmlファイル
基本的でシンプルなhtmlファイルは以下の様な感じだと思います。（MapLibreの例ですが、Mapboxの場合は読み込むライブラリのURLを直して、mapglをmapboxglにしてあげればいい。）


```html: 簡単な地図のURLの例
<html>
<head>
<meta charset='utf-8' />
<title>Map Name</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src="https://ubukawa.github.io/bizan/maplibre-gl@2.2.0-pre.2/maplibre-gl.js"></script>
<link href="https://ubukawa.github.io/bizan/maplibre-gl@2.2.0-pre.2/maplibre-gl.css" rel="stylesheet" />
<style>
body { margin:0; padding:0; }
#map {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100%;
}
</style>
</head>
<body>
<div id='map'></div>
<script>
const mapgl = maplibregl
var map = new mapgl.Map({
  container: 'map', 
  hash: true, 
  style: 'https://ubukawa.github.io/bizan/std.json', // style file path
  center: [134.233884, 34.033731], // center [lng, lat]
  zoom: 8, // zoom level at loading
  pitch: 52,
  maxZoom: 4, // min zoom
  maxZoom: 16, // max zoom
  maxPitch: 85
});


//UI
map.addControl(new mapgl.NavigationControl(), 'bottom-right');
map.addControl(new mapgl.ScaleControl() );
map.addControl(new mapgl.TerrainControl({
  source: "terrainSource",
  exaggeration: 1
}) );

//debug
map.showTileBoundaries = true;
map.showCollisionBoxes = false;

</script>
 
</body>
</html>
```
（上のhtmlでつくった地図はこちら https://ubukawa.github.io/bizan/practice-01.html 。MapLibre（2.2.0-pre.2）の3D Terrainなので、メモリをたくさん消費します。）

## スクリプトを外部モジュール化したhtmlファイル
もちろんhtmlファイルにスクリプトを書くことも可能ですが、module.jsというようなファイルを別途つくって、htmlをシンプルにすることも出来ます。（スタイルファイルも外部につくれる。）
そんなhtmlファイルの例は以下の様なものです。

```html: simple map html (practice02)
<html>
<head>
<meta charset='utf-8' />
<title>Map Name</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<script src="https://ubukawa.github.io/bizan/maplibre-gl@2.2.0-pre.2/maplibre-gl.js"></script>
<link href="https://ubukawa.github.io/bizan/maplibre-gl@2.2.0-pre.2/maplibre-gl.css" rel="stylesheet" />
<link href="style.css" rel="stylesheet"  />
</head>
<body>
<div id='map'></div>
<script type="module" src="practice02-module.js"></script>
</body>
</html>
```

上記のhtmlが参照しているJavaScriptモジュールは以下の様な感じにすればいいです。
```javascript:practice02-module.js
const mapgl = maplibregl
var map = new mapgl.Map({
  container: 'map', 
  hash: true, 
  style: 'https://ubukawa.github.io/bizan/std.json', // style file path
  center: [134.233884, 34.033731], // center [lng, lat]
  zoom: 8, // zoom level at loading
  pitch: 52,
  maxZoom: 4, // min zoom
  maxZoom: 16, // max zoom
  maxPitch: 85
});


//UI
map.addControl(new mapgl.NavigationControl(), 'bottom-right');
map.addControl(new mapgl.ScaleControl() );
map.addControl(new mapgl.TerrainControl({
  source: "terrainSource",
  exaggeration: 1
}) );

//debug
map.showTileBoundaries = true;
map.showCollisionBoxes = false;
```

（上のhtmlとmodule.jsでつくった地図はこちら https://ubukawa.github.io/bizan/practice-02.html 。この前の地図と同じ見た目です。MapLibre（2.2.0-pre.2）の3D Terrainなので、メモリをたくさん消費します。）

モジュールを使うことで、プラグインをまとめられる可能性に気づかれるかと思います。



# 3．webpackを使ったプラグインの実装
## 3-1. webpackとは
webpackは、JavaScriptのファイルをまとめるモジュールバンドラーです。ウェブページのHTTPリクエストの数を減らしたりできますが、私の場合は必要なプラグインをまとめてくれるツールとして使って見ることにしました。(@JinIgarashi さんのライブラリでも使っています。)

## 3-2. レポジトリ作成、webpackや関係モジュールのインストール
レポジトリを作って、webpackや必要なモジュールのインストールを進めていきます。
webpackやweboack-cliはdependenciesを-Dのオプションでやる人が多いみたいです。
path, style-loader, css-loaderも後で使うので入れておきます。

```
npm init -y
npm install -D webpack
npm install -D webpack-cli
npm install --save path style-loader css-loader
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/3b6daed9-06ab-f467-dcff-4cdac8d12b30.png)
（↑）途中の画面です。

そして、mapbox-gl（あるいはmaplibre-gl）や関係するプラグインをインストールしておきます。
今回は、mapbox-glベースで、スタイルスイッチャー、watergisさんのexpoert、watergisさんのlegend、watergisさんのpopupを入れておきます。

```
npm install mapbox-gl mapbox-gl-style-switcher @watergis/mapbox-gl-export @watergis/mapbox-gl-legend @watergis/mapbox-gl-popup
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/2649f8bb-eea0-beaa-da38-ce6dd624c47a.png)
※上の画面では、いくつか足りていないモジュールがあったり（pathなど）、dependenciesが違うものがあったりします。


## 3-3. フォルダ作成、src/index.js作成
ソースファイルを作成するsrcディレクトリと、出力するファイルを入れるdocsディレクトリを作ります。普通はdistというディレクトリに出力する場合が多いですが、docsにモジュールとhtmlファイルをいれることでそのままGithub pageでホストするつもりです。

```
mkdir src
mkdir docs
```

そして、作ったsrcフォルダのなかで、index.jsファイルを以下の様に作ります。

```javascript:src/index.js
//import modules
import mapboxgl from 'mapbox-gl';
import 'mapbox-gl/dist/mapbox-gl.css';
import { MapboxStyleSwitcherControl } from 'mapbox-gl-style-switcher';
import 'mapbox-gl-style-switcher/styles.css';
// We will do the followings later.
//import MapboxPopupControl from '@watergis/mapbox-gl-popup';
//import '@watergis/mapbox-gl-popup/css/styles.css';
//import MapboxLegendControl from '@watergis/mapbox-gl-legend';
//import '@watergis/mapbox-gl-legend/css/styles.css';
//import { MapboxExportControl}  from '@watergis/mapbox-gl-export';
//import '@watergis/mapbox-gl-export/css/styles.css';


var mapgl = mapboxgl;  // if you change here to maplibregl, please make sure that you import the module as well.
mapgl.accessToken = 'hoge hoge'; //Use your accessToken
const map = new mapgl.Map({ //edit map info
  container: 'map',
  style: 'std.json', 
  center: [134.233884, 34.033731],
  hash: true,
  zoom: 8,
  maxZoom: 16
});

map.addControl(new mapgl.NavigationControl(), 'bottom-right');
map.addControl(new mapgl.ScaleControl({
    maxWidth: 200, unit: 'metric'
}) );


//style-switcher
const styles = [
    { 'title': 'Geology', 'uri': 'std.json' },
    { 'title': 'Photo', 'uri': 'std-photo.json' }
];
MapboxStyleSwitcherControl.DEFAULT_STYLE = styles[1].title;
map.addControl(new MapboxStyleSwitcherControl(styles), 'top-right');

```

## 3-4. webpackのconfig設定
出力先のフォルダや入力元のファイルを指定出来るように、webpack.config.jsを作っておきます。ここでpath、style-loader、css-loaderを使っています。


```js:webpack.config.js
const path = require('path'); //path module

module.exports = {
    mode: 'development', //use production at the end
    entry: './src/index.js',
    output: {
        path: path.resolve(__dirname, 'docs'),
		filename: 'bundle-01.js' //
	},
    module:{ // モジュールプロパティの中に
        rules:[
            { // ルールズを配列で指定
            test: /\.css$/, // 対象の拡張子を正規表現で指定。
            use:[ // どのローダーを使うのか（下から実行されていく）
                'style-loader', //cssをhtmlにstyleタグとして出力
                'css-loader'
            ]
        }
    ]
    }
  };
```

## 3-5. bunldeファイル作成
コンフィグ設定ができたので、以下の様にコマンドを実行してbundleファイルを出力します。コンフィグで指定したdocsファイルに出力されているはずです。

```
npx webpack --config webpack.config.js 
```

## 3-6. htmlファイルを用意
bundleファイルが出力されたdocsフォルダに、そのbundleファイルを参照しているhtmlファイルを作っておきます。

```html:docs/test01.html
<html>
<head>
<meta charset='utf-8' />
<title>Test01-Styleswitcher</title>
<meta name='viewport' content='initial-scale=1,maximum-scale=1,user-scalable=no' />
<style>
body { margin:0; padding:0; }
#map {
  position: absolute;
  top: 0;
  bottom: 0;
  width: 100%;
}
</style>
</head>
<body>
<script type="module" src="bundle-01.js"></script>
<div id="map"/>
<div id="filter"/>
</body>
</html>

```
下の図は作業の途中のイメージです。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/d9674661-ce33-c9f0-2f13-ed19ee7a5ee4.png)

docsの中にbundleファイルとhtmlファイルがあります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/57ed456d-dd12-b013-a4df-86a1f24db4cd.png)

## 3-7. 完成
これでプラグインがついた地図が表示されます。（下の例はレイヤースイッチャーだけです）
※なお、ここではGithubページでのホストについては説明しませんが、docsフォルダのファイルはGithubページとしてホストされています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/679143/ffb1b8af-19cc-a40c-b2df-394fa032e192.png)


# 謝辞
webpackを使うという方法は、@JinIgarashi さんのレポジトリを見なければ知ることがなかったと思います。この場を借りましてwatergisでの偉大な仕事に感謝します。
また、webpackの使いかたについて、いろいろな人のブログを見ませていただきました。ありがとうございました。

# 参考
* ベクトルタイル地図のウェブアプリを作るには（Mapbox GL JSやMapLibre GL JSのプラグインの実装）https://qiita.com/T-ubu/items/d68c08f74fd96797c800
* @JinIgarashi さんのレポジトリ mapboxgljs-boilerplate　https://github.com/watergis/mapboxgljs-boilerplate

* webpack関係 (accessed on 6 June 2022)
    * https://ics.media/entry/12140/
    * https://original-game.com/how-to-use-webpack-config-js/
    * https://qiita.com/shin_moto/items/d75f1694bccf2bb4302d