Methods like modal() not working if Bootstrap loaded with Webpack (Rails)

安稳与你 提交于 2020-12-12 03:19:10

问题


In my Rails 5 app, if I load Bootstrap 4 using a header <script> tag from a CDN, everything works fine. But when I install Bootstrap (and its dependencies) to node_modules, and serve it with Webpack, it mostly still works... but the jQuery methods Bootstrap is supposed to add like $(foo).modal() or $(bar).popover() give errors in the JavaScript console:

Uncaught TypeError: $(...).modal is not a function
Uncaught TypeError: $(...).popover is not a function

There are several other StackOverflow questions about errors like that, but none of the solutions listed there work for me. The most common cause seems to be jQuery getting included twice, but I'm pretty sure I'm not doing that; when I remove the jQuery import from app/javascript/packs/application.js (see below), then all of jQuery stops working. jQuery is not in my Gemfile as a gem, and the word "jquery" only appears in the files I've shown below.

I'm loading in the correct order (see below; jQuery and Popper before Bootstrap). I'm using a document-ready wrapper around the method calls (see below), so I'm not calling them too soon. The Bootstrap CSS loads fine, and DOM elements using data-toggle="modal" display the modal correctly:

<button type="button" class="btn btn-primary" data-toggle="modal" data-target="#exampleModal">
  Show Modal
</button>
<div class="modal fade" id="exampleModal" tabindex="-1" role="dialog" aria-labelledby="exampleModalLabel" aria-hidden="true">
  <div class="modal-dialog" role="document">
    <div class="modal-content">
      <!- ... ->
    </div>
  </div>
</div>

...it's only when methods like $(foo).modal() etc. are called in JS code that I get the error:

<script>
  $(function () {
    $('#exampleModal').on('shown.bs.modal', function (e) {
      console.log('modal shown!');
    });
    $('#otherModalButton').click(function (e) {
      e.preventDefault();
      console.log('clicked!');
      $('#exampleModal').modal('show');  // <- "not a function" error
      return false;
    });
  });
</script>

My setup:

Node.js v10.20.1
ruby 2.5.8p224 (2020-03-31 revision 67882) [x86_64-linux]
Rails 5.2.4.2

package.json:    "@rails/webpacker": "4.2.2",
package.json:    "bootstrap": "4.4.1",
package.json:    "jquery": "3.4.1",
package.json:    "popper.js": "1.16.1"
package.json:    "webpack-dev-server": "^3.11.0"
// config/webpack/development.js
process.env.NODE_ENV = process.env.NODE_ENV || 'development'
const environment = require('./environment')
module.exports = environment.toWebpackConfig()
// config/webpack/environment.js
const { environment } = require('@rails/webpacker')
const webpack = require('webpack')
environment.plugins.append(
  'Provide',
  new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',  // taking this out doesn't fix it
    Popper: ['popper.js', 'default']
  })
)
module.exports = environment
<!DOCTYPE html>
<!-- app/views/layouts/application.html.erb -->
<html>
  <head>
    [...]
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>
    <%= javascript_pack_tag    'application' %>
    <%# if I load with these two lines (instead of in app/javascript/packs/application.js), it all works: %>
    <%# javascript_include_tag 'https://cdnjs.cloudflare.com/ajax/libs/popper.js/1.16.1/umd/popper.min.js' %>
    <%# javascript_include_tag 'https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.4.1/js/bootstrap.min.js' %>
  </head>
  <body>
    <%= yield %>
  </body>
</html>
// app/javascript/packs/application.js
import 'jquery/src/jquery'
import 'popper.js/dist/esm/popper'
import 'bootstrap/dist/js/bootstrap'
import '../stylesheets/application'
// app/javascript/stylesheets/application.scss
@import "~bootstrap/scss/bootstrap";

I've manually reviewed the JS pack that webpack-dev-server is producing; I can see Bootstrap in there. The Webpack output in the console shows the pack successfully compiled with no errors. I've tried this on both Chrome (ChromeOS and MacOS) and Firefox (MacOS).

Any ideas for what I can try?


回答1:


The problem is

new webpack.ProvidePlugin({
 $: 'jquery',
 jQuery: 'jquery',  // taking this out doesn't fix it
...

and require "jquery" caused jquery to be loaded twice. if you check the compiled application.js, you may see it required "./node_modules/jquery/dist/jquery.js", and then required all js files inside "./node_modules/jquery/" one by one, try it, search ./node_modules/jquery/

As you can see in the minimap, so many results!

My Solution

I solved it by removing this from enviroments.js

 $: 'jquery',
 jQuery: 'jquery',  

and in applictions.js change require "jquery" to

import JQuery from 'jquery';
window.$ = window.JQuery = JQuery;


来源:https://stackoverflow.com/questions/61705296/methods-like-modal-not-working-if-bootstrap-loaded-with-webpack-rails

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