Как добавить собственный JS-файл в новый проект rails 7

Я создал новый проект rails 7 rails new my_project и у меня проблема с включением моего пользовательского файла JS в обработанный рельсами.

мой "javascript / application.js"

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

import "chartkick"
import "Chart.bundle"
import "custom/uni_toggle"

мой собственный файл 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

Я использую в своем макете <%= javascript_importmap_tags %>

и мой "confing / 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"

4 ответа

Допустим, мы добавили каталог плагинов :

      app/
└── javascript/
   ├── application.js   # <= imports go here
   └── plugin/
      ├── app.js
      └── index.js
config/
└── importmap.rb        # <= pins go here

Закрепить один файл:

      # config/importmap.rb
pin "plugin/app"
pin "plugin/index"

# app/javascript/application.js
import "plugin/app"
import "plugin/index"

или закрепите все файлы в каталоге плагина и подкаталогах:

      # config/importmap.rb
pin_all_from "app/javascript/plugin", under: "plugin"

# app/javascript/application.js
import "plugin/app"
import "plugin"

Не используйте относительный импорт, напримерimport "./plugin", он может работать в разработке, но сломается в производстве.
См. выводbin/importmap jsonчтобы знать, что вы можете импортировать.

Не выполняйте предварительную компиляцию в процессе разработки, он будет обслуживать предварительно скомпилированные активы изpublic/assetsкоторые не обновляются при внесении изменений.
Бегатьbin/rails assets:clobberдля удаления предварительно скомпилированных ресурсов.

В случае, если что-то не работает, каталог app/javascript должен находиться в:
Rails.application.config.assets.paths
иapp/assets/config/manifest.js //= дерево_ссылок ../../javascript .js


Закрепление ваших файлов не приводит к их загрузке. Они должны быть импортированы в:

      // app/javascript/application.js
import "plugin"

В качестве альтернативы, если вы хотите разделить свой пакет, вы можете использовать отдельный тег модуля в своем макете:

      <%= javascript_import_module_tag "plugin" %>

или шаблоны:

      <% content_for :head do %>
  <%= javascript_import_module_tag "plugin" %>
<% end %>

# add this to the end of the <head> tag:
# <%= yield :head %>

Вы также можете добавить еще одну точку входа в дополнение кapplication.js, скажем, вы добавилиapp/javascript/admin.js. Вы можете импортировать его со всеми выводами:

      # this doesn't load application.js anymore
<%= javascript_importmap_tags "admin" %>

Кажетсяpin_all_fromне получил никакой документации, кроме того, что она есть в importmap.rb по умолчанию .

pin_all_from (каталог, под: ноль, в: ноль, предварительная загрузка: ложь)

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

      def pin_all_from(dir, under: nil, to: nil, preload: false)
  clear_cache
  @directories[dir] = MappedDir.new(dir: dir, under: under, path: to, preload: preload)
end

dir- Путь относительно Rails.root или абсолютный путь.

Параметры:

:under- Необязательный префикс булавки. Обязательно, если у вас естьindex.jsфайл.

- Необязательный путь к активу. Возвращается к опции : under . Требуется, если :under опущен. Этот путь относится к Rails.application.config.assets.paths .

- Добавляет ссылку на предварительную загрузку модуля , если установлено:

      <link rel="modulepreload" href="/assets/turbo-5605bff731621f9ca32b71f5270be7faa9ccb0c7c810187880b97e74175d85e2.js">

Мы можем закрепить все файлы в каталоге плагина :

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

# NOTE: `index.js` file gets a special treatment, instead
#       of pinning `plugin/index` it is just `plugin`.
{
  "imports": {
    "plugin/app": "/assets/plugin/app-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js",
    "plugin": "/assets/plugin/index-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js"
  }
}

Вот как все это сочетается:

         "plugin/app": "/assets/plugin/app-04024382391bb...4145d8113cf788597.js"
#   ^      ^      ^
#   |      |      |  
# :under   |      `-path_to_asset("plugin/app.js")
#          |                       ^      ^
#          |                       |      |
#          |..       (:to||:under)-'      |
#  "#{dir}/app.js"                        |
#          '''''`-------------------------'             

здесь вариант может быть неочевидным. Полезно, если опция :under изменена, что сделаетpath_to_assetне удается найти app.js.

Например, опция :under может быть чем угодно, но опция :to должна быть путем, который конвейер ресурсов, Sprockets , может найти (см. Rails.application.config.assets.paths ), а также предварительно скомпилировать (см. app/assets/ config/manifest.js ).

      pin_all_from "app/javascript/plugin", under: "@plug", to: "plugin"

# Outputs these pins
#
#   "@plug/app": "/assets/plugin/app-04024382391b1...16beb14ce788597.js"
#   "@plug": "/assets/plugin/index-04024382391bb91...4ebeb14ce788597.js"
#
# and can be used like this
#
#   import "@plug";
#   import "@plug/app";

Указание абсолютного пути приведет к обходу конвейера ресурсов.

      pin_all_from("app/javascript/plugin", under: "plugin", to: "/plugin")

#   "plugin/app": "/plugin/app.js"
#   "plugin": "/plugin/index.js"
#
# NOTE: It is up to you to set up `/plugin/*` route and serve these files.

Чтобы закрепить один файл, используйтеpinметод.

вывод (имя, до: ноль, предварительная загрузка: ложь)

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

      def pin(name, to: nil, preload: false)
  clear_cache
  @packages[name] = MappedFile.new(name: name, path: to || "#{name}.js", preload: preload)
end

name- Название булавки.

Параметры:

- Необязательный путь к активу. Отступает к{name}.js. Этот путь относится к Rails.application.config.assets.paths .

:preload- Добавляет ссылку на предварительную загрузку модуля , если установлено значениеtrue


При закреплении локального файла укажите имя относительно каталога app/javascript .

      pin("plugin/app")
pin("plugin/index")

# NOTE: produces these pins 
{
  "imports": {
    "plugin/app": "/assets/plugin/app-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js",
    "plugin/index": "/assets/plugin/index-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js"
  }
}

Вот как это сочетается:

         "plugin/app": "/assets/plugin/app-04024382391bb...16cebeb14ce788597.js"
#   ^             ^
#   |             |  
#  name           `-path_to_asset("plugin/app.js")
#                                  ^
#                                  |
#              (:to||"#{name}.js")-'

Если вы хотите изменить название пин-кода,:toтребуется, чтобы указать path_to_asset действительное расположение файла.

Например, чтобы получить тот же пин для файла index.js , который мы получаем из pin_all_from :

      pin("plugin", to: "plugin/index")

{
  "imports": {
    "plugin": "/assets/plugin/index-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js"
  }
} 

Вы можете возиться сImportmapв консоли быстрее отлаживать и узнавать, что работает, а что нет:

      >> map = Importmap::Map.new
>> map.pin_all_from("app/javascript/plugin", under: "plugin")

# NOTE: ApplicationController has the required `path_to_asset` helper
>> ApplicationController.helpers.path_to_asset("plugin/app.js")
=> "/assets/plugin/app-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js"

# NOTE: `path_to_asset` searches relative to these paths
>> Rails.application.config.assets.paths

>> puts map.to_json(resolver: ApplicationController.helpers)
{
  "imports": {
    "plugin/app": "/assets/plugin/app-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js",
    "plugin": "/assets/plugin/index-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js"
  }
}

# `pin` seems so much simpler now
>> map.pin("application")
>> puts map.to_json(resolver: ApplicationController.helpers)
{
  "imports": {
    "application": "/assets/application-8cab2d9024ef6f21fd55792af40001fd4ee1b72b8b7e14743452fab1348b4f5a.js"
  }
}

# Importmap from config/importmap.rb
>> Rails.application.importmap

Относительный/абсолютный импорт может работать, если вы сделаете правильное сопоставление:

      # config/importmap.rb
pin "/assets/plugin/app", to: "plugin/app.js"
      // app/javascript/application.js
import "./plugin/app"

application.js сопоставляется с дайджестом /assets/application-123.js, потому что./plugin/appотносится к /assets/application-123.js, он должен быть правильно разрешен к/assets/plugin/appу которого есть карта импорта, которую мы сделали с помощью нашего пин-кода:

      "/assets/plugin/app": "/assets/plugin/app-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js",

Это также должно работать:

      // app/javascript/plugin/index.js
import "./app"

Однако покаimport-maps поддерживает весь относительный и абсолютный импорт, это не похоже на предполагаемый вариант использования вimportmap-rails.

Также возникли проблемы с добавлением пользовательских файлов JS в мое приложение Rails 7. Я даже следил за видео DHH --> https://www.youtube.com/watch?v=PtxZvFnL2i0 , но все еще сталкивался с трудностями. Следующие шаги работали для меня:

  1. Перейдите в config/importmap.rb и добавьте следующее:pin_all_from "app/javascript/custom", в разделе: "custom"
  2. Перейдите в файл app/javascript/application.js и добавьте следующее: import "custom/main"
  3. В каталоге app/javascript добавьте папку custom.
  4. В каталог app/javascript/custom добавьте свой пользовательский файл js main.js.
  5. Запустите в своем терминале: rails assets:precompile
  6. Запустите свой сервер rails. Вуаля

После просмотра видео DHH я нашел последний кусочек головоломки.

Чтобы мой пользовательский код JS работал, я просто добавил эту строку в «confing/importmap.rb».

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

Если вы хотите использовать importmap, сделайте то, что люди уже ответили.

Но если вы добавите файл в карту импорта, это означает, что в каждом макете файл будет загружен, но если вы хотите добавить только один файл JS, я предлагаю использовать простой , с javascript_include_tag следующим образом :

      <%= javascript_include_tag 'filename' %>
Другие вопросы по тегам