【问题标题】:Leaflet with Webpack in Rails 6. L.timeline is not a functionRails 6 中带有 Webpack 的传单。L.timeline 不是函数
【发布时间】:2024-01-12 03:00:01
【问题描述】:

这看起来就像@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 和控制台中工作的传单宝石

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

// https://*.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"
  }
}

【问题讨论】:

  • 您似乎没有在任何地方使用过import 'leaflet.timeline'
  • 另外,请发布您的package.json 文件。
  • import 'leaflet' import "leaflet.timeline" 相同的错误L.timeline is not a function 将 `package.json 添加到 OP。谢谢。

标签: ruby-on-rails webpack leaflet ruby-on-rails-6 webpacker


【解决方案1】:

您的设置存在一些问题:

  1. 'leaflet.timeline' 插件假定传单模块可用作全局变量 'L'。插件的源代码表明这是真的(在这篇文章的时候在 master 上):https://github.com/skeate/Leaflet.timeline/blob/b7a8406f5a9a66ccdbcaf73465baaedadec76d1f/src/Timeline.js#L1
  2. (我相信)您一次在页面上使用了多个入口点:'application.js''mapTwo.js'。 Rails 将入口点称为“包”,因此app/javascript/packs 中的所有内容都是 Webpack 的单独入口点。 Webpack 建议 每页 1 个入口点;如果没有额外的配置,一个页面上的多个入口点可能会导致令人惊讶的行为,尤其是在全局变量方面(参见 #1)。

进一步详细说明问题 2,以您当前的配置,Webpack 不知道您想在页面上使用两个入口点;它将应用程序包中的 Leaflet 模块的一个实例和 mapTwo 包中的 Leaflet 模块的另一个实例捆绑在一起。它将 Leaflet 模块捆绑在 mapTwo 中,因为您添加了 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,这是一种跨Webpack“块”共享模块的方式,在您的情况下,这意味着入口点、application.js 和mapTwo.js。这意味着,将现有代码与 Rails Webpack 文档中更详细描述的其他更改一起保存在单独的包中: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 组。

【讨论】:

  • 感谢您的详细回答,这很有帮助,因为我正在使用这个示例(在我尝试 webpack 之前有效)来查看是否可以在迁移到 OpenLayers 之前让 webpacker 为我工作,这似乎不是有宝石支持。我不再有错误(也没有任何错误),但页面还没有工作,所以可能会回来有更多问题。我似乎在 application.js 中使用 leafletleaflet.timeline 并从 environment.js 中删除 L: 'leaflet' 得到相同的结果,就像我对您的修复 #1 所做的那样。前者似乎是一种更直接的方法。这有缺点吗?
  • 不确定我是否在没有完整上下文的情况下遵循您的问题。如果我重申一下可能会有所帮助:如果您的应用程序很小,我推荐选项 2。如果您的应用程序很大并且您坚持使用多个包,请尝试选项 3。
  • 谢谢。小应用程序。我从 environment.js 中删除了 L: 'leaflet' 并将 leafletleaflet.timeline 留在了 application.js 中。看起来更简单。但我假设我现在遇到了 Javascript 问题。我会更仔细地查看回调。
  • 我将其标记为已解决,但由于问题发生了变化,我希望从那时起解决方案,所以我从 *.com/questions/59744187/… 重新开始。谢谢@rossta