83547
[jquery-ui](https://jqueryui.com/download/) と
[jquery.validationEngine](https://github.com/posabsolute/jQuery-Validation-
Engine) を同時に使いたいのですがうまくいきません

どちらも $ っていう変数に対してメソッドを追加してるんだと思うんですが片方を使うともう片方が使えなくなります

* * *

jquery-ui は公式サイトダウンロードビルダーから zip ダウンロードしたものを  
app/javascript/vendor/jquery-ui  
に展開

jquery.validationEngine は  
app/javascript/vendor/jquery.validationEngine  
に clone してあります

* * *

**config/webpack/environment.js をデフォルトのまま**  
application.js に

```

    globalThis.jQuery = globalThis.$ = require('jquery');
    import '../vendor/jquery-ui/jquery-ui.min.js'
    import '../vendor/jquery-ui/jquery-ui.min.css'
    import '../vendor/jquery-ui/jquery-ui.theme.min.css'
    
```

とかくと $.slider() が動きますが

```

    import '../vendor/jQuery-Validation-Engine/js/jquery.validationEngine';
    
```

を追加すると

```

    jquery.validationEngine.js:2163 Uncaught ReferenceError: jQuery is not defined
        at Object../app/javascript/vendor/jQuery-Validation-Engine/js/jquery.validationEngine.js (jquery.validationEngine.js:2163)
        at __webpack_require__ (bootstrap:19)
        at Module../app/javascript/packs/application.js (application.js:1)
        at __webpack_require__ (bootstrap:19)
        at bootstrap:83
        at bootstrap:83
    
```

と jQuery が見つからないというエラーになります

globalThis.jQuery = に代入しているにもかかわらず  
なぜそのあとの import で jQuery がみつからなくなるんでしょうか

* * *

一方で config/webpack/environment.js に

```

    environment.plugins.prepend('Provide',
        new webpack.ProvidePlugin({
            $: 'jquery/src/jquery',
            jQuery: 'jquery/src/jquery'
        })
    );
    
```

をかくと application.js で

```

    import '../vendor/jQuery-Validation-Engine/js/jquery.validationEngine';
    
```

をしてもエラーが出なくなるんですが

```

    import '../vendor/jquery-ui/jquery-ui.min.js'
    import '../vendor/jquery-ui/jquery-ui.min.css'
    
```

もかいてるにもかかわらず $.slider(); で

```

    Uncaught TypeError: $(...).slider is not a function
    
```

となってしまいます

* * *

**追記:**

[Rails6 webpacker から bootstrap js
を使う方法](https://ja.stackoverflow.com/questions/83006/rails6-webpacker-%e3%81%8b%e3%82%89-bootstrap-
js-%e3%82%92%e4%bd%bf%e3%81%86%e6%96%b9%e6%b3%95)

ProvidePlugin を記述するとこちらで教えていただいた bootstrap の JS も  
jquery-ui に関係なく （jquery-ui関連のインポートを全部消しても)

`$(...).modal is not a function`

で動かなくなってしまいました

* * *

[Rails + webpacker における global と window と config/webpack/environment.js
の違い](https://ja.stackoverflow.com/questions/83118/rails-
webpacker-%e3%81%ab%e3%81%8a%e3%81%91%e3%82%8b-global-%e3%81%a8-window-%e3%81%a8-config-
webpack-environment-js-%e3%81%ae%e9%81%95%e3%81%84)

最近こちらの質問をみかけたんですが  
globalThis と ProvidePlugin でなぜ挙動がかわってしまうんでしょうか

ProvidePlugin があまり理解できてないなくてこれまではなしで動いていたので  
できれば ProvidePlugin を使わずに globalThis だけで  
jQuery-Validation-Engine を動かしたいのですが方法はないでしょうか

* * *

今の application.js がこんな感じで  
ここに validation engine を追加しようとしました

```

    import Rails from '@rails/ujs'
    globalThis.Rails = Rails
    Rails.start()
    
    require("turbolinks").start()
    require("@rails/activestorage").start()
    require("channels")
    
    import * as jquery from 'jquery'
    globalThis.jQuery = globalThis.$ = jquery;
    
    import * as bootstrap from 'bootstrap'
    globalThis.bootstrap = bootstrap
    
    // // jQuery-Validation-Engine
    // import '../vendor/jQuery-Validation-Engine/js/jquery.validationEngine';
    // // require('../vendor/jQuery-Validation-Engine/js/languages/jquery.validationEngine-ja');
    // import '../vendor/jQuery-Validation-Engine/js/languages/jquery.validationEngine-en';
    
    /* Validate form */
    // $(document).on('turbolinks:load', function () {
    //   $("form").validationEngine();
    // });
    
    import '@fortawesome/fontawesome-free/js/all';
    
    import '../vendor/jquery-ui/jquery-ui.min.js'
    import '../vendor/jquery-ui/jquery-ui.min.css'
    import '../vendor/jquery-ui/jquery-ui.theme.min.css'
    
    import * as moment from 'moment'
    globalThis.moment = moment
    
    import '../stylesheets/application.scss';
    
```
CC BY-SA 4.0
2021-11-09T07:01:25.300
83510
2021-11-11T09:49:24.040
2021-11-09T10:00:41.707
question
javascript jquery webpack
webpack での jquery の $ 変数の扱いについて
コードの順番に関係無く、`import`や`require`でモジュールのファイルを読み込む処理が最初に実行され、その後に地の文にある処理が実行されるからです。

どういうことかというと、`import '../vendor/jQuery-Validation-
Engine/js/jquery.validationEngine';`の方が、`globalThis.jQuery = globalThis.$ =
jquery;`での代入の処理より前に実行されてしまいます。そのため、jquery.validationEngineの中身が実行される時点ではグローバル変数`jQuery`が用意されておらず、変数が見つからないとして、実行に失敗するとなっています。逆に、ProvidePluginがうまくいくのは、`import`の処理の前にProvidePluginの処理が実行されるので、グローバル変数`jQuery`が用意されているというわけです。

jQuery UIが何故うまくいくというと、jQuery
UIのコードにはAMDに対応する部分があり、webpackがそれを考慮して、jQueryがモジュールとして読み込まれていれば、そのjQueryに対して設定するという動きになっているからです。(詳しくは調べていませんが、ProvidePluginだとおかしくなるのは、このあたりが原因かもしれません。ProviderPluginで読み込まれたjQueryとimportされたjQueryが別の物扱いで、追加のメソッドが設定されないという物です。bootstrapもjQueryをimportすると言った動作だったはずなので、そちらもそれが原因でしょう。)

では、どうすればいいのかというと、ファイルを分けます。下記内容のjquery-validation-engine.jsを用意します。

```

    import '../vendor/jQuery-Validation-Engine/js/jquery.validationEngine';
    
```

これをapplicationの後に読む込むようにします。application.html.erbは次のようになるでしょう。

```

    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'jquery-validation-engine', 'data-turbolinks-track': 'reload' %>
    
```

これで、うまくいくはずです。

* * *

この方法には注意事項があります。まもなく正式リリースされるwebpacker
6系では複数のJavaScirptに分割することをサポートしていません。全てのJavaScriptは`application.js`一つにまとめておく必要があり、この方法は使えなくなります。

一つのファイルにまとめるにはどうするのかですが、[Upgrading from Webpacker 5 to
6](https://github.com/rails/webpacker/blob/master/docs/v6_upgrade.md)に次のヒントが書いてありました。

> If you expose jquery globally with `expose-loader`, by using `import $ from
> "expose-loader?exposes=$,jQuery!jquery"` in your
> `app/javascript/application.js`, pass the option `efer: false` to your
> `javascript_pack_tag`.

この方法はwebpacker 5系でも使えます。実際に使ってみましょう。まずは、`yarn add expose-loader@1`として、expose-
loaderをインストールします(webpacker 5系はwebpack 4系を使用するため、expose-
loderは1系を使う必要があり、`@1`を付けるようにしてください)。そして、jQueryの部分を次のように書きます。(最新のexpose-loader
3系とは書き方が異なるので注意してください。)

```

    import $ from "expose-loader?exposes[]=$&exposes[]=jQuery!jquery";
    
```

こうすると、jQueryの`import`処理と同時にexpose-
loaderがグローバル変数にセットしてくれるようです。`import`処理同士は順番に実行されるため、jquery.validationEngineが読み込まれるときには、グローバル変数`jQuery`が存在することになりうまくいくという仕組みです。

* * *

そもそもの問題はjQuery.validationEngineが現代的なモジュールベースに対応した物としてかかれていないと言うことです。jQuery
UIの開発も終了しており、Bootstrapも5系からjQuery依存が無くなったと言うこともありますので、将来的にはjQueryには依存しない方向にシフトしていった方がいいかもしれません。
CC BY-SA 4.0
2021-11-10T13:00:01.027
83547
2021-11-11T09:49:24.040
2021-11-11T09:49:24.040
7347
7347
83510
answer