Rails 7(7.0.2.3)Itmotmap jQuery未定义

发布于 2025-01-21 07:45:16 字数 2066 浏览 5 评论 0原文

我在Rails 7(7.0.2.3)中安装JQuery尽可能多的帮助。我想在我的视图中使用脚本标签,但我似乎无法将其导出到全球可用的位置,嗯...在任何地方。

确保inoctimmap易于操纵与安装和映射软件包有关。布拉沃。之后,整个文档都崩溃了,一般的雾笼云云笼罩着使用JS软件包的新方法。环顾四周,有很多混乱。

也就是说,我该如何添加此或类似的内容:

import jquery from "jquery"
window.jQuery = jquery;
window.$ = jquery;

将其添加到application.js或任何地方以使这些全局功能工作(例如$)。我希望$可以在我所有的观点中使用。

至于我所做的:

./bin/importmap pin jquery --download

给我importmap行:

pin "jquery" # @3.6.0

好的。然后查看ImportMap JSON:

{
  "imports": {
    "application": "/assets/application-37a24e4747cc3cde854cbbd628efbdf8f909f7b031a9ec5d22c5052b06207eb8.js",
    "@hotwired/turbo-rails": "/assets/turbo.min-96cbf52c71021ba210235aaeec4720012d2c1df7d2dab3770cfa49eea3bb09da.js",
    "@hotwired/stimulus": "/assets/stimulus.min-900648768bd96f3faeba359cf33c1bd01ca424ca4d2d05f36a5d8345112ae93c.js",
    "@hotwired/stimulus-loading": "/assets/stimulus-loading-1fc59770fb1654500044afd3f5f6d7d00800e5be36746d55b94a2963a7a228aa.js",
    "jquery": "/assets/jquery-498b35766beec7b412bab57a5acbe41761daa65aa7090857db4e973fa88a5623.js",
    "controllers/application": "/assets/controllers/application-368d98631bccbf2349e0d4f8269afb3fe9625118341966de054759d96ea86c7e.js",
    "controllers/hello_controller": "/assets/controllers/hello_controller-549135e8e7c683a538c3d6d517339ba470fcfb79d62f738a0a089ba41851a554.js",
    "controllers": "/assets/controllers/index-7a8fc081f7e391bd7b6fba95a75e36f88ba813da2c4c8787adad248afb9a0a06.js"
  }
}

ding。看起来它在那里。然后在application.html.erb中一个简单的脚本标签:

<script type="text/javascript" charset="utf-8">
        $(document).ready(function (){
            console.log('jQuery working.');
        })
</script>

失败。检查员说:

(index):41 Uncaught ReferenceError: $ is not defined

这确实是非常基础的,并且非常烦人,不要在某些带有jQuery和bootstrap等最常用的库中提供文档。

这是第一天的东西,但是文档对这些事情非常稀疏。似乎应该有一些协调的努力来真正解释webpack的变化本身就是另一个惨败。

请,如果您知道答案的答案,请发布它,以便每个人都能受益。

谢谢。

I've looked around for as much help as possible regarding installing jQuery in Rails 7 (7.0.2.3). I want to use it in script tags in my views, but I can't seem to get it exported to where it is globally available, er...ANYWHERE for that matter.

Sure importmaps is easy to manipulate as far as installing and mapping packages. Bravo. After that the whole documentation falls apart and a general haze clouds this new way of using js packages. Look around, there is plenty of confusion.

That said, how can I add this or something similar:

import jquery from "jquery"
window.jQuery = jquery;
window.$ = jquery;

to application.js or wherever to get a those global functions to work, like $. I'd like $ to be available in all my views.

As for what I've done:

./bin/importmap pin jquery --download

Gives me the importmap line:

pin "jquery" # @3.6.0

Ok. Then looking at the importmap JSON:

{
  "imports": {
    "application": "/assets/application-37a24e4747cc3cde854cbbd628efbdf8f909f7b031a9ec5d22c5052b06207eb8.js",
    "@hotwired/turbo-rails": "/assets/turbo.min-96cbf52c71021ba210235aaeec4720012d2c1df7d2dab3770cfa49eea3bb09da.js",
    "@hotwired/stimulus": "/assets/stimulus.min-900648768bd96f3faeba359cf33c1bd01ca424ca4d2d05f36a5d8345112ae93c.js",
    "@hotwired/stimulus-loading": "/assets/stimulus-loading-1fc59770fb1654500044afd3f5f6d7d00800e5be36746d55b94a2963a7a228aa.js",
    "jquery": "/assets/jquery-498b35766beec7b412bab57a5acbe41761daa65aa7090857db4e973fa88a5623.js",
    "controllers/application": "/assets/controllers/application-368d98631bccbf2349e0d4f8269afb3fe9625118341966de054759d96ea86c7e.js",
    "controllers/hello_controller": "/assets/controllers/hello_controller-549135e8e7c683a538c3d6d517339ba470fcfb79d62f738a0a089ba41851a554.js",
    "controllers": "/assets/controllers/index-7a8fc081f7e391bd7b6fba95a75e36f88ba813da2c4c8787adad248afb9a0a06.js"
  }
}

Ding. Appears it is there. Then a simple script tag in application.html.erb:

<script type="text/javascript" charset="utf-8">
        $(document).ready(function (){
            console.log('jQuery working.');
        })
</script>

Fail. Inspector says:

(index):41 Uncaught ReferenceError: $ is not defined

This really seems so very basic and is thoroughly irritating not to have documentation on some of the most used libraries with importmaps like jQuery and Bootstrap.

This is day 1 stuff, and yet docs are so very sparse on these things. Seems like there should be some coordinated effort to really explain a change away from webpack which in and of itself was another fiasco.

Please, if you know the answer to this, post it so that everyone can benefit.

Thanks.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

亣腦蒛氧 2025-01-28 07:45:16

截至目前(4月2022年)讨论

有两件事要考虑:内联脚本加载浏览器importmap支持。两者都可以使内在
脚本是指通过ImportMap反插图和容易出错的变量定义的变量。

直列脚本加载

内联脚本首先执行。那是在加载ImportMap JS脚本之前。请参阅 mdn script
文档

浏览器ImportMAP支持

ImportMap仍然非常新,并且支持各不相同。这使事情变得复杂。

  • 对于没有importMap的Firefox,使用eS模块shim,可以加载
    ImportMap 'load' +“ domcontentloaded”事件。
  • 对于带有importMap支持的Chrome,在'load'和
    “ domcontentloaded”。
  • 另外,对于各种原因

结论

可变的和功能 - 备用机制会处理脚本加载序列问题,但是在这种情况下,由于脚本是内联定义的,并且importmap脚本尚未加载,因此该变量未确定,并确定会导致一个
Reference Error:...未定义

解决方案

确保在访问之前定义变量,通过检查ImportMap中的脚本是否已加载到Inline脚本中,并且在运行代码访问它们之前

大多数可靠将变量放入application.js
在内联脚本中检查其声明 。如果它存在于ImportMap,并且已加载了application.js中的所有内容。

document.domcontentloaded事件或window.load.load事件或 都可以与 >关键字。另外,自定义事件可以在应用程序的末尾投掷。 JS仅在加载ImportMap代码之后才能强制运行内联码。

示例:

  1. importmap.rb中固定jQuery
// jquery does not export 'default' but defines window.$ and
// window.jQuery when loaded:
// - import 'jquery'; will not work
// - namespace does not matter here (jq)
// - no need to redefine it again w/ window.$ = jq.$
import * as jq from 'jquery';

// Define a variable to check in inlined HTML script
window.importmapScriptsLoaded = true;
  1. 之后

注意:根据注入的垫片/多填充,负载顺序仍然不确定。在这种情况下,需要更多的工作(例如扔自定义活动)。另外,DOM可能会加载两次,当不执行代码时,需要考虑考虑。

<h1 id="hello">Hello</h1>

<script type="text/javascript">

// Guard against double DOM loads
var codeExecuted = false;

document.addEventListener('DOMContentLoaded', function(e) {

  // Check if importmap stuff exisits without throwing an error.
  // Then run main code w/ guard against multiple executions.
  if ("importmapScriptsLoaded" in window) { 

    if (!codeExecuted) {
      // Main code here
      console.log($('#hello'));

      // Don't forget to bump guard for one-time only JS execution !!
      codeExecuted = true; 
    };  
  };

});
</script>
  • 或者,直接使用 Asset管道或直接public文件夹。
    这是不推荐的,原因有两个:
    内联脚本将被加载到ImportMap脚本一边。一个脚本可能会导致其所有依赖关系。 (ImportMap脚本尚未加载此处)。

例子:

<script type="text/javascript" src="/jquery.js"></script> 

Discussion

As of now (Apr-2022) There are two things to consider: inline script loading and browser importmap support. Both together can make inlining
scripts which refer to variables defined through importmap counter-intuivite and error-prone.

Inline Script Loading

Inline scripts are executed first. That's before the importmap JS scripts are loaded. See MDN script
docs
.

Browser Importmap Support

Importmap is still very new and support varies. This complicates things.

  • For firefox without importmap support the es-module-shim is used which can load the
    importmap after 'load' + 'DomContentLoaded' events.
  • For Chrome with importmap support the importmap is loaded before 'load' and
    'DomContentLoaded'.
  • Additionally DOM might be loaded twice for various reasons.

Conclusion

The variable- and function- hoisting mechanism takes care of script loading sequence problems, but in this case because the script is defined inline and importmap scripts have not yet been loaded, the variable is undeclared and it will definitively result in a
ReferenceError: ... is not defined.

Solutions

Ensure the variable is defined before accessing, by checking if scripts from the importmap have been loaded within the inline script and before running code accessing them.

Most reliable is placing a variable into application.js and
checking for its declaration safely in the inline script. If it exists importmap has been loaded and everything in application.js exists in the inline script context.

The document.DomContentLoaded event or the window.load event or both can be used for this in conjunction with the in keyword. Alternatively a custom event can be thrown at the end of application.js to enforce running the inline code only after the importmap code has been loaded.

Example:

  1. After pinning jquery in importmap.rb
  2. In app/javascript/application.js
// jquery does not export 'default' but defines window.$ and
// window.jQuery when loaded:
// - import 'jquery'; will not work
// - namespace does not matter here (jq)
// - no need to redefine it again w/ window.$ = jq.$
import * as jq from 'jquery';

// Define a variable to check in inlined HTML script
window.importmapScriptsLoaded = true;
  1. In the .html / .erb.html

NOTE: Depending on injected shims/polyfills the load order might still be undefined. In this case more work is needed (like throwing a custom event). Also the DOM might be loaded twice which needs to be taken into account when code shan't be double executed.

<h1 id="hello">Hello</h1>

<script type="text/javascript">

// Guard against double DOM loads
var codeExecuted = false;

document.addEventListener('DOMContentLoaded', function(e) {

  // Check if importmap stuff exisits without throwing an error.
  // Then run main code w/ guard against multiple executions.
  if ("importmapScriptsLoaded" in window) { 

    if (!codeExecuted) {
      // Main code here
      console.log($('#hello'));

      // Don't forget to bump guard for one-time only JS execution !!
      codeExecuted = true; 
    };  
  };

});
</script>
  • Alternatively inline the respective script directly, either by using the asset pipeline or straight the public folder.
    This is not recommended for two reasons:
    Inline scripts will be loaded aside importmap scripts. It is likely that inlining one script will lead to inline all its dependencies. (importmap scripts are not loaded here yet).

Example:

<script type="text/javascript" src="/jquery.js"></script> 
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文