几年后我再次使用 Rails(最后一次使用 Rails 4)。我有多个刺激控制器引用一个名为
metric_defaults.js
的文件。该文件仅包含一组平面定义,例如:
Chart.defaults.elements.line.tension = 0.25;
Chart.defaults.elements.line.borderWidth = 5;
在 Rails 7 开发环境中,此导入与每个刺激控制器中的
import '../metric_defaults.js'
配合良好,但在生产中我得到:
Failed to load resource: the server responded with a status of 404 (Not Found) (metric_defaults.js)
我花了一天的时间试图找出这个问题,但所有努力都失败了。一些花絮:
任何想法表示赞赏
设置:
# config/importmap.rb
pin "application"
pin "plugin"
// app/javascript/application.js
import "./plugin";
查看生成的导入映射:
$ bin/importmap json
{
"imports": {
"application": "/assets/application-6aad68dfc16d361773f71cfe7fe74ae0ace4eea0b74067bc717475bbbbf4e580.js",
"plugin": "/assets/plugin-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js"
}# ^ ^
} # imports urls
# for you for browser
非常简单:
import "plugin";
// will match "plugin" from import-maps
"plugin": "/assets/plugin-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js"
// and turn it into
import "/assets/plugin-04024382391bb910584145d8113cf35ef376b55d125bb4516cebeb14ce788597.js";
// browser sends request to this url ^
但是:
import "./plugin";
// is relative to `application.js`, because that's where the import is.
// application.js is imported correctly with `import "application"` in the layout
"application": "/assets/application-6aad68dfc16d361773f71cfe7fe74ae0ace4eea0b74067bc717475bbbbf4e580.js"
// ^^^^^^^^^^^
// so "./plugin" is relative to this, which resolves to "/assets/plugin"
import "/assets/plugin"; // doesn't match
"plugin" // the import-map
import "/assets/plugin";
// ^
// browser sends request in development and production
很确定这是我第一次关闭
config.assets.quiet
:
Started GET "/assets/application-6aad68dfc16d361773f71cfe7fe74ae0ace4eea0b74067bc717475bbbbf4e580.js" for 127.0.0.1 at 2023-04-27 00:28:21 -0400
Started GET "/assets/es-module-shims.js-32db422c5db541b7129a2ce936aed905edc2cd481748f8d67ffe84e28313158a.map" for 127.0.0.1 at 2023-04-27 00:28:21 -0400
Started GET "/assets/plugin" for 127.0.0.1 at 2023-04-27 00:28:21 -0400
# ^
# NOTE: see how this one didn't get mapped to anything, it is just a plain url.
在开发中
/assets
已路由到链轮,可以处理已消化和未消化的资产,并且工作正常:
>> Rails.application.routes.routes.detect {|i| i.ast.to_s =~ /assets/ }.app.app.class
=> Sprockets::Environment
# ^ same thing v undigested path v
>> Rails.application.assets.call(Rack::MockRequest.env_for("plugin")).last
=> #<Sprockets::Asset:fe718 "file:///home/alex/code/stackoverflow/app/javascript/plugin.js?type=application/javascript&id=187d193631f6880345ca4c2a2ac5d3a7c06ec09a64d4fbbd2cc1eed3a614997e">
在生产环境中,Web 服务器代替执行此工作,并且只有预编译的资源,
/assets/plugin
得到 404。
>> Rails.application.routes.routes.detect {|i| i.ast.to_s =~ /assets/ }
=> nil
停止使用相对导入。
制作一个与相对导入相匹配的导入映射:
# config/importmap.rb
pin "application"
pin "/assets/plugin", to: "plugin"
# ^ look familiar?
import "./plugin"; // this will be
import "/assets/plugin" // resolved to this
"/assets/plugin" // and will match the import-map
Started GET "/assets/application-6aad68dfc16d361773f71cfe7fe74ae0ace4eea0b74067bc717475bbbbf4e580.js" for 127.0.0.1 at 2023-04-27 03:52:47 -0400
Started GET "/assets/plugin-c8122d51d5713808bd0206fb036b098e74b576f45c42480e977eb11b9040f1f4.js" for 127.0.0.1 at 2023-04-27 03:52:47 -0400
Started GET "/assets/es-module-shims.js-32db422c5db541b7129a2ce936aed905edc2cd481748f8d67ffe84e28313158a.map" for 127.0.0.1 at 2023-04-27 03:52:47 -0400
如果你想走这条路,我会借用@cesoid的helper方法,它会帮助你开始:
# config/importmap.rb
def pin_all_relative(dir_name)
pin_all_from "app/javascript/#{dir_name}",
under: "#{Rails.application.config.assets.prefix}/#{dir_name}",
to: dir_name
end
pin_all_relative "controllers"
# etc
如果相对路径有困难,可以使用绝对路径。
// app/javascript/controllers/index.js
import { application } from 'controllers/application';
import DeleteController from 'controllers/delete_controller'; <= absolute path
application.register('delete', DeleteController);
import { eagerLoadControllersFrom } from '@hotwired/stimulus-loading';
eagerLoadControllersFrom('controllers', application);
这解决了我在生产中部署渲染时的问题。