Rails 中带有 Webpack 的 Leaflet 6. L.timeline 不是一个函数

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

这看起来就像@rossta 为 Gmaps 回答的问题,但我不理解这个问题并回答得足够好,无法使他的建议奏效。

错误是:Uncaught TypeError: L.timeline is not a function at Object.success (mapTwo.js:14) 第 14 行是 var timelineData = L.timeline(data_data, {。完整代码如下。

我删除了在 Rails 5.2 和控制台

中工作的传单 gem
yarn add leaflet
yarn add leaflet.timeline

和代码:

// 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

我尝试应用所提供的解决方案:

// 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
  }))

// 
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. 'leaflet.timeline' 插件假定传单模块可用作全局变量 'L'。插件的源代码显示这是真的(在 post 时在 master 上):https://github.com/skeate/Leaflet.timeline/blob/b7a8406f5a9a66ccdbcaf73465baaedadec76d1f/src/Timeline.js#L1
  2. (我相信)您一次在页面上使用了多个入口点:'application.js''mapTwo.js'。 Rails 调用入口点 "packs",因此 app/javascript/packs 中的所有内容都是 Webpack 的单独入口点。 Webpack 建议每页 1 个入口点 ;如果没有额外的配置,一个页面上的多个入口点可能会导致令人惊讶的行为,特别是关于全局变量(参见#1)。

为了进一步详细说明问题 2,根据您当前的配置,Webpack 不知道您要在页面上使用两个入口点;它在应用程序包中捆绑了 Leaflet 模块的一个实例,在 mapTwo 包中捆绑了 Leaflet 模块的另一个实例。它在 mapTwo 中捆绑了 Leaflet 模块,因为您添加了 ProvidePlugin 配置 L: 'leaflet',基本上,将 var L = require('leaflet') 添加到每个引用 L.

的模块

所以有一些可能的修复方法:

  1. 将您的 import 'leaflet.timeline' 移至 mapTwo.js 并从 application.js 中删除 import 'leaflet'。鉴于您的 ProvidePlugin 配置,您不需要 import 'leaflet'。这是解决 L.timeline is not a function 短期问题的最简单方法。它不会阻止您在页面上使用多个入口点时两次捆绑像 Leaflet 这样的模块,比如您是否需要在 application.js 依赖关系图中的某处添加 import 'leaflet'

  2. 不要分开你的背包;将所有现有代码合并到 'application.js' 的依赖关系图中。您可能需要将现有的 mapTwo 代码包装在回调中,即 document.addEventListener('DOMContentLoaded', callback)

  3. 使用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。您可能还需要在 DOMContentLoaded 侦听器中包装 mapTwo.js 代码,如 2.

最后,从您的配置中删除此代码;因为这是从另一个解决方案复制的,所以它不会为您的设置增加任何价值:

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

您也可以合并单独的 ProvidePlugin 组,也就是说,您不需要单独的 lodash 组。