css 裡面url 和 asset_url 路徑問題


#1

小弟在一直在測路徑問題,已經測兩天快瘋了,

我想弄清楚css裡面 url 和assets_url 路徑到底是如何抓的

目前檔案目錄結構如下
53 PM

在app/assets/stylesheets/bootstrap/bootstrap.css.erb 裡面想要抓到字型檔

@font-face {
  font-family: 'Glyphicons Halflings';
  src: url('glyphicons-halflings-regular.svg') format('truetype');
}

觀察request 是http://localhost:3000/assets/bootstrap/glyphicons-halflings-regular.svg
所以把字型檔放在public/assets/bootstrap/glyphicons-halflings-regular.svg 結果200 ok

問題1

為什麼會去讀public/assets/bootstrap/ ? rails 是根據什麼規則呢?
難道每次都要開chrome 工具觀察request才知道檔案應該放哪嗎?Orz

問題2

但為什麼換其他的副檔名就會出錯?.eot .svg會出現以下錯誤,但.ttf .woff .woff2 就不會

Failed to decode downloaded font: 
http://localhost:3000/assets/bootstrap/glyphicons-halflings-regular.eot
localhost/:1 OTS parsing error: invalid version tag

問題3

如果bootstrap.css.erb換成用asset_url抓字型檔

@font-face {
  font-family: 'Glyphicons Halflings';
  src: url('<%= asset_url "bootstrap/glyphicons-halflings-regular.svg" %>') format('truetype');
}

然後字型檔放在app/assets/fonts/bootstrap/glyphicons-halflings-regular.svg
結果200 ok

我很困惑為什麼寫asset_url "bootstrap/.... 就知道去app/assets/fonts/bootstrap/...
到底規則是什麼???

因為像在view寫 image_tag "a.jpg" 圖片是放在app/assets/images/
路徑的問題真的快把人搞瘋了啊!


#2

嘛 … 我們的 youtube 有教學 … 你真的可以去看一看 |||

public/asset 不准動,因為裡面都是 precompiler / uglify 後的東西(來源是 %RAILS_APP%/app/assets/*),以你的專案方式根本不用放在那邊的啊啊啊 … 對我而言那邊可以全砍,因為都是從另外一邊處理後的結果放置處,很像亂葬岡的地方 …

你可以放在類似 public/static/image.gif 則網址填入 /static/image.gif 即可(隨便開了一個叫做 static 的資料夾在 public 內),但你不應該放在 public/asset

其餘的,assets 後面做得很像白名單,需要加入 config.assets.precompile 內才會做 precompiler / uglify 後的動作,並放到 public/asset 內去哩


#5

可是assets.rb已經有加所有檔名了噎…
Rails.application.config.assets.precompile += %w( .svg .eot .woff .ttf )

大大還有印象講解路徑是在哪個章節嗎?我剛瀏覽了一次沒有在目錄出現噎…。

還有請問像字型比較建議放在public還是加入assets pipline?還是用CDN

目前理解是,因為字型不太會改變所以其實不用加入assets pipline,因為加入assets pipline是為了加入finger print,防止cache造成的問題,所以其實放在public就可以了,至於CDN雖然不用擔心更新問題,也安裝容易,不過要是server距離遠會影響速度。


#6

首先,為何需要 assets pipline?原因是當初 sass / less / coffee script 之類的需要做二次處理,因為其是中介封裝的語言,最後會出 css / js 檔,也只有這兩種,所以你的字型檔應該不在這裡面,且 image 之類的也都不會處理才是 … 你就放 public 可以省掉很多事情哩

再來,我說它是白名單的意思是和 route 一樣是完全嚴格的白名單||| … 所以需要完整路徑 Orz" 如果你真的真的要全加,你可以用類似下面的語法

["#{Rails.root}/app" , "#{Rails.root}/vendor"].each do |from_dir|
  config.assets.paths << "#{from_dir}/assets/fonts"
  config.assets.paths << "#{from_dir}/assets/images"
  config.assets.paths << "#{from_dir}/assets/javascripts"
  config.assets.paths << "#{from_dir}/assets/stylesheets"
  config.assets.precompile += Dir.glob("#{from_dir}/assets/stylesheets/*.css").select{|e|File.file? e}.map{|i|i.to_s.gsub(/.+stylesheets\// , '')}
  config.assets.precompile += Dir.glob("#{from_dir}/assets/javascripts/*.js" ).select{|e|File.file? e}.map{|i|i.to_s.gsub(/.+javascripts\// , '')}
  config.assets.precompile += Dir.glob("#{from_dir}/assets/stylesheets/*/*.css").select{|e|File.file? e}.map{|i|i.to_s.gsub(/.+stylesheets\// , '')}
  config.assets.precompile += Dir.glob("#{from_dir}/assets/javascripts/*/*.js" ).select{|e|File.file? e}.map{|i|i.to_s.gsub(/.+javascripts\// , '')}
end

這個是卍解,掃描資料夾下所有所有的檔案然後加到該 array 去,不過很蠢不建議用,因為被加入怪怪的檔案後就會編譯成功|||,再來使用時只需要用類似 asset_url "testme.jpg" 就好(我記得 … )其餘前置 path 全都不用加,所以相同檔名會覆蓋掉有點麻煩|||

然而這邊和 CDN 一點關係都沒有,因為 CDN 是其他的解法(通常要對象 server 的 lib 支援,給你包含 domain 的網址之類的)

anyway 重來一次 … assets pipline 對我而言最大的好處只有對 css / js 做合併與壓縮,還有你說的上 fingerprint 的處理而已,其餘的好處應該都沒有,甚至已經 minify 的 lib 也不包含在裡面,因為它連 path 都要計算後才能產生,evil 寫法全部會噴死光光 … (webpack 還比較有趣些,不過那是另外一個故事了)所以對我而言,我只會把變動較多得主要的 js / css 丟進去,樹狀的 include(被 include 可以不用加在 config.assets.precompile 內),啟動點只有少數幾個,類似 application.js / dashboard.js / page.js 可以以 controller 或是像我用 layout 的方式來分,其餘不會變動的都丟 public 即可(尤其是你家美工額外用的 jQuery plugin / Bootstrap addon …),把事情簡單化,別讓自己鑽那個牛角尖,強迫自己弄那個看似很酷炫的東西,但實際使用都在砸自己的腳唄|||

最後,你到底是在做產品還是一直在試毒?而你在這個東西上已經花多久時間了呢?挑你覺得好用的,而不是一昧的全部都要吃進去,否則別的語言沒有 assets pipline 是如何打造一流的產品呢?先把你的東西完成後再來最佳化唄 … 不然都在浪費時間而已|||


#7

感謝大大,我知道情況是如何了,其實我覺得每次問問題最大的進步是觀點的進步,知道什麼樣的問題是重要,哪些不重要,學習更宏觀看待事情的角度:grinning: