如何将自定义 JS 文件添加到新的 Rails 7 项目中

pa3*_*a3k 37 javascript ruby-on-rails import-maps ruby-on-rails-7

我创建了新的 Rails 7 项目rails new my_project,但在包含要由 Rails 处理的自定义 JS 文件时遇到问题。

我的“javascript/application.js”

import "@hotwired/turbo-rails"
import "controllers"

import "chartkick"
import "Chart.bundle"
import "custom/uni_toggle"
Run Code Online (Sandbox Code Playgroud)

我的自定义 JS 文件:“javascript/custom/uni_toggle.js”

function uniToggleShow() {
    document.querySelectorAll(".uni-toggle").forEach(e => e.classList.remove("hidden"))
}

function uniToggleHide() {
    console.log("uni toggle hide")
    document.querySelectorAll(".uni-toggle").forEach(e => e.classList.add("hidden"))
}

window.uniToggleShow = uniToggleShow
window.uniToggleHide = uniToggleHide
Run Code Online (Sandbox Code Playgroud)

我在我的布局中使用<%= javascript_importmap_tags %>

和我的“config/importmap.rb”

pin "application", preload: true
pin "@hotwired/turbo-rails", to: "turbo.min.js", preload: true
pin "@hotwired/stimulus", to: "stimulus.min.js", preload: true
pin "@hotwired/stimulus-loading", to: "stimulus-loading.js", preload: true
pin_all_from "app/javascript/controllers", under: "controllers"
Run Code Online (Sandbox Code Playgroud)

Ale*_*lex 87

1. Quickstart            - quick things you should know\n2. `pin_all_from`        - a few details\n3. `pin`                   ...\n4. Run in a console      - when you need to figure stuff out\n5. Relative imports      - don\'t do it, unless you want to\n6. Examples              - to make it extra clear\n
Run Code Online (Sandbox Code Playgroud)\n

如果您不使用,实际上importmap-rails,您不应该遇到任何问题。然后添加一个文件import "./path/to/file"。如果您正在bin/dev使用jsbundling-rails.

\n

如果您使用importmap-rails,则无需编译,每个文件都必须在开发和生产中单独提供,并且每个导入都必须映射到浏览器要获取的 URL。

\n

pinpin_all_from一种构建importmap. 导入通过资产 URL 映射到本地文件。因此请记住,import "something"可以映射到 url /assets/file-123.js,该 url 可以映射到文件app/some_asset_path/file.js或在生产中public/assets/file-123.js

\n
<script type="importmap" data-turbo-track="reload">{\n  "imports": {\n    "application":                  "/assets/application-da9b182f12cdd2de0b86de67fc7fde8d1887a7d9ffbde46937f8cd8553cb748d.js",\n    "@hotwired/turbo-rails":        "/assets/turbo.min-49f8a244b039107fa6d058adce740847d31bdf3832c043b860ebcda099c0688c.js",\n    "@hotwired/stimulus":           "/assets/stimulus-a1299f07b3a1d1083084767c6e16a178a910487c81874b80623f7f2e48f99a86.js",\n    "@hotwired/stimulus-loading":   "/assets/stimulus-loading-6024ee603e0509bba59098881b54a52936debca30ff797835b5ec6a4ef77ba37.js",\n    "controllers/application":      "/assets/controllers/application-44e5edd38372876617b8ba873a82d48737d4c089e5180f706bdea0bb7b6370be.js",\n    "controllers/hello_controller": "/assets/controllers/hello_controller-29468750494634340c5c12678fe2cdc3bee371e74ac4e9de625cdb7a89faf11b.js",\n    "controllers":                  "/assets/controllers/index-e70bed6fafbd4e4aae72f8c6fce4381d19507272ff2ff0febb3f775447accb4b.js",\n  }#    ^                             ^\n   #    |                             |\n   #  names you use to import        urls browser uses to get it\n   #    |                             ^ \n   #    |                             |\n   #    `------>  mapped to  ---------\'\n}</script>\n
Run Code Online (Sandbox Code Playgroud)\n

一旦你有了导入图,你就可以得到import你需要的东西了。Importmap 不加载任何内容,它只是一个配置。

\n
\n

快速开始

\n

假设我们添加了一个插件目录:

\n
app/\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 javascript/\n   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 application.js   # <= imports go here and other js files\n   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 plugin/\n      \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 app.js\n      \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 index.js\nconfig/\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 importmap.rb        # <= pins go here\n
Run Code Online (Sandbox Code Playgroud)\n

固定单个文件:

\n
# config/importmap.rb\npin "plugin/app"\npin "plugin/index"\n\n# app/javascript/application.js\nimport "plugin/app"     # which maps to a url which maps to a file\nimport "plugin/index"\n
Run Code Online (Sandbox Code Playgroud)\n

或者固定插件目录和子目录中的所有文件:

\n
# config/importmap.rb\npin_all_from "app/javascript/plugin", under: "plugin"\n\n# app/javascript/application.js\nimport "plugin/app"\nimport "plugin"\n
Run Code Online (Sandbox Code Playgroud)\n

不要使用相对导入,例如import "./plugin/app",它可能在开发中有效,但在生产中会崩溃。
\n查看输出bin/importmap json以了解可以导入哪些内容并验证importmap.rb配置。

\n

不要在开发中预编译,它将提供预编译的资源,public/assets当您进行更改时,这些资源不会更新。
\n运行bin/rails assets:clobber以删除预编译资源。

\n

如果出现问题,app/javascript目录必须位于:
\n Rails.application.config.assets.paths
\ napp/assets/config/manifest.js并且为//= link_tree ../../javascript .js

\n
\n

固定文件并不会使它们加载。它们必须导入application.js

\n
// app/javascript/application.js\nimport "plugin"\n
Run Code Online (Sandbox Code Playgroud)\n

或者,如果您想拆分捆绑包,可以在布局中使用单独的模块标签:

\n
<%= javascript_import_module_tag "plugin" %>\n
Run Code Online (Sandbox Code Playgroud)\n

或模板:

\n
<% content_for :head do %>\n  <%= javascript_import_module_tag "plugin" %>\n<% end %>\n\n# add this to the end of the <head> tag:\n# <%= yield :head %>\n
Run Code Online (Sandbox Code Playgroud)\n

除了 之外,您还可以添加另一个入口点application.js,假设您已经添加了app/javascript/admin.js。您可以使用所有引脚导入它:

\n
# this doesn\'t `import` application.js anymore\n<%= javascript_importmap_tags "admin" %>\n
Run Code Online (Sandbox Code Playgroud)\n

因为applicationpinpreload: true默认设置了选项,所以它会发出加载application.js文件的请求,即使您application使用admin. 预加载和导入是两件独立的事情,一件事不会导致另一件事。删除preload选项以避免不必要的请求。

\n
\n

pin_all_from(dir, 下: nil, 到: nil, 预加载: false)

\n

固定目录和子目录中的所有文件。

\n

https://github.com/rails/importmap-rails/blob/v1.1.2/lib/importmap/map.rb#L33

\n
def pin_all_from(dir, under: nil, to: nil, preload: false)\n  clear_cache\n  @directories[dir] = MappedDir.new(dir: dir, under: under, path: to, preload: preload)\nend\n
Run Code Online (Sandbox Code Playgroud)\n

dir- 相对于Rails.root的路径或绝对路径。

\n

选项:

\n

:under- 可选的[1]引脚前缀。如果您有index.js文件,则需要。

\n

:to- 可选的[1]资产路径。返回: under选项。如果省略:under则为必需。\n此路径相对于Rails.application.config.assets.paths

\n

:preload- 添加模块预加载链接(如果设置为true:)

\n
<link rel="modulepreload" href="/assets/turbo-5605bff731621f9ca32b71f5270be7faa9ccb0c7c810187880b97e74175d85e2.js">\n
Run Code Online (Sandbox Code Playgroud)\n
    \n
  1. 注意: 或:under:to必需的
  2. \n
\n
\n

要将所有文件固定在插件目录中:

\n
<link rel="modulepreload" href="/assets/turbo-5605bff731621f9ca32b71f5270be7faa9ccb0c7c810187880b97e74175d85e2.js">\n
Run Code Online (Sandbox Code Playgroud)\n

以下是它们的组合方式:
\n (如果某些功能不起作用,请选择您的选项并按照箭头操作,尤其是该path_to_asset部分,您可以在控制台中尝试,请参见下文)

\n
pin_all_from "app/javascript/plugin", under: "plugin"\n\n# NOTE: `index.js` file gets a special treatment, instead\n#       of pinning `plugin/index` it is just `plugin`.\n{\n  "imports": {\n    "plugin/app": "/assets/plugin/app-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js",\n    "plugin": "/assets/plugin/index-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js"\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

:to这里的选项可能并不明显。如果更改:underpath_to_asset选项,这将很有用,这将导致找不到app.js

\n

例如,:under选项可以是您想要的任何内容,但:to选项必须是资产管道Sprockets可以找到的路径(请参阅Rails.application.config.assets.paths)并且还可以预编译(请参阅app/assets/配置/manifest.js)。

\n
   "plugin/app": "/assets/plugin/app-04024382391bb...4145d8113cf788597.js"\n#   ^      ^      ^\n#   |      |      |  \n# :under   |      `-path_to_asset("plugin/app.js")\n#          |                       ^      ^\n#          |                       |      |\n#          |..       (:to||:under)-\'      |\n#  "#{dir}/app.js"                        |\n#          \'\'\'\'\'`-------------------------\'             \n
Run Code Online (Sandbox Code Playgroud)\n

指定绝对路径将绕过资产管道:

\n
pin_all_from "app/javascript/plugin", under: "@plug", to: "plugin"\n\n# Outputs these pins\n#\n#   "@plug/app": "/assets/plugin/app-04024382391b1...16beb14ce788597.js"\n#   "@plug": "/assets/plugin/index-04024382391bb91...4ebeb14ce788597.js"\n#\n# and can be used like this\n#\n#   import "@plug";\n#   import "@plug/app";\n
Run Code Online (Sandbox Code Playgroud)\n
\n

pin(名称,至:nil,预加载:false)

\n

固定单个文件。

\n

https://github.com/rails/importmap-rails/blob/v1.1.2/lib/importmap/map.rb#L28

\n
pin_all_from("app/javascript/plugin", under: "plugin", to: "/plugin")\n\n#   "plugin/app": "/plugin/app.js"\n#   "plugin": "/plugin/index.js"\n#\n# NOTE: It is up to you to set up `/plugin/*` route and serve these files.\n
Run Code Online (Sandbox Code Playgroud)\n

name- 引脚名称。

\n

选项:

\n

:to- 资产的可选路径。跌回到{name}.js. 此路径相对于Rails.application.config.assets.paths

\n

:preload- 添加模块预加载链接(如果设置为)true

\n
\n

固定本地文件时,指定相对于app/javascript目录(或供应商或任何其他资产目录)的名称。

\n
def pin(name, to: nil, preload: false)\n  clear_cache\n  @packages[name] = MappedFile.new(name: name, path: to || "#{name}.js", preload: preload)\nend\n
Run Code Online (Sandbox Code Playgroud)\n

以下是它的组合方式:

\n
pin "plugin/app"\npin "plugin/index"\n\n{\n  "imports": {\n    "plugin/app": "/assets/plugin/app-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js",\n    "plugin/index": "/assets/plugin/index-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js"\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

如果您想更改引脚名称:to,则需要选项为path_to_asset提供有效的文件位置。

\n

例如,要为index.js文件获取与我们从pin_all_from获取的引脚相同的引脚:

\n
   "plugin/app": "/assets/plugin/app-04024382391bb...16cebeb14ce788597.js"\n#   ^             ^\n#   |             |  \n#  name           `-path_to_asset("plugin/app.js")\n#                                  ^\n#                                  |\n#              (:to||"#{name}.js")-\'\n
Run Code Online (Sandbox Code Playgroud)\n
\n

在控制台中运行

\n

您可以在控制台中乱搞Importmap,调试和了解哪些有效、哪些无效的速度更快:

\n
pin "plugin", to: "plugin/index"\n\n{\n  "imports": {\n    "plugin": "/assets/plugin/index-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js"\n  }\n} \n
Run Code Online (Sandbox Code Playgroud)\n
\n

相对/绝对进口

\n

如果您进行正确的映射,相对/绝对导入可以工作:

\n
>> helper.path_to_asset("plugin/app.js")\n=> "/assets/plugin/app-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js"\n\n>> map = Importmap::Map.new\n>> map.pin_all_from("app/javascript/plugin", under: "plugin")\n>> puts map.to_json(resolver: helper)\n{\n  "imports": {\n    "plugin/app": "/assets/plugin/app-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js",\n    "plugin": "/assets/plugin/index-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js"\n  }\n}\n\n>> map.pin("application")\n>> puts map.to_json(resolver: helper)\n{\n  "imports": {\n    "application": "/assets/application-8cab2d9024ef6f21fd55792af40001fd4ee1b72b8b7e14743452fab1348b4f5a.js"\n  }\n}\n\n# Importmap from config/importmap.rb\n>> Rails.application.importmap\n
Run Code Online (Sandbox Code Playgroud)\n
// app/javascript/application.js\nimport "./plugin/app"\n
Run Code Online (Sandbox Code Playgroud)\n

application.js映射到消化后的/assets/application-123.js,因为./plugin/app相对于/assets/application-123.js,它应该正确解析为/assets/plugin/app具有我们用 pin 制作的导入映射:

\n
"/assets/plugin/app": "/assets/plugin/app-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js",\n
Run Code Online (Sandbox Code Playgroud)\n

这也应该有效:

\n
// app/javascript/plugin/index.js\nimport "./app"\n
Run Code Online (Sandbox Code Playgroud)\n

然而,虽然import-maps 支持所有相对和绝对导入,但这似乎不是importmap-rails.

\n
\n

例子

\n

这应该涵盖几乎所有内容:

\n
# config/importmap.rb\npin "/assets/plugin/app", to: "plugin/app.js"\n
Run Code Online (Sandbox Code Playgroud)\n

输出来自运行bin/importmap json

\n
// app/javascript/application.js\nimport "./plugin/app"\n
Run Code Online (Sandbox Code Playgroud)\n

注意区别:

\n
"/assets/plugin/app": "/assets/plugin/app-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js",\n
Run Code Online (Sandbox Code Playgroud)\n

注意模式:

\n
// app/javascript/plugin/index.js\nimport "./app"\n
Run Code Online (Sandbox Code Playgroud)\n
.\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 app/\n\xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 javascript/\n\xe2\x94\x82       \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 admin.js\n\xe2\x94\x82       \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 application.js\n\xe2\x94\x82       \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 extra/\n\xe2\x94\x82       \xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 nested/\n\xe2\x94\x82       \xe2\x94\x82       \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 directory/\n\xe2\x94\x82       \xe2\x94\x82           \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 special.js\n\xe2\x94\x82       \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 plugin/\n\xe2\x94\x82           \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 app.js\n\xe2\x94\x82           \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 index.js\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 vendor/\n    \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 javascript/\n        \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 downloaded.js\n        \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 package/\n            \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 vendored.js\n
Run Code Online (Sandbox Code Playgroud)\n
# this is the only time when both `to` and `under` options can be omitted\n# you don\'t really want to do this, at least not for `app/javascript`\npin_all_from "app/javascript"\npin_all_from "vendor/javascript"\n\n"admin":                          "/assets/admin-761ee3050e9046942e5918c64dbfee795eeade86bf3fec34ec126c0d43c931b0.js",\n"application":                    "/assets/application-d0d262731ff4f756b418662f3149e17b608d2aab7898bb983abeb669cc73bf2e.js",\n"extra/nested/directory/special": "/assets/extra/nested/directory/special-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js",\n"plugin/app":                     "/assets/plugin/app-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js",\n"plugin":                         "/assets/plugin/index-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js",\n"downloaded":                     "/assets/downloaded-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js",\n"package/vendored":               "/assets/package/vendored-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js"\n
Run Code Online (Sandbox Code Playgroud)\n

同样的事情也适用于供应商:

\n
pin_all_from "app/javascript/extra", under: "extra"    # `to: "extra"` is implied\n"extra/nested/directory/special": "/assets/extra/nested/directory/special-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js"\n ^\n\npin_all_from "app/javascript/extra", to: "extra"\n"nested/directory/special": "/assets/extra/nested/directory/special-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js"\n ^\n\npin_all_from "app/javascript/extra", under: "@name", to: "extra"\n"@name/nested/directory/special": "/assets/extra/nested/directory/special-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js"\n ^\n
Run Code Online (Sandbox Code Playgroud)\n

单个文件很简单:

\n
pin_all_from "app/javascript"\npin_all_from "app/javascript/extra",                  under: "extra"\npin_all_from "app/javascript/extra/nested",           under: "extra/nested"\npin_all_from "app/javascript/extra/nested/directory", under: "extra/nested/directory"\n
Run Code Online (Sandbox Code Playgroud)\n

pin_all_from失败时:

\n
pin_all_from "app/javascript/extra",                  to: "extra"\npin_all_from "app/javascript/extra/nested",           to: "extra/nested"\npin_all_from "app/javascript/extra/nested/directory", to: "extra/nested/directory"\n
Run Code Online (Sandbox Code Playgroud)\n

  • 这篇文章值得所有的点赞。谢谢。 (10认同)
  • 这个答案就像缺少导入映射手册。 (6认同)
  • 这必须在 Rails 官方文档中。特别是关于从“Rails.application.config.assets.paths”相对导入的部分。恕我直言,这并不明显。感谢您为此评论付出的所有努力 (2认同)

小智 27

在我的 Rails 7 应用程序中添加自定义 JS 文件时也遇到问题。我什至关注了 DHH 视频 --> https://www.youtube.com/watch?v=PtxZvFnL2i0但仍然面临困难。以下步骤对我有用:

\n
    \n
  1. 转到config/importmap.rb并添加以下内容:

    \n

    pin_all_from "app/javascript/custom", under: "custom"

    \n
  2. \n
  3. 转到 app/javascript/application.js 文件并添加以下内容:

    \n

    import "custom/main"

    \n
  4. \n
  5. “app/javascript”目录中,添加“custom”文件夹。

    \n
  6. \n
  7. “app/javascript/custom”目录中添加自定义 js 文件“main.js”。

    \n
  8. \n
  9. 在您的终端中运行:

    \n

    Rails 资产:预编译

    \n
  10. \n
  11. 启动 Rails 服务器。\nVoil\xc3\xa0

    \n
  12. \n
\n

  • 这种方法可行,但在对自定义 JS 文件进行任何编辑后运行 `rails asset:precompile` 不可能是正确的行为 (4认同)
  • @depassion 我认为该视频现在有点旧了。您不必再预编译了。 (2认同)
  • 不,不应该。像“./custom/main”这样的导入最终会直接指向资产文件夹。他们会在生产中中断。 (2认同)

pa3*_*a3k 22

看完 DHH视频后,我找到了最后一块拼图。

为了使我的自定义 JS 代码正常工作,我刚刚将此行添加到“confing/importmap.rb”中

pin_all_from "app/javascript/custom", under: "custom"
Run Code Online (Sandbox Code Playgroud)