如何在 Rails 7 引擎中设置 importmap-rails?

jam*_*esc 10 ruby-on-rails rails-engines import-maps ruby-on-rails-7

我已经在 importmap-rails gem github 存储库中提出了一个关于此问题的问题但我想我会在这里抛出这个问题,以防有人可能有解决方法

这是我迄今为止发现的

使用 Rails 7 alpha 2 或 Rails 7.0 生成的新引擎rails plugin new custom_page --mountable --full会生成一个新引擎,该引擎在捆绑的 gem 中包含 importmap-rails gem,但无法使用它。添加spec.add_dependency 'importmap-rails'到enginename.gemspec 没有什么区别,添加arequire importmap-rails到engine.rb 也没有区别。bin 目录中没有 importmap 可执行文件。调用bundle info importmap-rails 产生一个有希望的结果,表明默认情况下安装了 gem

* importmap-rails (0.8.1)
    Summary: Use ESM with importmap to manage modern JavaScript in Rails without transpiling or bundling.
    Homepage: https://github.com/rails/importmap-rails
    Source Code: https://github.com/rails/importmap-rails
    Path: /home/jamie/.rvm/gems/ruby-3.0.0@custom_page/gems/importmap-rails-0.8.1
Run Code Online (Sandbox Code Playgroud)

致电rails --tasks节目

rails app:importmap:install # Setup Importmap for the app
Run Code Online (Sandbox Code Playgroud)

但我相信这是来自 --full 选项生成的测试应用程序,而不是可供引擎的 Rails 命令使用。我期望在没有 app: 前缀的情况下看到相同的内容对此任务的调用会解析为模板错误,如图所示

rails app:importmap:install
Run Code Online (Sandbox Code Playgroud)

不知道如何构建任务“app:template”(使用 来查看可用任务列表rails --tasks)您是说吗?应用程序:tmp:创建

如果有一个解决此问题的解决方案,我将很高兴听到它,并且我相信其他人也会这样做。我想要这个的原因是我完全未能在 Rails 6.1.4 引擎中引入 webpacker,我希望这将是我的、经过改进的解决方案

更新响应亚历克斯

bin/importmap json在引擎目录中运行会导致

importmap-rails-1.2.1/lib/importmap/commands.rb:63:in json': undefined method join' for nil:NilClass (NoMethodError)

require Rails.root.join("config/environment")
                  ^^^^^
from /home/jamie/.rvm/gems/ruby-3.2.2@custom_page/gems/thor-1.2.2/lib/thor/command.rb:27:in `run'
from /home/jamie/.rvm/gems/ruby-3.2.2@custom_page/gems/thor-1.2.2/lib/thor/invocation.rb:127:in `invoke_command'
from /home/jamie/.rvm/gems/ruby-3.2.2@custom_page/gems/thor-1.2.2/lib/thor.rb:392:in `dispatch'
from /home/jamie/.rvm/gems/ruby-3.2.2@custom_page/gems/thor-1.2.2/lib/thor/base.rb:485:in `start'
from /home/jamie/.rvm/gems/ruby-3.2.2@custom_page/gems/importmap-rails-1.2.1/lib/importmap/commands.rb:147:in `<top (required)>'
from <internal:/home/jamie/.rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
from <internal:/home/jamie/.rvm/rubies/ruby-3.2.2/lib/ruby/3.2.0/rubygems/core_ext/kernel_require.rb>:37:in `require'
from bin/importmap:24:in `<main>'
Run Code Online (Sandbox Code Playgroud)

该引擎功能尚未出现在应用程序中

我的日志中没有 importmap 错误消息,搜索了“Importmap 跳过了丢失的路径”和“跳过”和“importmap”,最后一个确实抛出了早期错误的错误,但自从该错误得到解决后没有任何消息

我有一个标准的资产设置,我确实有一个更新 css 文件的功能,这可能就是您所想到的。

我没有已编译的资源,所有文件都以单数形式命名为 import 和 import.rb

我的application.js中的代码如下

// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails
Run Code Online (Sandbox Code Playgroud)

我的清单

//= link_directory ../stylesheets/ccs_cms/custom_page .css
//= link_tree ../javascripts/ccs_cms/custom_page .js
//= link_tree ../javascripts/new_ckeditor
//= link ccs_cms/custom_page/jqtree.css
//= link ccs_cms/custom_page/public.css
Run Code Online (Sandbox Code Playgroud)

我的 application.js 看起来像

// Configure your import map in config/importmap.rb. Read more: https://github.com/rails/importmap-rails

//= require ccs_cms/custom_page/jquery-3.6.0.min
//= require ccs_cms/custom_page/jquery-ui.min
//= require ccs_cms/custom_page/tree.jquery
//= require ccs_cms/custom_page/sortable
//= require ccs_cms/custom_page/nested_fields/addFields
//= require_tree .

//require("./nested-forms/addFields");
//require("./nested-forms/removeFields");

// do some javascript
document.querySelector("h1").innerText = "Hi!, i'm your engine";
console.log("hi, again");
Run Code Online (Sandbox Code Playgroud)

importmap.rb 包含以下内容

# my_engine/config/importmap.rb

# NOTE: this pin works because `my_engine/app/assets/javascripts
#       is in the `Rails.application.config.assets.paths`
pin "ccs_cms/custom_page/application"
Run Code Online (Sandbox Code Playgroud)

头部生成如下

<script type="importmap" data-turbo-track="reload">{
  "imports": {
  }
}</script>
Run Code Online (Sandbox Code Playgroud)

随着

<script type="module">import "application"</script>

<script type="module">import "ccs_cms/custom_page/application"</script>
Run Code Online (Sandbox Code Playgroud)

进一步更新:我确实在控制台中看到了 hi Again 消息,所以可以console.log("hi, again");工作,但document.querySelector("h1").innerText = "Hi!, i'm your engine";没有效果

最后,添加

  initializer :append_importmap_paths do |app|
    app.config.importmap.paths << root.join("config/importmap.rb")
  end
Run Code Online (Sandbox Code Playgroud)

到engine.rb解决了拼图的最后一块

Ale*_*lex 17

您不需要使用安装任务来设置导入映射。它所做的只是一些复制粘贴操作,无论如何它对引擎设置并没有真正的帮助。

将 importmaps 添加到引擎的 gemspec 文件中:

# my_engine/my_engine.gemspec

spec.add_dependency "importmap-rails"
Run Code Online (Sandbox Code Playgroud)

更新engine.rb

# my_engine/lib/my_engine/engine.rb

require "importmap-rails"

module MyEngine
  class Engine < ::Rails::Engine
    isolate_namespace MyEngine
    
    initializer "my-engine.importmap", before: "importmap" do |app|
      # NOTE: this will add pins from this engine to the main app
      # https://github.com/rails/importmap-rails#composing-import-maps
      app.config.importmap.paths << root.join("config/importmap.rb")

      # NOTE: something about cache; I did not look into it.
      # https://github.com/rails/importmap-rails#sweeping-the-cache-in-development-and-test
      app.config.importmap.cache_sweepers << root.join("app/assets/javascripts")
    end

    # NOTE: add engine manifest to precompile assets in production
    initializer "my-engine.assets" do |app|
      app.config.assets.precompile += %w[my_engine_manifest]
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

更新资产清单:

# my_engine/my_engine.gemspec

spec.add_dependency "importmap-rails"
Run Code Online (Sandbox Code Playgroud)

如果需要,为我们的引擎添加 javascript 入口点。无需此文件即可使用 Pin 图。

# my_engine/lib/my_engine/engine.rb

require "importmap-rails"

module MyEngine
  class Engine < ::Rails::Engine
    isolate_namespace MyEngine
    
    initializer "my-engine.importmap", before: "importmap" do |app|
      # NOTE: this will add pins from this engine to the main app
      # https://github.com/rails/importmap-rails#composing-import-maps
      app.config.importmap.paths << root.join("config/importmap.rb")

      # NOTE: something about cache; I did not look into it.
      # https://github.com/rails/importmap-rails#sweeping-the-cache-in-development-and-test
      app.config.importmap.cache_sweepers << root.join("app/assets/javascripts")
    end

    # NOTE: add engine manifest to precompile assets in production
    initializer "my-engine.assets" do |app|
      app.config.assets.precompile += %w[my_engine_manifest]
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

更新引擎的布局:

# my_engine/app/assets/config/my_engine_manifest.js

//= link_tree ../javascripts/my_engine .js
Run Code Online (Sandbox Code Playgroud)

创建importmap.rb和 pin my_engine/application,该名称必须与 匹配javascript_import_module_tag。它不能与主应用程序中的任何其他名称冲突,因此您不能只使用application

# my_engine/config/importmap.rb

# NOTE: this pin works because `my_engine/app/assets/javascripts
#       is in the `Rails.application.config.assets.paths`
pin "my_engine/application"
Run Code Online (Sandbox Code Playgroud)

用于测试设置的一些额外内容:

# my_engine/app/assets/javascripts/my_engine/application.js

// do some javascript
document.querySelector("h1").innerText = "hi, i'm your engine";
console.log("hi, again");
Run Code Online (Sandbox Code Playgroud)

此时,您应该在渲染布局的<head>标签中包含以下内容:

# my_engine/app/views/layouts/my_engine/application.html.erb

<!DOCTYPE html>
<html>
  <head>
    <!--
      NOTE: This loads/imports main app `application.js` and all the pins from
            the main app and from the engine (because we set it up in the engine.rb).
    -->
    <%= javascript_importmap_tags %>

    <!--
      NOTE: To add engine's javascript functionality we have to load the
            entrypoint here or `import` it in the main app `application.js`
    -->
    <%= javascript_import_module_tag "my_engine/application" %>
  </head>
  <body> <%= yield %> </body>
</html>
Run Code Online (Sandbox Code Playgroud)

H1标签应在重新加载时更改为<h1>hi, i'm your engine</h1>

可以使用https://generator.jspm.io/手动添加其他导入映射。

对于奖励积分,bin/importmap可以定制为在引擎内部工作。在bin目录中创建一个新importmap文件。

# my_engine/config/importmap.rb

# NOTE: this pin works because `my_engine/app/assets/javascripts
#       is in the `Rails.application.config.assets.paths`
pin "my_engine/application"
Run Code Online (Sandbox Code Playgroud)

从引擎目录内部运行:

# config/routes.rb
Rails.application.routes.draw do
  mount MyEngine::Engine => "/"
end

# my_engine/config/routes.rb
MyEngine::Engine.routes.draw do
  get "home", to: "homes#index"
end

# my_engine/app/controllers/my_engine/homes_controller.rb
module MyEngine
  class HomesController < ApplicationController
    def index; end
  end
end

# my_engine/app/views/my_engine/homes/index.html.erb
<h1>Home</h1>
Run Code Online (Sandbox Code Playgroud)

我还没有对其进行太多测试,因此欢迎任何反馈。如果某些内容没有出现,请重新启动服务器,我不知道重新加载的行为如何。