Search code examples
javascriptnode.jswebpackbrowserifyrequire

Bundle Leaflet for use in Browser


I would like to use leaflet to load a custom map on a simple local website.

Currently I'm using Node Js, Express, EJS (as template engine) but I can't seem to be able to use leaflet. I've tried also using browserify and importing the bundle.js script but still no luck.

Any idea on how I could do that?

//map.js

var map = L.map("map-panel");

var osmUrl = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
var osmAttrib = 'Map data © <a href="http://openstreetmap.org">OpenStreetMap</a> contributors';
var mapLayer = new L.TileLayer(osmUrl, {minZoom: 8, maxZoom: 20, attribution: osmAttrib });

map.addLayer(mapLayer).fitWorld();
//map.setView([location.lat, location.lon], 13);
<!DOCTYPE>
<html lang="en">
<head>
    <meta charset="utf-8"/>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <title>Map</title>
    <link rel="stylesheet" type="text/css" href="css/style.css"/>
    <link rel="stylesheet" href="./../node_modules/leaflet/dist/leaflet.css" />
</head> 

<body>
<div id="map-panel">
</div>
   <!--    <script src="bundle.js"></script> -->
    <script src="/js/map_panel.js"></script>
</body>
</html>

As per the import, I've tried both in app.js or map.js with var L = require('leaflet');

or in the controller var L = require('leaflet');

I used to get this ReferenceError: L is not defined. The line is referring to the first js line.

Now I tried with using browserify and I get "window is not defined" error. I was trying to follow this tutorial http://mappingandco.com/blog/leaflet-with-browserify-basic-tutorial/

Thanks for any help or suggestion!


Solution

  • You can't require() anything natively in the browser, but Browserify or Webpack will let you bundle modules in to your code so it can be run in a browser.

    You should write your JavaScript code with require statements, then build it to produce a JavaScript bundle that you deliver to the browser with the HTML. Every time you change your code, you'll need to rebuild, or add a watcher to your project and let the watcher run the rebuild. It's important to understand that it's bundle.js that gets called by the HTML, not app.js. The code you posted above hasn't been bundled and won't work for that reason.

    Also, the code you posted above doesn't seem to actually add anything visible except zoom controls to the map.

    Using the tutorial code, I've posted a working example below:

    directory structure

    project
      node_modules/
      app.js
      package.json
      index.html
      dist/
        bundle.js
        style.css
    

    package.json

    {
      "name": "leaf",
      "version": "1.0.0",
      "description": "",
      "main": "index.js",
      "scripts": {
        "test": "echo \"Error: no test specified\" && exit 1",
        "build": "browserify app.js -o dist/bundle.js"
      },
      "author": "",
      "license": "ISC",
      "devDependencies": {
        "browserify": "^16.2.0"
      },
      "dependencies": {
        "jquery": "^3.3.1",
        "leaflet": "^1.3.1"
      }
    }
    

    app.js

    // require modules
    var L = require('leaflet');
    var $ = require('jquery');
    // Create the map
    var map = L.map('map').setView([41.3921, 2.1705], 13);
    
    // Indicate leaflet the specific location of the images folder that it needs to render the page
    L.Icon.Default.imagePath = 'node_modules/leaflet/dist/images/'
    
    // Use OpenStreetMap tiles and attribution
    var osmTiles = 'http://{s}.tile.openstreetmap.org/{z}/{x}/{y}.png';
    var attribution = '© OpenStreetMap contributors';
    
    // Create the basemap and add it to the map
    L.tileLayer(osmTiles, {
      maxZoom: 18,
      attribution: attribution
    }).addTo(map);
    
    // Add some geojson from this URL
    var geojsonURL = 'http://mappingandco.github.io/geojsonDB/barcelona/neighbourhoods.geojson'
    
    $.getJSON(geojsonURL, function(neighbourhoods) {
      L.geoJson(neighbourhoods, {
        onEachFeature: function (feature, layer) {
          layer.bindPopup(feature.properties.NBarri);
        }
      }).addTo(map);
    });
    

    index.html

    <!DOCTYPE html>
    <html>
    <head>
        <meta charset="utf-8">
        <title>Leaflet with browserify template</title>
        <link rel="stylesheet" href="node_modules/leaflet/dist/leaflet.css" />
        <link rel="stylesheet" href="dist/style.css">
    </head>
    <body>
    <div id="map"></div>
        <script src="dist/bundle.js" charset="utf-8"></script>
    </body>
    </html>
    

    install and build

    npm install
    npm run build
    

    Then open the index.html file in your browser and you should see a map.