Leaflet with Webpack in Rails 6. L.timeline is not a function

只愿长相守 提交于 2020-01-16 08:43:08

问题


This looks just like the question @rossta answered for Gmaps, but I don't understand the problem and answer well enough to make his suggestion work.

The error is: Uncaught TypeError: L.timeline is not a function at Object.success (mapTwo.js:14) Line 14 is var timelineData = L.timeline(data_data, {. Complete code below.

I removed the leaflet gems that work in Rails 5.2 and in console

yarn add leaflet
yarn add leaflet.timeline

and code:

// app/javascript/packs/application.js
import "core-js/stable"
import "regenerator-runtime/runtime"
import '../stylesheets/application'
window.jQuery = $
window.$      = $
import 'leaflet'
import "leaflet.timeline"
require("@rails/ujs").start()
require("turbolinks").start()
require("@rails/activestorage").start()
require("trix")
require("@rails/actiontext")
require("jquery") 
import "bootstrap"
import 'bootstrap/dist/js/bootstrap'

document.addEventListener("turbolinks:load", () => {
  $('[data-toggle="tooltip"]').tooltip()
  $('[data-toggle="popover"]').popover()
})

<!-- map/index.html.erb -->
<div id="map_two"></div>
<%= javascript_pack_tag 'mapTwo' %> 


// javascript/packs/mapTwo.js  called from map/index.html.erb
console.log('Hello from /javascript/packs/mapTwo.js')
var mapVar = L.map("map_two", {
  center: [34.040951, -118.258579],
  zoom: 13
});
L.tileLayer('https://crores.s3.amazonaws.com/tiles/bkm/{z}/{x}/{y}.png').addTo(mapVar);
$.getJSON("map/line_data.geojson", function(data_data) {
  var timelineData = L.timeline(data_data, {
    style: function(data_data) {
      return {
        stroke: true,
        fillOpacity: 0.5
      }
    }, // end style: function(data_data)
    waitToUpdateMap: true,
    onEachFeature: function(data_data, layer) {
        layer.bindTooltip(data_data.properties.popup, {
          direction: 'top'
        });
      } // onEachFeature: 
  }); // end let timelineData = L.timeline
  var timelineControl = L.timelineSliderControl({
    enableKeyboardControls: true,
    steps: 100,
    start: 1885,
    end: 1928,
  });
  timelineControl.addTo(mapVar);
  timelineData.addTo(mapVar);
  timelineControl.addTimelines(timelineData);
}); //  end $.getJSON

My attempt at applying the solution offered:

// config/webpack/environment.js
const { environment } = require('@rails/webpacker')
const webpack = require('webpack')

environment.plugins.append('Provide',
  new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    jquery: 'jquery',
    // 'window.Jquery': 'jquery', 
    Popper: ['popper.js' ,'default'],
    L: 'leaflet' // didn't help
  }))

// https://stackoverflow.com/questions/59042437/gmaps-with-rails-6-webpack
environment.loaders.append('leaflet', {
  test: /map/,
  use: [
    {
      loader: 'imports-loader',
      options: 'this=>window',
    },
  ],
})

environment.plugins.append(
  'lodash',
  new webpack.ProvidePlugin({
    _: 'lodash',
  })
)

module.exports = environment

package.json

{
  "license": "ISC",
  "main": "application.js",
  "dependencies": {
    "@rails/actiontext": "^6.0.0",
    "@rails/ujs": "^6.0.1",
    "@rails/webpacker": "4.2.2",
    "bootstrap": "^4.4.1",
    "core-js": "^3.5.0",
    "imports-loader": "^0.8.0",
    "jquery": "^3.4.1",
    "jqueryui": "^1.11.1",
    "leaflet": "^1.6.0",
    "leaflet.timeline": "^1.2.1",
    "lodash": "^4.17.15",
    "mapbox": "^1.0.0-beta10",
    "ol": "^6.1.1",
    "ol-ext": "^3.1.7",
    "ol-layerswitcher": "^3.4.0",
    "ol-loupe": "^1.0.1",
    "popper.js": "^1.16.0",
    "regenerator-runtime": "^0.13.3",
    "trix": "^1.0.0",
    "turbolinks": "^5.2.0",
    "webpack": "^4.41.2"
  },
  "devDependencies": {
    "webpack-dev-server": "^3.10.0"
  }
}

回答1:


There are a few issues with your setup:

  1. The 'leaflet.timeline' plugin assumes the leaflet module is available as the global variable 'L'. The source code of the plugin shows this to be true (on master at the time of this post): https://github.com/skeate/Leaflet.timeline/blob/b7a8406f5a9a66ccdbcaf73465baaedadec76d1f/src/Timeline.js#L1
  2. (I believe) You are using more than one entry point on the page at one time: 'application.js' and 'mapTwo.js'. Rails calls entry points "packs", so everything in app/javascript/packs is a separate entry point to Webpack. Webpack recommends 1 entry point per page; without extra configuration, multiple entry points on one page can lead to surprising behavior, especially with regards to global variables (see #1).

To elaborate further on issue 2, with your current configuration, Webpack doesn't know you want to use two entry points on the page; it bundles one instance of the Leaflet module in the application pack and another instance of the Leaflet module in the mapTwo pack. It bundles the Leaflet module in mapTwo because you added the ProvidePlugin configuration L: 'leaflet', which says, basically, add var L = require('leaflet') to every module that references L.

So there are a few possible fixes:

  1. Move your import 'leaflet.timeline' into mapTwo.js and remove import 'leaflet' from application.js. You don't need import 'leaflet' given your ProvidePlugin config. This is the easiest fix to address the short-term issue of L.timeline is not a function. It does not prevent you from bundling modules like Leaflet twice when using multiple entry points on the page, say if you were to need to add import 'leaflet' somewhere in the application.js dependency graph. OR

  2. Don't split up your packs; consolidate all your existing code in the dependency graph of 'application.js'. You may need to wrap your existing mapTwo code in callback, i.e., document.addEventListener('DOMContentLoaded', callback). OR

  3. Use the SplitChunksPlugin, which is a way of sharing modules across Webpack "chunks" which, in your case, means the entry points, application.js and mapTwo.js. This means, keep your existing code in separate packs along with additional changes described in more detail in the Rails Webpack docs: https://github.com/rails/webpacker/blob/master/docs/webpack.md#add-splitchunks-webpack-v4. You may need to also wrap mapTwo.js code in the DOMContentLoaded listener, as in 2.

Finally, remove this code from your configuration; as this was copied from another solution, it's not adding any value to your setup:

environment.loaders.append('leaflet', {
  test: /map/, 
  use: [
    {
      loader: 'imports-loader',
      options: 'this=>window',
    },
  ],
})

You can also likely combine the separate ProvidePlugin groups, i.e., you don't need a separate one for lodash.



来源:https://stackoverflow.com/questions/59670743/leaflet-with-webpack-in-rails-6-l-timeline-is-not-a-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!