英文:
Specific Image Not Loading After Rails 7 ESBuilt Update
问题
我在迁移到Ruby 3.2并使用Esbuild后,我的Rails 7应用出现了一个非常令人沮丧的问题。
基本上,有一些特定的图像根本加载不出来,然而,有许多其他图像在相同位置加载得很好,而且以完全相同的方式访问。这让我感到非常困扰。
我已经清除了缓存,重新启动了服务器,清除了所有本地构建文件,尽我所能做的一切。这个问题在开发和生产环境中都存在。
我的Esbuild运行得很好,它能够找到文件并使用指纹进行编译。这些文件都存在并位于正确的位置(都在app/assets/builds目录下)。
在浏览器中直接访问文件,比如:
http://localhost:4000/assets/logo_white_trans-QEBURZJB.png
会返回404错误,找不到图像。然而,该文件在app/assets/builds文件夹中以正确的名称存在。
访问页面中的另一张图像,比如:
http://localhost:4000/assets/leadstory-symbol-B5T7OIJB.png
则可以正常加载。
几乎可以认为有一个静态的Rails路由列表与这些图像匹配,但对于其中一些特定的图像,它没有生成路由,因此返回404错误,尽管文件存在。
下面是一些突出显示奇怪行为的截图:
以及在目录中列出的文件,显示文件明显存在:
我的package.json构建步骤如下:
esbuild app/javascript/bundles/*.* --bundle --sourcemap --outdir=app/assets/builds --public-path=/assets --minify --log-limit=0 --loader:.js=jsx --loader:.png=file --loader:.svg=file
以下是应用程序中加载图像的部分示例:
import LogoWhiteTrans from "../../assets/images/logo_white_trans.png";
<img src={LogoWhiteTrans} className="logo" alt="logo" />
这看起来工作正常,生成的HTML如下:
<img src="/assets/logo_white_trans-QEBURZJB.png" class="logo" alt="logo">
这个图像可以从应用程序中的其他地方正常加载,使用asset助手(而不是从React应用程序内部):
例如:
<%= asset_path('logo_white_trans.png') %>
我注意到日志中出现了以下内容:
ActionController::RoutingError (No route matches [GET] "/logo_white_trans-QEBURZJB.png"):
请注意,它没有说"/assets/logo_white_trans..."?我觉得这很奇怪,因为图像标签中的URL明显以/assets开头。无论在浏览器中是否包含/assets,都不起作用。Rails会以这种方式查看它似乎很奇怪。
我已经非常苦恼,我错过了什么?这不是一个特定于png的问题,因为其他png以相同的方式正常加载,也不是图像问题,因为文件存在且命名正确。
是否存在某种未更新的清单?内部资产路由列表或类似的东西?
我正在运行Rails 7
Ruby 3.2
ESBuild
英文:
I have a very frustrating issue with a Rails 7 app after migrating to Ruby 3.2 with Esbuild.
Basically there is a few specific images that simply will not load, however, there are many others that load just fine that live in the same location, and are accessed the exact same way. It's driving me nuts.
I have cleared cached, restarted servers, cleared all the local build files, everything I can think of. This is also happening in both dev and production.
My Esbuild is running just fine, it is finding the files and compiling them with a finger print. The files all exist and are in the right location. (all sitting under app/assets/builds)
Accessing the file direcly in the browser, ie
http://localhost:4000/assets/logo_white_trans-QEBURZJB.png
Fails with a 404, cannot find the image. This file however exists with the correct name in the app/assets/builds folder.
Accessing another image from the page ie
http://localhost:4000/assets/leadstory-symbol-B5T7OIJB.png
Loads just fine.
It's almost like there is a static list of rails routes that match the images and it is not generating the route for some of these specific images, hence the 404, even though the file exists.
Some screenshots that highlight the odd behaviour
and the files listed in the directory, showing the file clearly exists
My package.json build step is
esbuild app/javascript/bundles/*.* --bundle --sourcemap --outdir=app/assets/builds --public-path=/assets --minify --log-limit=0 --loader:.js=jsx --loader:.png=file --loader:.svg=file
And a snip from the app of how its being loaded.
import LogoWhiteTrans from "../../assets/images/logo_white_trans.png";
<img src={LogoWhiteTrans} className="logo" alt="logo" />
Which looks to be working fine, the HTML outputs
<img src="/assets/logo_white_trans-QEBURZJB.png" class="logo" alt="logo">
The image can be loaded fine, from elsewhere in the app in a regular rails view using asset helpers (not from within the React app)
ie <%= asset_path('logo_white_trans.png') %>
Something I have noticed is in the logs, I see
ActionController::RoutingError (No route matches [GET] "/logo_white_trans-QEBURZJB.png"):
Notice there it does not say "/assets/logo_white_trans..."? I thought that was weird, as the URL in the image tag clearly has a /assets at the start. Trying either path does not work, with or without /assets directly in the browser. Just seems odd rails would see it that way
Im going nuts here, what am I missing. Its not a png specific issue, as other pngs are loading fine in the same way, nor is it an image issue the file exists and the naming is fine.
Is there some sort of manifest thats not being updated? An internal asset route list or something along those lines?
Im running Rails 7
Ruby 3.2
ESBuild
答案1
得分: 1
这不是一个真正的答案,但我最终做的事情是将所有的图像资产从资产管道移出,并放入public文件夹中。我注意到我的资产被esbuilt和Rails资产预编译过程重复了,基本上JavaScript构建和Rails生态系统并不很好地协同工作。
对于其他遇到类似问题的人,我们将所有静态资产都移动到public/images文件夹中,现在在React和Ruby中都以相同的方式引用路径/images/blah.png
。
无论是在React还是标准的.erb视图中,所有图像标签都只是<img src="/images/blah.png/">
。这使一切变得更加清晰。
是的,我们放弃了资产指纹,但这只是一个小损失,考虑到大多数图像都不会改变,这极大地简化了事情并加快了我们的构建过程,因为它不必在预编译过程中触及每个文件。
我们的视图现在只有标准的标签,而不是<asset_path>标签,我相信这通常比Ruby一直生成这些资产字符串更快。
所以,这不是对最初问题的真正答案,但它是一个解决方案,我认为任何将现代JavaScript、React、TypeScript等融合到Rails应用中的人都可以考虑。
英文:
This isn't really an answer, but what I have ended up doing is moving all image assets out of the asset pipeline and into the public folder. I noticed that my assets were being duplicated by esbuilt and the rails asset precompile process, and basically the javascript build and rails eco system just do not work well together.
For anyone else having issues like this, we've just moved all our static assets in the public/images folder and we refernce the path /images/blah.png
the same way in both React and Ruby now.
All image tags in either React or standard .erb views are just <img src="/images/blah.png/>
. Its a lot cleaner.
Yes, we have given up asset finger printing, but its a small loss, considering most images never change and It's dramatically simplified things and sped up our build process considerably as it does not have to touch each file during precompilation.
Our views now also just have standard <img> tags, instead of <asset_path> tags, which im sure is just quicker in general instead of ruby generating these asset strings all the time.
So, not really and answer to the initial question but it is a solution, and one i think anyone who is fusing modern javascript, react, typescript etc into a Rails app.
答案2
得分: 1
我认为你所遇到的情况就是在this jsbundling-rails issue中所描述的。
简而言之,
(1) esbuild正在处理你的图像,对它们进行指纹处理,并保存到app/assets/builds目录中。
image.png -- esbuild --> app/assets/builds/image-123456.png
(2) 然后,Sprockets从app/assets/builds目录中处理你的图像,进行指纹处理,并保存到public/assets目录中。
app/assets/builds/image-123456.png -- Sprockets --> public/assets/image-123456-qwerty.png
而你的JavaScript代码正在寻找public/assets/image-123456.png。
我遵循了this suggestion,基本上是在你的package.json中的构建命令中添加了--asset-names=[name]-[hash].digested
。
英文:
I think what's happening to you is what is described in this jsbundling-rails issue..
In very simple words
(1) esbuild is processing your images, fingerpriting them and saving them to app/assets/builds..
image.png -- esbuild --> app/assets/builds/image-123456.png
(2) Then, sprockets is processing your images from app/assets/builds, fingerprinting them and saving to public/assets..
app/assets/builds/image-123456.png -- sprockets --> public/assets/image-123456-qwerty.png
And your js is looking for public/assets/image-123456.png
I followed this suggestion, which basically is adding --asset-names=[name]-[hash].digested
to your build command in package.json
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论