83227


Rails 6 から JS が webpacker 管理になって  
ビューに onclick="..." でうめこんだJSが動いたり動かなかったりするので困っています

モジュールになっちゃうせいでグローバルコンテキストにないせいかと思うんですが

  1. window.xxx に代入する

  2. global.xxx に代入する

  3. config/webpack/environment.js の Provide Plugin にかく

の使い分けを教えて下さい

* * *

`onclick="Rails.fire(...)"` みたいなのをビューにうめこもうとすると  
2 が必要みたいです

参考：  
<https://stackoverflow.com/questions/6959481/rails-trying-to-submit-a-form-
onchange-of-dropdown/49643534>

jquery の導入では 3 を採用してるブログが多いんですが  
jquery + bootstrap を導入しようとすると 3 だけでは  
`onclick="$().modal()"` みたいなのが動かなくて 1 を行わないといけないようです  
この場合 2 でも動きませんでした

参考：  
<https://teratail.com/questions/279420>

1 はRailsとは関係なく JS 自体に定義されてるものなので全部 1 で統一したほうがいいのかなとも思ったんですが 2 や 3
を使うメリット何かあるんでしょうか


CC BY-SA 4.0
2021-10-15T11:16:37.317
83118
2021-10-23T05:39:14.207
2021-10-16T00:57:49.873
7347
question
javascript ruby-on-rails webpack
Rails + webpacker における global と window と config/webpack/environment.js の違い


それぞれについて「一体何をしているのか？」を理解しておく必要があります。

`window`や`global`は[
**グローバルオブジェクト**](https://developer.mozilla.org/ja/docs/Glossary/Global_object)というものです。歴史的な経緯でグローバルオブジェクトはJavaScriptの実装によって名前が異なっており、ブラウザでは`window`、Node.jsでは`global`を使っていました。これは混乱のもとなっていたため、最新のECMAScript(JavaScriptのベースとなる言語)の仕様では`globalThis`をグローバルオブジェクトとして使えるようになっています。(それぞれ使える名前は下記の表を参照してください。)

| window | global | globalThis  
---|---|---|---  
古いブラウザ(Internet Explorer,Chrome71未満,Edge79未満,Firefox65未満,Safari12.1未満) | ○ | ×
| ×  
古いNode.js(12未満) | × | ○ | ×  
新しいブラウザ(Chrome71以上,Edge79以上,Firefox65以上,Safari12.1以上) | ○ | × | ○  
新しいNode.js(12以上) | × | ○ | ○  
  
※ babelやcore-
jsの古いバージョンでは、ブラウザ環境でも`global`を使えるようにするpolyfillが含まれていたため、ブラウザで動作させるコードであっても、これらを使う場合、`global`を使うことができました。

Internet
Explorer(IE)を除けば、現在サポートされているバージョンで`globalThis`を使用できないモダンブラウザやNode.jsはありません。わざと古いバージョンを使うことや、IEに対応すると言うことが無ければ、`window`や`global`の代わりに`globalThis`を使った方が何も迷わなくても済むでしょう。

※ なお、babelやcore-jsの新しいバージョンでは`globalThis`のpolyfillが含まれています。

さて、JavaScirptでは、グローバルオブジェクトのプロパティがグローバル変数になります(逆に言うと、グローバル変数はグローバルオブジェクトのプロパティであるとも言えます。)。つまり、グローバルオブジェクトのプロパティとして代入することによって、どこでも使えるグローバル変数にしていると言うことです。例えば、以前と同じようにjQueryを`$`や`jQuery`でどこでも使いたいという場合は、次のように書いておけばよくなります。

[code]

    import jQuery from 'jquery';
    globalThis.jQuery = jQuery;
    globalThis.$ = jQuery;
    
[/code]

この方法はwebpackに限らず、モジュールとしてJavaScirptを使うときも使えます。ほとんどの場合は、こちらで問題ないと思われます。以前は、`gloablThis`の代わりに`window`(ブラウザ上で実行が前提)または`global`(Node.js、または、ブラウザの場合はpolyfillがつかわれることが前提)を使うしかなったと言うだけになります。

では、ProvidePluginはどういうときに使うのかと言うことです。ProvidePluginもグローバル変数としてライブラリを読み込むと言うだけで、結果はほとんど同じです。ですが、これは「ソースコード上にライブラリを書きたくない」や「ソースコードの記載に関係無く全体として使えるようにしておきたい」と言う場合に有用です。

webpackとかが無かった昔のJavaScriptの書き方としては、jQueryは別のscriptタグで読み込んでおいて、その後のJavaScriptはjQueryが読み込まれていることが前提で書くということしかできませんでした。今でもそのような書き方をしたいという場合があると思います。そういうときにProviderPluginの機能を使ってjQueryを読み込んでおけば、個々にjQueryの読み込む必要は無くなります。特にcore-
jsのようなpolyfillについては、IE対応をなくすことや将来対応ブラウザのバージョンを上げたとき、将来そのpolyfillのみ削除すると言う場合、JavaScriptのコードは変更せずに、webpackの設定だけの変更で対応できると言う利点があります。

言ってしまえば、昔ながらの

[code]

    <stript src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
    
[/code]

と書いていた代わりに、CDN経由では無く、できあがったコード側にjQueryを埋め込もうと思ったとき、ProviderPluginで対応すれば、もともとのコードは何も変更しなくても済みます。

ProviderPluginの難点は、JavaScriptのまとまったコードとは別の所にライブラリについての記載が出てきてしまうと言うことです。読み込むライブラリを変更しようとしたとき、どこで読み込んでいるのかわからないという事になる場合があります。

まとめると、polyfillであればProviderPluginの方がいいかと思いますが、一般的なライブラリは、そのライブラリがグローバルに存在することが前提だった場合を除いて、避けた方がいいでしょう。application.js上に`globalThis`に代入してあるほうが、コードを追いやすいからと言う単純な話ですが。グローバルオブジェクトにどの名前を使うかは、`globalThis`で問題ないでしょう。IEに対応したいという場合は、core-
js等のpolyfillが対応しているので、core-js等をProviderPluginに含めておけば良いとなります。

* * *

少し蛇足ですが、いずれの方法もグローバル変数に何かしら足されるため、グローバル変数の汚染があ問題になります。グローバル変数が名前衝突した場合、その解決が非常に難しくなります。ですので、現代的な書き方では、必要に迫られない限りグローバル変数はなるべく使わない方がいいというのがあります。例えば、jQUeryを使うJavaScriptのファイルにだけ、

[code]

    import jQuery from 'jquery';
    const $ = jQuery;
    
[/code]

と書いておいと、そこでだけ、jQueryを使うということです。これが、複数のファイルになっても、webpackの結合時に一つにまとめられるため、jQuery自体の読み込みが複数回になると言うことはありません。

では、onclickの所はどうするかですが、HTML上に直接コードを書く場合は、結局何かをグローバル変数にするしかありません。それよりは、クラスやIDで要素を取り出して、addEventListener等を使う方がビューとロジックの分離という所でよりよい方法だと思います。逆に、タグとスクリプトが非常に強く紐付いている場合は、React等を使って動的にDOMを生成していく形の方が、より良いコードになっていくのだと思います。いずれにしても、HTML上でonclick等を使う方法では、どこかで限界が来る可能性を考えておくべきではないでしょうか。


CC BY-SA 4.0
2021-10-23T05:39:14.207
83227
2021-10-23T05:39:14.207
7347
83118
answer