edge
เพิ่มเติมที่ rubyonrails.org: เพิ่มเติมเกี่ยวกับ Ruby on Rails

ท่องทางทรัพยากร (Asset Pipeline)

เอกสารนี้เป็นคู่มือเกี่ยวกับท่องทางทรัพยากร (asset pipeline)

หลังจากอ่านคู่มือนี้คุณจะรู้:

Chapters

  1. ท่องทางทรัพยากรคืออะไร?
  2. คุณสมบัติหลัก
  3. วิธีการใช้ Import Maps เป็นการประมวลผล Javascript Asset Pipeline
  4. วิธีใช้ Sprockets
  5. ในการใช้งานจริง
  6. การปรับแต่งไฟล์แอสเซ็ต
  7. การเก็บแคชทรัพยากร
  8. เพิ่มทรัพยากรใน Gems ของคุณ
  9. ทำให้ไลบรารีหรือ gem ของคุณเป็นตัวก่อนการประมวลผล
  10. ไลบรารีทางเลือก

1 ท่องทางทรัพยากรคืออะไร?

ท่องทางทรัพยากร (asset pipeline) ให้เฟรมเวิร์กสำหรับการจัดการการส่งมอบทรัพยากร JavaScript และ CSS โดยใช้เทคโนโลยีเช่น HTTP/2 และเทคนิคเช่นการรวมและการย่อขนาด (concatenation and minification) ในที่สุด มันยังช่วยให้แอปพลิเคชันของคุณสามารถรวมกับทรัพยากรจาก gem อื่นๆ ได้อัตโนมัติ

ท่องทางทรัพยากรนี้ถูกนำมาใช้งานโดย gem importmap-rails, sprockets และ sprockets-rails และถูกเปิดใช้งานโดยค่าเริ่มต้น คุณสามารถปิดใช้งานได้เมื่อสร้างแอปพลิเคชันใหม่โดยใช้ตัวเลือก --skip-asset-pipeline

$ rails new appname --skip-asset-pipeline

หมายเหตุ: เอกสารนี้เน้นใช้ท่องทางทรัพยากรเริ่มต้นที่ใช้เพียง sprockets สำหรับ CSS และ importmap-rails สำหรับการประมวลผล JavaScript เจาะจงสิ่งที่สองนี้มีข้อจำกัดคือไม่มีการสนับสนุนการแปลงรหัสเพื่อใช้งาน Babel, Typescript, Sass, React JSX format หรือ TailwindCSS คุณสามารถอ่านส่วน Alternative Libraries section หากคุณต้องการการแปลงรหัสสำหรับ JavaScript/CSS

2 คุณสมบัติหลัก

คุณสมบัติหลักของท่องทางทรัพยากรคือการแทรก SHA256 fingerprinting เข้าไปในชื่อไฟล์แต่ละไฟล์เพื่อให้เบราว์เซอร์เว็บและ CDN แคชไฟล์นั้น ๆ ซึ่ง fingerprint นี้จะถูกอัปเดตโดยอัตโนมัติเมื่อคุณเปลี่ยนเนื้อหาของไฟล์ ซึ่งทำให้แคชเก่าไม่สามารถใช้งานได้อีก

คุณสมบัติที่สองของท่องทางทรัพยากรคือการใช้ import maps เมื่อให้บริการไฟล์ JavaScript ซึ่งช่วยให้คุณสร้างแอปพลิเคชันที่ใช้งานไลบรารี JavaScript รุ่นใหม่ที่สร้างสำหรับ ES modules (ESM) โดยไม่ต้องแปลงรหัสและรวมไฟล์ นอกจากนี้ สิ่งนี้ยังเป็นการลดความจำเป็นในการใช้งาน Webpack, yarn, node หรือส่วนอื่น ๆ ของเครื่องมือ JavaScript

คุณสมบัติที่สามของท่องทางทรัพยากรคือการรวมไฟล์ CSS ทั้งหมดเข้าไปในไฟล์หลัก .css เดียว แล้วทำการย่อขนาดหรือบีบอัดไฟล์นั้น ๆ ตามต้องการ ตามที่คุณจะเรียนรู้ในภายหลังในคู่มือนี้ คุณสามารถกำหนดกลยุทธ์นี้เพื่อจัดกลุ่มไฟล์ได้ตามที่คุณต้องการ ในโหมดการใช้งานจริง Rails จะแทรก SHA256 fingerprint เข้าไปในชื่อไฟล์แต่ละไฟล์เพื่อให้เบราว์เซอร์เว็บแคชไฟล์นั้น ๆ คุณสามารถยกเลิกแคชได้โดยการเปลี่ยน fingerprint นี้ซึ่งเกิดขึ้นโดยอัตโนมัติเมื่อคุณเปลี่ยนเนื้อหาของไฟล์

คุณสมบัติที่สี่ของท่องทางทรัพยากรคือการให้คุณเขียนทรัพยากรผ่านภาษาระดับสูงสำหรับ CSS

2.1 Fingerprinting คืออะไรและทำไมฉันควรสนใจ?

Fingerprinting เป็นเทคนิคที่ทำให้ชื่อของไฟล์ขึ้นอยู่กับเนื้อหาของไฟล์ เมื่อเนื้อหาของไฟล์เปลี่ยนแปลง ชื่อไฟล์ก็จะเปลี่ยนไปด้วย สำหรับเนื้อหาที่เป็นคงที่หรือไม่เปลี่ยนบ่อย วิธีนี้จะช่วยให้คุณสามารถรู้ได้ง่ายว่าสองเวอร์ชันของไฟล์เหล่านั้นเหมือนกันหรือไม่ แม้ว่าจะอยู่บนเซิร์ฟเวอร์ที่แตกต่างกันหรือวันที่ติดตั้งแตกต่างกัน

เมื่อชื่อไฟล์เป็นเอกลักษณ์และขึ้นอยู่กับเนื้อหาของไฟล์ คุณสามารถตั้งค่า HTTP headers เพื่อสร้างแคชที่ทุกที่ (ไม่ว่าจะอยู่ที่ CDNs, ISPs, อุปกรณ์เครือข่าย หรือเบราว์เซอร์เว็บ) เก็บสำเนาของเนื้อหาไว้ในแคชของตัวเอง เมื่อเนื้อหามีการอัปเดต fingerprint ก็จะเปลี่ยน ซึ่งจะทำให้ไคลเอนต์ระยะไกลต้องขอเนื้อหาใหม่ สิ่งนี้เป็นที่รู้จักกันในนามของ cache busting เทคนิคที่ Sprockets ใช้สำหรับการทำ fingerprinting คือการแทรกแฮชของเนื้อหาลงในชื่อ โดย通常จะอยู่ที่ส่วนท้าย ตัวอย่างเช่นไฟล์ CSS global.css

global-908e25f4bf641868d8683022a5b62f54.css

นี่คือกลยุทธ์ที่ได้รับการนำมาใช้ใน Rails asset pipeline

Fingerprinting ถูกเปิดใช้งานโดยค่าเริ่มต้นสำหรับทั้งสภาพแวดล้อมการพัฒนาและการผลิต คุณสามารถเปิดหรือปิดใช้งานได้ในการกำหนดค่าของคุณผ่านตัวเลือก config.assets.digest

2.2 Import Maps คืออะไรและทำไมฉันควรสนใจ?

Import maps ช่วยให้คุณสามารถนำเข้าโมดูล JavaScript โดยใช้ชื่อตรรกะที่จับคู่กับไฟล์ที่มีเวอร์ชัน/แฮช - โดยตรงจากเบราว์เซอร์ ดังนั้นคุณสามารถสร้างแอปพลิเคชัน JavaScript ที่ใช้ไลบรารี JavaScript ที่สร้างสำหรับ ES modules (ESM) โดยไม่ต้องทำการแปลงรหัสหรือรวมไฟล์

ด้วยวิธีการนี้คุณจะส่งออกไฟล์ JavaScript เล็ก ๆ หลายไฟล์แทนที่จะส่งออกไฟล์ JavaScript ใหญ่ ๆ หนึ่งไฟล์ ด้วยคุณสมบัติ HTTP/2 ที่ไม่มีผลกระทบต่อประสิทธิภาพในการส่งข้อมูลครั้งแรกและในความเป็นจริงนั้นยังมีประโยชน์มากขึ้นเนื่องจากการแคชที่ดีกว่า

3 วิธีการใช้ Import Maps เป็นการประมวลผล Javascript Asset Pipeline

Import Maps เป็นตัวประมวลผล Javascript เริ่มต้น โลจิกในการสร้าง import maps จัดการโดย gem importmap-rails

คำเตือน: Import maps ใช้เฉพาะสำหรับไฟล์ Javascript เท่านั้นและไม่สามารถใช้สำหรับการส่ง CSS ได้ ตรวจสอบส่วน Sprockets section เพื่อเรียนรู้เกี่ยวกับ CSS

คุณสามารถค้นหาคำสั่งการใช้งานอย่างละเอียดในหน้าหลักของ Gem แต่สิ่งสำคัญที่ต้องเข้าใจคือ importmap-rails พื้นฐาน

3.1 วิธีการทำงาน

Import maps ในพื้นฐานแล้วเป็นการแทนที่สตริงสำหรับสิ่งที่เรียกว่า "bare module specifiers" พวกเขาช่วยให้คุณมีความสามารถในการมาตรฐานชื่อของการนำเข้าโมดูล JavaScript

เรามาดูตัวอย่างการนำเข้าที่ไม่สามารถทำงานได้โดยไม่มี import map:

import React from "react"

คุณต้องกำหนดมันเช่นนี้เพื่อให้สามารถทำงานได้:

import React from "https://ga.jspm.io/npm:[email protected]/index.js"

นี่คือ import map เรากำหนดชื่อ react ให้เป็น https://ga.jspm.io/npm:[email protected]/index.js ด้วยข้อมูลเช่นนี้เบราว์เซอร์ของเรายอมรับการนิยาม import React from "react" ที่เรียบง่ายขึ้น คิดว่า import map เป็นเหมือนตัวย่อสำหรับที่อยู่แหล่งของไลบรารี

3.2 การใช้งาน

ด้วย importmap-rails คุณสร้างไฟล์กำหนดค่า importmap ที่ตรึงเส้นทางไลบรารีไปยังชื่อ:

# config/importmap.rb
pin "application"
pin "react", to: "https://ga.jspm.io/npm:[email protected]/index.js"

ทุก import map ที่กำหนดค่าควรถูกแนบไปยังองค์ประกอบ <head> ของแอปพลิเคชันของคุณโดยการเพิ่ม <%= javascript_importmap_tags %> เป็นที่แท็กสคริปต์จะแสดงสคริปต์จำนวนมากในองค์ประกอบ head:

  • JSON พร้อม import maps ที่กำหนดค่าทั้งหมด:
<script type="importmap">
{
  "imports": {
    "application": "/assets/application-39f16dc3f3....js"
    "react": "https://ga.jspm.io/npm:[email protected]/index.js"
  }
}
</script>
  • Es-module-shims ที่ทำหน้าที่เป็น polyfill เพื่อให้รองรับ import maps บนเบราว์เซอร์รุ่นเก่า:
<script src="/assets/es-module-shims.min" async="async" data-turbo-track="reload"></script>
  • จุดเริ่มต้นสำหรับการโหลด JavaScript จาก app/javascript/application.js:
<script type="module">import "application"</script>

3.3 การใช้งานแพ็คเกจ npm ผ่าน JavaScript CDNs

คุณสามารถใช้คำสั่ง ./bin/importmap ที่เพิ่มเข้ามาในการติดตั้ง importmap-rails เพื่อตรึงเส้นทาง ยกเลิกการตรึงเส้นทาง หรืออัปเดตแพ็คเกจ npm ใน import map ของคุณ สคริปต์ binstub ใช้ JSPM.org

มันทำงานดังนี้:

./bin/importmap pin react react-dom
Pinning "react" to https://ga.jspm.io/npm:[email protected]/index.js
Pinning "react-dom" to https://ga.jspm.io/npm:[email protected]/index.js
Pinning "object-assign" to https://ga.jspm.io/npm:[email protected]/index.js
Pinning "scheduler" to https://ga.jspm.io/npm:[email protected]/index.js

./bin/importmap json

{
  "imports": {
    "application": "/assets/application-37f365cbecf1fa2810a8303f4b6571676fa1f9c56c248528bc14ddb857531b95.js",
    "react": "https://ga.jspm.io/npm:[email protected]/index.js",
    "react-dom": "https://ga.jspm.io/npm:[email protected]/index.js",
    "object-assign": "https://ga.jspm.io/npm:[email protected]/index.js",
    "scheduler": "https://ga.jspm.io/npm:[email protected]/index.js"
  }
}

เห็นได้ว่าแพคเกจสองแพคเกจ react และ react-dom แก้ไขไปยังทั้งหมดสี่ความสัมพันธ์เมื่อแก้ไขผ่าน jspm default

ตอนนี้คุณสามารถใช้พวกเขาใน application.js ต้นทางเข้าเหมือนกับโมดูลอื่น ๆ:

import React from "react"
import ReactDOM from "react-dom"

คุณยังสามารถกำหนดรุ่นที่แน่นอนได้:

./bin/importmap pin [email protected]
กำหนด "react" ไปยัง https://ga.jspm.io/npm:[email protected]/index.js
กำหนด "object-assign" ไปยัง https://ga.jspm.io/npm:[email protected]/index.js

หรือลบการกำหนดรุ่น:

./bin/importmap unpin react
ยกเลิกการกำหนด "react"
ยกเลิกการกำหนด "object-assign"

คุณสามารถควบคุมสภาพแวดล้อมของแพคเกจสำหรับแพคเกจที่มีการสร้างแยกต่างหากสำหรับ "production" (ค่าเริ่มต้น) และ "development":

./bin/importmap pin react --env development
กำหนด "react" ไปยัง https://ga.jspm.io/npm:[email protected]/dev.index.js
กำหนด "object-assign" ไปยัง https://ga.jspm.io/npm:[email protected]/index.js

คุณยังสามารถเลือกผู้ให้บริการ CDN ที่เป็นทางเลือกอื่น ๆ เมื่อกำหนดรุ่น เช่น unpkg หรือ jsdelivr (jspm เป็นค่าเริ่มต้น):

./bin/importmap pin react --from jsdelivr
กำหนด "react" ไปยัง https://cdn.jsdelivr.net/npm/[email protected]/index.js

อย่าลืมว่าหากคุณสลับการกำหนดรุ่นจากผู้ให้บริการหนึ่งไปยังอีกผู้ให้บริการหนึ่งคุณอาจต้องทำความสะอาดความขึ้นอยู่กับผู้ให้บริการแรกที่ไม่ถูกใช้โดยผู้ให้บริการที่สอง

เรียกใช้ ./bin/importmap เพื่อดูตัวเลือกทั้งหมด

โปรดทราบว่าคำสั่งนี้เป็นเพียงตัวครอบคลุมสะดวกสบายเพื่อแก้ไขชื่อแพคเกจตามตัวแปรที่เป็นทางลอจิกไปยัง URL CDN คุณยังสามารถค้นหา URL CDN เองและกำหนดรุ่นเหล่านั้นได้เช่นกัน ตัวอย่างเช่นหากคุณต้องการใช้ Skypack สำหรับ React คุณสามารถเพิ่มต่อไปนี้ใน config/importmap.rb:

pin "react", to: "https://cdn.skypack.dev/react"

3.4 การโหลดก่อนใช้งานโมดูลที่กำหนดรุ่น

เพื่อหลีกเลี่ยงปัญหาที่เกิดจากการโหลดไฟล์หลังไฟล์หนึ่งหลังไฟล์อื่นก่อนที่จะเข้าถึงการนำเข้าที่ซ้อนกันลึกที่สุด เครื่องมือ importmap-rails รองรับลิงก์การโหลดโมดูล (modulepreload links) โมดูลที่กำหนดรุ่นสามารถโหลดก่อนโดยเพิ่ม preload: true ในการกำหนดรุ่น

เป็นไอเดียที่ดีที่จะโหลดไลบรารีหรือเฟรมเวิร์กที่ใช้ในแอปของคุณทั้งหมด เนื่องจากสิ่งนี้จะบอกเบราว์เซอร์ให้ดาวน์โหลดไฟล์เหล่านั้นก่อน

ตัวอย่าง:

# config/importmap.rb
pin "@github/hotkey", to: "https://ga.jspm.io/npm:@github/[email protected]/dist/index.js", preload: true
pin "md5", to: "https://cdn.jsdelivr.net/npm/[email protected]/md5.js"

# app/views/layouts/application.html.erb
<%= javascript_importmap_tags %>

# จะรวมลิงก์ต่อไปนี้ก่อนที่จะตั้งค่า importmap:
<link rel="modulepreload" href="https://ga.jspm.io/npm:@github/[email protected]/dist/index.js">
...

หมายเหตุ: อ้างอิง importmap-rails สำหรับเอกสารที่อัปเดตล่าสุด

4 วิธีใช้ Sprockets

วิธีที่ไม่รู้จักที่จะเปิดเผยทรัพยากรแอปของคุณให้กับเว็บคือการเก็บไว้ในโฟลเดอร์ย่อยของโฟลเดอร์ public เช่น images และ stylesheets การทำเช่นนั้นด้วยตนเองจะยากเนื่องจากแอปเว็บที่ทันสมัยส่วนใหญ่ต้องการให้ทรัพยากรถูกประมวลผลในวิธีที่เฉพาะเจาะจง เช่นการบีบอัดและเพิ่มลายนิ้วมือลงในทรัพยากร

Sprockets ถูกออกแบบให้ประมวลผลทรัพยากรของคุณที่เก็บไว้ในไดเรกทอรีที่กำหนดและหลังจากการประมวลผลจะเปิดเผยในโฟลเดอร์ public/assets พร้อมกับการเพิ่มลายนิ้วมือ การบีบอัด การสร้างแผนที่แหล่งกำเนิดและคุณสมบัติที่กำหนดได้อื่น ๆ

ทรัพยากรยังคงอยู่ในโครงสร้างของ public ได้ ทรัพยากรใด ๆ ภายใต้ public จะถูกให้บริการเป็นไฟล์สถิตเมื่อ config.public_file_server.enabled ถูกตั้งค่าเป็น true คุณต้องกำหนดคำสั่ง manifest.js สำหรับไฟล์ที่ต้องผ่านการประมวลผลก่อนที่จะให้บริการ

ในโปรดักชัน Rails จะทำการคอมไพล์ไฟล์เหล่านี้เป็น public/assets เป็นค่าเริ่มต้น สำเนาที่คอมไพล์ไว้จะถูกให้บริการเป็นทรัพยากรสถิตโดยเว็บเซิร์ฟเวอร์ ไฟล์ใน app/assets จะไม่ถูกให้บริการโดยตรงในโปรดักชัน

4.1 ไฟล์และคำสั่ง Manifest

เมื่อคอมไพล์แอสเซ็ตด้วย Sprockets จะต้องตัดสินใจว่าจะคอมไพล์เป้าหมายระดับบนไหน เช่น application.css และรูปภาพ ระดับบนถูกกำหนดในไฟล์ manifest.js ของ Sprockets โดยค่าเริ่มต้นจะมีรูปแบบดังนี้:

//= link_tree ../images
//= link_directory ../stylesheets .css
//= link_tree ../../javascript .js
//= link_tree ../../../vendor/javascript .js

มันประกอบด้วย คำสั่ง - คำสั่งที่บอก Sprockets ว่าจะต้องการไฟล์ใดในการสร้างไฟล์ CSS หรือ JavaScript เดียว

สิ่งนี้จะรวมเนื้อหาของไฟล์ทั้งหมดที่พบในไดเรกทอรี ./app/assets/images หรือในไดเรกทอรีย่อย ๆ รวมถึงไฟล์ใด ๆ ที่รู้จักว่าเป็น JS โดยตรงที่ ./app/javascript หรือ ./vendor/javascript

มันจะโหลด CSS จากไดเรกทอรี ./app/assets/stylesheets (ไม่รวมไดเรกทอรีย่อย) ถ้าคุณมีไฟล์ application.css และ marketing.css ในโฟลเดอร์ ./app/assets/stylesheets มันจะช่วยให้คุณโหลดสไตล์ชีตเหล่านั้นด้วย <%= stylesheet_link_tag "application" %> หรือ <%= stylesheet_link_tag "marketing" %> จากมุมมองของคุณ

คุณอาจสังเกตเห็นว่าไฟล์ JavaScript ของเราไม่ได้โหลดจากไดเรกทอรี assets โดยค่าเริ่มต้น นั่นเพราะ ./app/javascript เป็นจุดเริ่มต้นเริ่มต้นสำหรับแพคเกจ importmap-rails และโฟลเดอร์ vendor เป็นสถานที่ที่แพคเกจ JS ที่ดาวน์โหลดจะถูกเก็บไว้

ใน manifest.js คุณยังสามารถระบุคำสั่ง link เพื่อโหลดไฟล์เฉพาะแทนทั้งโฟลเดอร์ คำสั่ง link ต้องระบุนามสกุลไฟล์โดยชัดเจน

Sprockets โหลดไฟล์ที่ระบุ ประมวลผลไฟล์ตามความจำเป็น รวมไฟล์เป็นไฟล์เดียว แล้วบีบอัดไฟล์ (ขึ้นอยู่กับค่า config.assets.css_compressor หรือ config.assets.js_compressor) การบีบอัดลดขนาดไฟล์ ทำให้เบราว์เซอร์สามารถดาวน์โหลดไฟล์ได้เร็วขึ้น

4.2 แอสเซ็ตที่เฉพาะเจาะจงตามคอนโทรลเลอร์

เมื่อคุณสร้างสเก็ตโครงสร้างหรือคอนโทรลเลอร์ Rails ยังจะสร้างไฟล์ Cascading Style Sheet สำหรับคอนโทรลเลอร์นั้นด้วย นอกจากนี้ เมื่อสร้างสเก็ต Rails จะสร้างไฟล์ scaffolds.css ด้วย

ตัวอย่างเช่น ถ้าคุณสร้าง ProjectsController Rails ยังจะเพิ่มไฟล์ใหม่ที่ app/assets/stylesheets/projects.css โดยค่าเริ่มต้นไฟล์เหล่านี้จะพร้อมใช้งานโดยแอปพลิเคชันของคุณทันทีโดยใช้คำสั่ง link_directory ในไฟล์ manifest.js

คุณยังสามารถเลือกที่จะรวมไฟล์สไตล์ชีตที่เฉพาะเจาะจงของคอนโทรลเลอร์เท่านั้นในคอนโทรลเลอร์ที่เกี่ยวข้องโดยใช้:

<%= stylesheet_link_tag params[:controller] %>

เมื่อทำเช่นนี้ ตรวจสอบให้แน่ใจว่าคุณไม่ได้ใช้คำสั่ง require_tree ใน application.css เพราะอาจทำให้แอสเซ็ตที่เฉพาะเจาะจงของคอนโทรลเลอร์ของคุณถูกนำเข้ามากกว่าหนึ่งครั้ง

4.3 การจัดระเบียบแอสเซ็ต

แอสเซ็ตของพายพลายน์สามารถวางไว้ในแอปพลิเคชันได้ในหนึ่งในสามตำแหน่ง: app/assets, lib/assets หรือ vendor/assets

  • app/assets ใช้สำหรับแอสเซ็ตที่เป็นเจ้าของโดยแอปพลิเคชัน เช่น รูปภาพหรือสไตล์ชีตที่กำหนดเอง

  • app/javascript ใช้สำหรับโค้ด JavaScript ของคุณ

  • vendor/[assets|javascript] ใช้สำหรับแอสเซ็ตที่เป็นเจ้าของโดยหน่วยงานภายนอก เช่น CSS frameworks หรือ Javascript libraries โปรดทราบว่าโค้ดจากบุคคลที่สามที่มีการอ้างอิงไปยังไฟล์อื่น ๆ ที่ผ่านการประมวลผลโดย Pipeline แอสเซ็ต (รูปภาพ สไตล์ชีต เป็นต้น) จะต้องถูกเขียนใหม่ใช้ช่วยเหลือเช่น asset_path

สถานที่อื่น ๆ สามารถกำหนดค่าได้ในไฟล์ manifest.js อ้างอิงไปที่ ไฟล์และคำสั่ง Manifest

4.3.1 พาธการค้นหา

เมื่อไฟล์ถูกอ้างอิงจาก manifest หรือ helper Sprockets จะค้นหาในทุกตำแหน่งที่ระบุใน manifest.js คุณสามารถดูพาธการค้นหาได้โดยตรวจสอบ Rails.application.config.assets.paths ในคอนโซลของ Rails

4.3.2 การใช้ไฟล์ดัชนีเป็นพร็อกซี่สำหรับโฟลเดอร์

Sprockets ใช้ไฟล์ที่ชื่อว่า index (พร้อมกับส่วนขยายที่เกี่ยวข้อง) สำหรับวัตถุประสงค์ที่เฉพาะเจาะจง

ตัวอย่างเช่น หากคุณมีไลบรารี CSS ที่มีโมดูลหลายๆ โมดูล ซึ่งเก็บอยู่ใน lib/assets/stylesheets/library_name ไฟล์ lib/assets/stylesheets/library_name/index.css จะเป็นไฟล์เรียกข้อมูลสำหรับไฟล์ทั้งหมดในไลบรารีนี้ ไฟล์นี้สามารถรวมรายการของไฟล์ที่จำเป็นทั้งหมดตามลำดับ หรือใช้คำสั่ง require_tree อย่างง่าย

นอกจากนี้ มันคล้ายกับวิธีที่ไฟล์ใน public/library_name/index.html สามารถเข้าถึงได้โดยการร้องขอไปที่ /library_name นี้หมายความว่าคุณไม่สามารถใช้ไฟล์ดัชนีโดยตรงได้

ไลบรารีทั้งหมดสามารถเข้าถึงได้ในไฟล์ .css ดังนี้:

/* ...
*= require library_name
*/

สิ่งนี้ทำให้ง่ายต่อการบำรุงรักษาและรักษาความสะอาดโดยการรวมรหัสที่เกี่ยวข้องกันก่อนนำเข้าไปใช้ที่อื่น

4.4 การเขียนลิงก์ไปยังทรัพยากร

Sprockets ไม่เพิ่มเมธอดใดๆ เพื่อเข้าถึงทรัพยากรของคุณ - คุณยังคงใช้ stylesheet_link_tag ที่คุ้นเคย:

<%= stylesheet_link_tag "application", media: "all" %>

หากใช้แพ็กเกจ turbo-rails ซึ่งรวมมาพร้อมกับ Rails โดยค่าเริ่มต้น ให้รวมตัวเลือก data-turbo-track ซึ่งทำให้ Turbo ตรวจสอบว่าทรัพยากรได้รับการอัปเดตหรือไม่ และหากอัปเดตแล้วจะโหลดเข้าสู่หน้า:

<%= stylesheet_link_tag "application", "data-turbo-track": "reload" %>

ในมุมมองปกติคุณสามารถเข้าถึงรูปภาพในไดเรกทอรี app/assets/images ได้ดังนี้:

<%= image_tag "rails.png" %>

โดยเงื่อนไขคือต้องเปิดใช้งานไฟล์แหล่งทรัพยากรภายในแอปพลิเคชันของคุณ (และไม่ได้ปิดใช้งานในบริบทของสภาพแวดล้อมปัจจุบัน) ไฟล์นี้จะถูกให้บริการโดย Sprockets หากมีไฟล์อยู่ที่ public/assets/rails.png จะให้บริการโดยเว็บเซิร์ฟเวอร์

หรือจะร้องขอไฟล์ที่มี SHA256 hash เช่น public/assets/rails-f90d8a84c707a8dc923fca1ca1895ae8ed0a09237f6992015fef1e11be77c023.png ก็จะถูกจัดการเช่นเดียวกัน วิธีการสร้างเลข hash เหล่านี้จะถูกกล่าวถึงในส่วน ในโหมดการใช้งานจริง ในคู่มือนี้

รูปภาพยังสามารถจัดระเบียบในโฟลเดอร์ย่อยได้ตามต้องการ และจากนั้นสามารถเข้าถึงได้โดยระบุชื่อของโฟลเดอร์ในแท็ก:

<%= image_tag "icons/rails.png" %>

คำเตือน: หากคุณกำลังเตรียมคอมไพล์ทรัพยากรของคุณ (ดูที่ ในโหมดการใช้งานจริง ด้านล่าง) การเชื่อมโยงไปยังทรัพยากรที่ไม่มีอยู่จะเกิดข้อยกเว้นในหน้าที่เรียกใช้ ซึ่งรวมถึงการเชื่อมโยงไปยังสตริงว่าง ดังนั้น โปรดใช้ image_tag และช่วยเหลืออื่นๆ ด้วยข้อมูลที่ได้รับจากผู้ใช้ในลักษณะนี้อย่างระมัดระวัง

4.4.1 CSS และ ERB

ไฟล์ทรัพยากรจะประเมินค่า ERB โดยอัตโนมัติ นั่นหมายความว่าหากคุณเพิ่มส่วนขยาย erb ให้กับทรัพยากร CSS (ตัวอย่างเช่น application.css.erb) จะสามารถใช้ตัวช่วยเช่น asset_path ในกฎ CSS ของคุณได้:

.class { background-image: url(<%= asset_path 'image.png' %>) }

ส่วนนี้จะเขียนเส้นทางไปยังทรัพยากรที่เฉพาะเจาะจงที่กำลังถูกอ้างอิง ในตัวอย่างนี้ มันจะเหมาะสมกับการมีรูปภาพในหนึ่งในเส้นทางทรัพยากร เช่น app/assets/images/image.png ซึ่งจะถูกอ้างอิงที่นี่ หากรูปภาพนี้มีอยู่แล้วใน public/assets เป็นไฟล์ที่มี fingerprint จะอ้างอิงเส้นทางนั้น

หากคุณต้องการใช้ data URI - วิธีการฝังข้อมูลรูปภาพโดยตรงลงในไฟล์ CSS - คุณสามารถใช้ตัวช่วย asset_data_uri ได้

#logo { background: url(<%= asset_data_uri 'logo.png' %>) }

นี้แทรก URI ข้อมูลที่จัดรูปแบบถูกต้องเข้าไปในแหล่งที่มาของ CSS

โปรดทราบว่าแท็กปิดไม่สามารถเป็นแบบ -%> ได้

4.5 เรียกข้อผิดพลาดเมื่อไม่พบทรัพยากร

หากคุณใช้ sprockets-rails >= 3.2.0 คุณสามารถกำหนดการกระทำเมื่อมีการค้นหาทรัพยากรและไม่พบอะไรได้ หากคุณปิด "การสำรองทรัพยากร" จะเกิดข้อผิดพลาดเมื่อไม่พบทรัพยากร

config.assets.unknown_asset_fallback = false

หากเปิดใช้งาน "การสำรองทรัพยากร" เมื่อไม่พบทรัพยากรเส้นทางจะถูกแสดงออกมาแทนและไม่เกิดข้อผิดพลาด พฤติกรรมการสำรองทรัพยากรถูกปิดใช้งานโดยค่าเริ่มต้น

4.6 ปิดการใช้งาน Digests

คุณสามารถปิดการใช้งาน digests ได้โดยการอัปเดต config/environments/development.rb เพื่อรวมเข้าไปใน:

config.assets.digest = false

เมื่อตัวเลือกนี้เป็นจริง digests จะถูกสร้างขึ้นสำหรับ URL ทรัพยากร

4.7 เปิดใช้งาน Source Maps

คุณสามารถเปิดใช้งานแผนที่แหล่งที่มาโดยการอัปเดต config/environments/development.rb เพื่อรวมเข้าไปใน:

config.assets.debug = true

เมื่อโหมดการแก้จุดบกพร่องเปิดอยู่ Sprockets จะสร้าง Source Map สำหรับแต่ละทรัพยากร นี้ช่วยให้คุณสามารถแก้ไขแต่ละไฟล์แยกต่างหากในเครื่องมือนักพัฒนาของเบราว์เซอร์ของคุณ

ทรัพยากรถูกคอมไพล์และแคชในคำขอครั้งแรกหลังจากเซิร์ฟเวอร์เริ่มทำงาน Sprockets ตั้งค่า must-revalidate Cache-Control HTTP header เพื่อลดการขอข้อมูลเพิ่มเติมในคำขอถัดไป - ในกรณีนี้เบราว์เซอร์จะได้รับการตอบกลับ 304 (ไม่มีการเปลี่ยนแปลง)

หากมีไฟล์ใดไฟล์หนึ่งในแผนการเปลี่ยนระหว่างคำขอ เซิร์ฟเวอร์จะตอบกลับด้วยไฟล์ที่คอมไพล์ใหม่

5 ในการใช้งานจริง

ในสภาพแวดล้อมการใช้งานจริง Sprockets ใช้รูปแบบ fingerprinting ตามที่ได้กล่าวไว้ข้างต้น โดยค่าเริ่มต้น Rails ถือว่าทรัพยากรได้รับการคอมไพล์ล่วงหน้าและจะถูกให้บริการเป็นทรัพยากรแบบสถิตย์โดยเซิร์ฟเวอร์เว็บของคุณ

ในขั้นตอนการคอมไพล์ล่วงหน้า SHA256 จะถูกสร้างขึ้นจากเนื้อหาของไฟล์ที่คอมไพล์และแทรกเข้าไปในชื่อไฟล์เมื่อเขียนลงบนดิสก์ ชื่อที่มี fingerprint นี้จะถูกใช้โดยช่วยเหลือของ Rails แทนชื่อแผนการ

ตัวอย่างเช่นนี้:

<%= stylesheet_link_tag "application" %>

จะสร้างสิ่งที่คล้ายกับนี้:

<link href="/assets/application-4dd5b109ee3439da54f5bdfd78a80473.css" rel="stylesheet" />

พฤติกรรมการสร้าง fingerprint ถูกควบคุมโดยตัวเลือก config.assets.digest การเริ่มต้น (ซึ่งมีค่าเริ่มต้นเป็น true)

หมายเหตุ: ภายใต้สถานการณ์ปกติตัวเลือก config.assets.digest เริ่มต้นไม่ควรเปลี่ยนแปลง หากไม่มี digests ในชื่อไฟล์และตั้งค่าส่วนหัวในอนาคตไกล ไคลเอ็นต์ระยะไกลจะไม่รู้ว่าจะต้องเรียกข้อมูลใหม่เมื่อเนื้อหาเปลี่ยนแปลง

5.1 คอมไพล์ล่วงหน้าทรัพยากร

Rails มาพร้อมกับคำสั่งในการคอมไพล์แผนการทรัพยากรและไฟล์อื่น ๆ ในท่อ

ทรัพยากรที่คอมไพล์แล้วจะถูกเขียนลงในตำแหน่งที่ระบุใน config.assets.prefix โดยค่าเริ่มต้นคือไดเรกทอรี /assets

คุณสามารถเรียกใช้คำสั่งนี้บนเซิร์ฟเวอร์ระหว่างการติดตั้งเพื่อสร้างเวอร์ชันที่คอมไพล์ของทรัพยากรของคุณโดยตรงบนเซิร์ฟเวอร์ ดูส่วนถัดไปสำหรับข้อมูลเกี่ยวกับการคอมไพล์ในเครื่อง

คำสั่งคือ:

$ RAILS_ENV=production rails assets:precompile

การเชื่อมโยงโฟลเดอร์ที่ระบุใน config.assets.prefix ไปยัง shared/assets หากคุณใช้โฟลเดอร์ที่ใช้ร่วมกันนี้อยู่แล้วคุณจะต้องเขียนคำสั่งการติดตั้งของคุณเอง

สิ่งสำคัญคือโฟลเดอร์นี้ถูกใช้ร่วมกันระหว่างการติดตั้งเพื่อให้หน้าที่ถูกแคชจากระยะเวลาของหน้าที่ถูกแคชยังทำงานตลอดชีวิตของหน้าที่ถูกแคช หมายเหตุ: ระบุชื่อไฟล์ที่คอมไพล์ที่คาดว่าจะมีนามสกุล .js หรือ .css

คำสั่งยังสร้างไฟล์ .sprockets-manifest-randomhex.json (ที่ randomhex เป็นสตริงฮีกซ์สุ่ม 16 ไบต์) ที่มีรายการทั้งหมดของคุณสินทรัพย์และรหัสลายนิ้วมือที่เกี่ยวข้อง สิ่งนี้ใช้โดยเมธอดช่วยของ Rails เพื่อหลีกเลี่ยงการส่งคำขอแมปกลับไปยัง Sprockets ไฟล์แสดงตัวอย่างประมาณนี้:

{"files":{"application-<fingerprint>.js":{"logical_path":"application.js","mtime":"2016-12-23T20:12:03-05:00","size":412383,
"digest":"<fingerprint>","integrity":"sha256-<random-string>"}},
"assets":{"application.js":"application-<fingerprint>.js"}}

ในแอปพลิเคชันของคุณ จะมีไฟล์และสินทรัพย์อื่น ๆ ที่ระบุในแมนิเฟสต์ <fingerprint> และ <random-string> จะถูกสร้างขึ้นเช่นกัน

ตำแหน่งเริ่มต้นสำหรับแมนิเฟสต์คือรากของตำแหน่งที่ระบุใน config.assets.prefix ('/assets' เป็นค่าเริ่มต้น)

หมายเหตุ: หากมีไฟล์ที่คอมไพล์ไม่ครบถ้วนในการผลิตภัณฑ์ คุณจะได้รับข้อยกเว้น Sprockets::Helpers::RailsHelper::AssetPaths::AssetNotPrecompiledError ที่ระบุชื่อของไฟล์ที่หายไป

5.1.1 ส่วนหัว Expires ในอนาคตที่ไกล

คุณสินทรัพย์ที่คอมไพล์อยู่ในระบบไฟล์และถูกให้บริการโดยเว็บเซิร์ฟเวอร์ของคุณโดยตรง โดยค่าเริ่มต้นไม่มีส่วนหัวในอนาคตที่ไกล ดังนั้นหากต้องการใช้ประโยชน์จากการตรวจสอบลายนิ้วมือคุณต้องอัปเดตการกำหนดค่าเซิร์ฟเวอร์ของคุณเพื่อเพิ่มส่วนหัวเหล่านั้น

สำหรับ Apache:

# คำสั่ง Expires* ต้องการโมดูล Apache
# `mod_expires` ที่เปิดใช้งาน
<Location /assets/>
  # การใช้ ETag ไม่แนะนำเมื่อ Last-Modified มีอยู่
  Header unset ETag
  FileETag None
  # RFC บอกให้แคชเป็นเวลา 1 ปีเท่านั้น
  ExpiresActive On
  ExpiresDefault "access plus 1 year"
</Location>

สำหรับ NGINX:

location ~ ^/assets/ {
  expires 1y;
  add_header Cache-Control public;

  add_header ETag "";
}

5.2 การคอมไพล์ก่อนการใช้งานในเครื่อง

บางครั้งคุณอาจไม่ต้องการหรือไม่สามารถคอมไพล์คุณสินทรัพย์บนเซิร์ฟเวอร์การผลิตได้ เช่น คุณอาจมีการเขียนลดลงในระบบไฟล์ของคุณหรือคุณอาจวางแผนที่จะเผยแพร่บ่อยครั้งโดยไม่มีการเปลี่ยนแปลงใด ๆ ในคุณสินทรัพย์ของคุณ

ในกรณีเช่นนี้คุณสามารถคอมไพล์คุณสินทรัพย์ ในเครื่อง - กล่าวคือเพิ่มคุณสมบัติที่คอมไพล์แล้วพร้อมใช้งานในรหัสซอร์สของคุณก่อนการเผยแพร่ไปยังการผลิต ด้วยวิธีนี้คุณไม่จำเป็นต้องคอมไพล์แยกต่างหากบนเซิร์ฟเวอร์ทุกครั้งที่มีการใช้งาน

เช่นเดียวกับข้างต้นคุณสามารถดำเนินการขั้นตอนนี้โดยใช้

$ RAILS_ENV=production rails assets:precompile

โปรดทราบข้อควรระวังต่อไปนี้:

  • หากคุณสินทรัพย์ที่คอมไพล์พร้อมใช้งาน จะถูกให้บริการ - แม้ว่าจะไม่ตรงกับคุณสินทรัพย์ต้นฉบับ (ที่ยังไม่ได้คอมไพล์) แม้ในเซิร์ฟเวอร์การพัฒนา

    เพื่อให้แน่ใจว่าเซิร์ฟเวอร์การพัฒนาคอมไพล์คุณสินทรัพย์อยู่ในสภาพล่าสุดเสมอ (และดังนั้นสะท้อนสถานะล่าสุดที่สุดของรหัส) สภาพแวดล้อมการพัฒนา ต้องกำหนดค่าให้คอมไพล์คุณสินทรัพย์ไว้ในตำแหน่งที่แตกต่างกันจากการใช้งานในการผลิต มิฉะนั้น คุณสินทรัพย์ที่คอมไพล์สำหรับการใช้งานในการผลิตจะทับคำขอสำหรับการใช้งานในการพัฒนา (เช่น การเปลี่ยนแปลงที่คุณทำกับคุณสินทรัพย์จะไม่สะท้อนในเบราว์เซอร์)

    คุณสามารถทำได้โดยเพิ่มบรรทัดต่อไปนี้ใน config/environments/development.rb:

    config.assets.prefix = "/dev-assets"
    
  • งานคอมไพล์คุณสินทรัพย์ในเครื่อง (เช่น Capistrano) ควรปิดใช้งาน

  • ตัวบีบอัดหรือตัวลดขนาดที่จำเป็นต้องใช้งานต้องมีอยู่ในระบบการพัฒนาของคุณ

คุณยังสามารถตั้งค่า ENV["SECRET_KEY_BASE_DUMMY"] เพื่อเรียกใช้ secret_key_base ที่สร้างขึ้นแบบสุ่มที่เก็บไว้ในไฟล์ชั่วคราว สิ่งนี้เป็นประโยชน์เมื่อคอมไพล์คุณสินทรัพย์สำหรับการผลิตเป็นส่วนหนึ่งของขั้นตอนการสร้างที่ไม่จำเป็นต้องเข้าถึงความลับในการผลิต bash $ SECRET_KEY_BASE_DUMMY=1 bundle exec rails assets:precompile

5.3 การคอมไพล์แบบสด (Live Compilation)

ในบางกรณีคุณอาจต้องการใช้การคอมไพล์แบบสด (live compilation) ในโหมดนี้ การร้องขอสำหรับแอสเซ็ตในไพพลินจะถูกจัดการโดย Sprockets โดยตรง

เพื่อเปิดใช้งานตัวเลือกนี้ ให้ตั้งค่า:

config.assets.compile = true

ในคำขอแรก แอสเซ็ตจะถูกคอมไพล์และแคชตามที่อธิบายไว้ใน Assets Cache Store และชื่อแมนิเฟสต์ที่ใช้ในเฮลเปอร์จะถูกเปลี่ยนแปลงเพื่อรวม SHA256 hash

Sprockets ยังตั้งค่า Cache-Control HTTP header เป็น max-age=31536000 ซึ่งบอกให้แคชทั้งหมดระหว่างเซิร์ฟเวอร์ของคุณและเบราว์เซอร์ของไคลเอนต์ว่าเนื้อหานี้ (ไฟล์ที่ให้บริการ) สามารถแคชได้เป็นเวลา 1 ปี ผลที่ได้คือลดจำนวนคำขอสำหรับแอสเซ็ตนี้จากเซิร์ฟเวอร์ของคุณ แอสเซ็ตมีโอกาสที่จะอยู่ในแคชเบราว์เซอร์ท้องถิ่นหรือแคชกลางบางส่วน

โหมดนี้ใช้หน่วยความจำมากขึ้น ทำงานช้ากว่าค่าเริ่มต้น และไม่แนะนำให้ใช้

5.4 CDN (Content Delivery Network)

CDN หมายถึง Content Delivery Network ซึ่งออกแบบมาเพื่อแคชแอสเซ็ตทั่วโลกเพื่อให้เมื่อเบราว์เซอร์ร้องขอแอสเซ็ต จะมีการคัดลอกที่อยู่ใกล้กับเบราว์เซอร์นั้นทางภูมิภาค หากคุณกำลังให้บริการแอสเซ็ตโดยตรงจากเซิร์ฟเวอร์ Rails ในโหมดการใช้งานจริง ที่ดีที่สุดคือให้ใช้ CDN ข้างหน้าแอปพลิเคชันของคุณ

รูปแบบที่พบบ่อยในการใช้ CDN คือการตั้งค่าแอปพลิเคชันการให้บริการในโหมด "origin" นั่นหมายความว่าเมื่อเบราว์เซอร์ร้องขอแอสเซ็ตจาก CDN และมีการไม่พบแคช จะดึงไฟล์จากเซิร์ฟเวอร์ของคุณแบบ real-time และจากนั้นแคชไฟล์นั้น ตัวอย่างเช่น หากคุณกำลังเรียกใช้แอปพลิเคชัน Rails ที่ example.com และมีการกำหนดค่า CDN ที่ mycdnsubdomain.fictional-cdn.com เมื่อมีคำขอที่เข้ามาที่ mycdnsubdomain.fictional-cdn.com/assets/smile.png CDN จะสอบถามเซิร์ฟเวอร์ของคุณครั้งเดียวที่ example.com/assets/smile.png และแคชคำขอ คำขอถัดไปที่เข้ามาที่ CDN ใน URL เดียวกันจะเข้าถึงสำเนาแคช การเซิร์ฟแอสเซ็ตโดยตรงจาก CDN ไม่เคยสัมผัสเซิร์ฟเวอร์ Rails ของคุณ โดยเนื่องจากแอสเซ็ตจาก CDN อยู่ใกล้กับเบราว์เซอร์ที่ภูมิภาค คำขอจะเร็วขึ้น และเนื่องจากเซิร์ฟเวอร์ของคุณไม่ต้องใช้เวลาในการให้บริการแอสเซ็ต มันสามารถใช้เวลาในการให้บริการโค้ดแอปพลิเคชันได้เร็วที่สุด

5.4.1 การตั้งค่า CDN เพื่อให้บริการแอสเซ็ตแบบคงที่

เพื่อตั้งค่า CDN ของคุณ คุณต้องให้แอปพลิเคชันของคุณทำงานในโหมดการให้บริการจริงบนอินเทอร์เน็ตที่มี URL ที่เปิดให้ใช้งานสาธารณะ เช่น example.com ถัดจากนั้นคุณจะต้องลงทะเบียนใช้บริการ CDN จากผู้ให้บริการโฮสติ้งคลาวด์ เมื่อคุณทำเช่นนี้คุณจะต้องกำหนดค่า "origin" ของ CDN เพื่อชี้กลับไปที่เว็บไซต์ของคุณ example.com ตรวจสอบเอกสารของผู้ให้บริการเพื่อดูคู่มือการกำหนดค่าเซิร์ฟเวอร์ต้นฉบับ

CDN ที่คุณได้รับมอบหมายควรจะให้คุณมีโดเมนย่อยที่กำหนดเองสำหรับแอปพลิเคชันของคุณ เช่น mycdnsubdomain.fictional-cdn.com (โปรดทราบว่า fictional-cdn.com ไม่ใช่ผู้ให้บริการ CDN ที่ถูกต้องในเวลาที่เขียนบทความนี้) ตอนนี้ที่คุณกำหนดค่าเซิร์ฟเวอร์ CDN แล้วคุณต้องแจ้งให้เบราว์เซอร์ใช้ CDN ของคุณในการเรียกใช้แอสเซ็ตแทนที่จะใช้เซิร์ฟเวอร์ Rails ของคุณโดยตรง คุณสามารถทำได้โดยกำหนดค่า asset host ใน Rails โดยตั้งค่า config.asset_host ใน config/environments/production.rb: ruby config.asset_host = 'mycdnsubdomain.fictional-cdn.com' ```

หมายเหตุ: คุณต้องให้ "host" เท่านั้น นี่คือ subdomain และ root domain คุณไม่จำเป็นต้องระบุโปรโตคอลหรือ "scheme" เช่น http:// หรือ https:// เมื่อมีการร้องขอหน้าเว็บ โปรโตคอลในลิงก์ไปยังทรัพยากรของคุณที่ถูกสร้างขึ้นจะตรงกับวิธีการเข้าถึงหน้าเว็บโดยค่าเริ่มต้น

คุณยังสามารถตั้งค่าค่านี้ผ่านตัวแปรสภาพแวดล้อม environment variable เพื่อทำให้การเรียกใช้สำเนาของเว็บไซต์ของคุณง่ายขึ้น:

config.asset_host = ENV['CDN_HOST']

หมายเหตุ: คุณต้องตั้งค่า CDN_HOST บนเซิร์ฟเวอร์ของคุณเป็น mycdnsubdomain.fictional-cdn.com เพื่อให้สามารถทำงานได้

เมื่อคุณตั้งค่าเซิร์ฟเวอร์และ CDN ของคุณ พาธของทรัพยากรจาก helpers เช่น:

<%= asset_path('smile.png') %>

จะถูกแสดงเป็น URL ของ CDN ทั้งหมด เช่น http://mycdnsubdomain.fictional-cdn.com/assets/smile.png (digest ถูกละเว้นเพื่อความอ่านง่าย)

หาก CDN มีสำเนาของ smile.png จะให้บริการให้กับเบราว์เซอร์ และเซิร์ฟเวอร์ของคุณไม่รู้ว่ามีการร้องขอมา หาก CDN ไม่มีสำเนา จะพยายามค้นหาที่ "origin" example.com/assets/smile.png และจัดเก็บไว้สำหรับใช้ในอนาคต

หากคุณต้องการให้บริการเฉพาะบางทรัพยากรจาก CDN ของคุณ คุณสามารถใช้ตัวเลือก :host ที่กำหนดเองใน asset helper ซึ่งจะเขียนทับค่าที่ตั้งไว้ใน config.action_controller.asset_host

<%= asset_path 'image.png', host: 'mycdnsubdomain.fictional-cdn.com' %>

5.4.2 ปรับแต่งพฤติกรรมการแคชของ CDN

CDN ทำงานโดยการแคชเนื้อหา หาก CDN มีเนื้อหาที่เก่าหรือเนื้อหาที่ไม่ถูกต้อง จะทำให้เกิดความเสียหายแทนที่จะช่วยให้แอปพลิเคชันของคุณดีขึ้น วัตถุประสงค์ของส่วนนี้คืออธิบายพฤติกรรมการแคชทั่วไปของ CDN สำหรับผู้ให้บริการที่เฉพาะเจาะจงของคุณอาจมีพฤติกรรมที่แตกต่างเล็กน้อย

5.4.2.1 การแคชคำขอของ CDN

ในขณะที่ CDN ถูกอธิบายว่าดีสำหรับการแคชทรัพยากร แต่จริงๆแล้ว CDN แคชคำขอทั้งหมด ซึ่งรวมถึงเนื้อหาของทรัพยากรและส่วนหัวใดๆ ที่สำคัญที่สุดคือ Cache-Control ซึ่งบอกให้ CDN (และเบราว์เซอร์เว็บ) ทราบวิธีการแคชเนื้อหา นี้หมายความว่าหากมีคนร้องขอทรัพยากรที่ไม่มีอยู่ เช่น /assets/i-dont-exist.png และแอปพลิเคชัน Rails ของคุณส่งคืน 404 แล้ว CDN ของคุณจะแคชหน้า 404 หากมีส่วนหัว Cache-Control ที่ถูกต้อง

5.4.2.2 การตรวจสอบส่วนหัวของ CDN

วิธีหนึ่งในการตรวจสอบว่าส่วนหัวถูกแคชอย่างถูกต้องใน CDN ของคุณคือการใช้ curl คุณสามารถขอส่วนหัวจากเซิร์ฟเวอร์และ CDN ของคุณเพื่อยืนยันว่าเหมือนกัน:

$ curl -I http://www.example/assets/application-
d0e099e021c95eb0de3615fd1d8c4d83.css
HTTP/1.1 200 OK
Server: Cowboy
Date: Sun, 24 Aug 2014 20:27:50 GMT
Connection: keep-alive
Last-Modified: Thu, 08 May 2014 01:24:14 GMT
Content-Type: text/css
Cache-Control: public, max-age=2592000
Content-Length: 126560
Via: 1.1 vegur

เทียบกับสำเนาของ CDN:

$ curl -I http://mycdnsubdomain.fictional-cdn.com/application-
d0e099e021c95eb0de3615fd1d8c4d83.css
HTTP/1.1 200 OK Server: Cowboy Last-
Modified: Thu, 08 May 2014 01:24:14 GMT Content-Type: text/css
Cache-Control:
public, max-age=2592000
Via: 1.1 vegur
Content-Length: 126560
Accept-Ranges:
bytes
Date: Sun, 24 Aug 2014 20:28:45 GMT
Via: 1.1 varnish
Age: 885814
Connection: keep-alive
X-Served-By: cache-dfw1828-DFW
X-Cache: HIT
X-Cache-Hits:
68
X-Timer: S1408912125.211638212,VS0,VE0

ตรวจสอบเอกสารของ CDN ของคุณสำหรับข้อมูลเพิ่มเติมที่อาจมี เช่น X-Cache หรือสำหรับส่วนหัวเพิ่มเติมที่อาจเพิ่มเข้ามา

5.4.2.3 CDNs และ Header ของ Cache-Control

Header Cache-Control ใช้ในการระบุว่า request สามารถถูกเก็บไว้ในแคชได้หรือไม่ ในกรณีที่ไม่มีการใช้ CDN เบราว์เซอร์จะใช้ข้อมูลนี้ในการเก็บแคชเนื้อหา ซึ่งมีประโยชน์มากสำหรับสิ่งที่ไม่ได้ถูกแก้ไข เพื่อให้เบราว์เซอร์ไม่ต้องดาวน์โหลด CSS หรือ JavaScript ของเว็บไซต์ทุกครั้งที่มีการร้องขอ โดยทั่วไปเราต้องการให้เซิร์ฟเวอร์ Rails บอก CDN (และเบราว์เซอร์) ว่าแอสเซ็ตเป็น "public" ซึ่งหมายความว่าแคชใดๆ ก็สามารถเก็บ request ได้ นอกจากนี้เราต้องการกำหนด max-age ซึ่งเป็นระยะเวลาที่แคชจะเก็บวัตถุไว้ก่อนที่จะทำให้แคชเกิดข้อผิดพลาด ค่า max-age ถูกกำหนดเป็นวินาทีโดยมีค่าสูงสุดเป็น 31536000 หรือ 1 ปี คุณสามารถทำได้ในแอปพลิเคชัน Rails ของคุณโดยการตั้งค่าดังนี้

config.public_file_server.headers = {
  'Cache-Control' => 'public, max-age=31536000'
}

ตอนนี้เมื่อแอปพลิเคชันของคุณให้บริการแอสเซ็ตในโหมดการใช้งานจริง CDN จะเก็บแอสเซ็ตไว้เป็นเวลาสูงสุดหนึ่งปี โดยเนื่องจากเกือบทุก CDN ยังเก็บแคชของ header ของ request ด้วย ค่า Cache-Control นี้จะถูกส่งต่อไปยังเบราว์เซอร์ที่มีการร้องขอแอสเซ็ตนี้ในอนาคต จากนั้นเบราว์เซอร์จะทราบว่าสามารถเก็บแอสเซ็ตนี้ไว้เป็นเวลานานมากก่อนที่จะต้องร้องขอใหม่

5.4.2.4 CDNs และการยกเลิกแคชตาม URL

ส่วนใหญ่ CDNs จะเก็บแคชเนื้อหาของแอสเซ็ตตาม URL ทั้งหมด นั่นหมายความว่า request ที่มี URL แบบเต็มเหมือนกัน

http://mycdnsubdomain.fictional-cdn.com/assets/smile-123.png

จะเป็นแคชที่แตกต่างกันอย่างสิ้นเชิงจาก

http://mycdnsubdomain.fictional-cdn.com/assets/smile.png

หากคุณต้องการตั้งค่า max-age ใน Cache-Control ให้มีอายุนาน (และคุณต้องการ) คุณต้องแน่ใจว่าเมื่อคุณเปลี่ยนแอสเซ็ตแล้วแคชของคุณถูกยกเลิก ตัวอย่างเช่นเมื่อคุณเปลี่ยนหน้าตาของรูปแบบใบหน้าจากสีเหลืองเป็นสีน้ำเงิน คุณต้องการให้ผู้เยี่ยมชมเว็บไซต์ของคุณทุกคนได้รับใบหน้าสีน้ำเงินใหม่ ในกรณีที่ใช้ CDN กับไฟล์แอสเซ็ตของ Rails ค่า config.assets.digest จะถูกตั้งค่าเป็น true โดยค่าเริ่มต้น เพื่อให้แต่ละแอสเซ็ตมีชื่อไฟล์ที่แตกต่างกันเมื่อมีการเปลี่ยนแปลง ดังนั้นคุณไม่ต้องยกเลิกแคชด้วยตนเองเลย แต่ใช้ชื่อแอสเซ็ตที่แตกต่างกันเป็นอันดับแทน ผู้ใช้ของคุณจะได้รับแอสเซ็ตล่าสุด

6 การปรับแต่งไฟล์แอสเซ็ต

6.1 การบีบอัด CSS

หนึ่งในตัวเลือกในการบีบอัด CSS คือ YUI โปรแกรมบีบอัด CSS ของ YUI compressor ให้การบีบอัด

บรรทัดต่อไปนี้เปิดใช้งานการบีบอัด YUI และต้องการ gem yui-compressor

config.assets.css_compressor = :yui

6.2 การบีบอัด JavaScript

ตัวเลือกที่เป็นไปได้สำหรับการบีบอัด JavaScript คือ :terser, :closure และ :yui ซึ่งต้องใช้ gem terser, closure-compiler หรือ yui-compressor ตามลำดับ

เราจะใช้ตัวอย่างของ gem terser เป็นตัวอย่าง gem นี้ครอบคลุม Terser (เขียนสำหรับ Node.js) ในรูปแบบของ Ruby โดยการบีบอัดโค้ดของคุณโดยการลบช่องว่างและคอมเมนต์ ย่อชื่อตัวแปรท้องถิ่น และดำเนินการปรับปรุงเล็กน้อยอื่นๆ เช่นการเปลี่ยนคำสั่ง if และ else เป็นตัวดำเนินการเงื่อนไขแบบ ternary ที่เป็นไปได้

บรรทัดต่อไปนี้เรียกใช้ terser สำหรับการบีบอัด JavaScript

config.assets.js_compressor = :terser

หมายเหตุ: คุณจำเป็นต้องมี ExecJS รันไทม์ที่รองรับเพื่อใช้ terser หากคุณใช้ macOS หรือ Windows คุณมี JavaScript runtime ติดตั้งในระบบปฏิบัติการของคุณ หมายเหตุ: การบีบอัด JavaScript จะทำงานได้กับไฟล์ JavaScript ของคุณเมื่อคุณโหลดทรัพยากรของคุณผ่าน importmap-rails หรือ jsbundling-rails gems

6.3 GZipping ทรัพยากรของคุณ

ตามค่าเริ่มต้น จะสร้างเวอร์ชันที่บีบอัดของทรัพยากรที่คอมไพล์ขึ้นมา พร้อมกับเวอร์ชันที่ไม่ได้บีบอัดของทรัพยากร การบีบอัดทรัพยากรช่วยลดการส่งข้อมูลผ่านเครือข่าย คุณสามารถกำหนดค่านี้ได้โดยตั้งค่าตัวแปร gzip

config.assets.gzip = false # ปิดการสร้างทรัพยากรที่บีบอัด

อ่านเอกสารของเว็บเซิร์ฟเวอร์ของคุณเพื่อดูคำแนะนำเกี่ยวกับวิธีการให้บริการทรัพยากรที่ถูกบีบอัด

6.4 ใช้ตัวบีบอัดของคุณเอง

การตั้งค่าการบีบอัดสำหรับ CSS และ JavaScript ยังรองรับอ็อบเจ็กต์ใดๆ ที่มีเมธอด compress ที่รับสตริงเป็นอาร์กิวเมนต์เดียวและต้องส่งคืนสตริง

class Transformer
  def compress(string)
    ทำบางอย่างแล้วส่งคืนสตริง(string)
  end
end

เพื่อเปิดใช้งานนี้ ให้ส่งอ็อบเจ็กต์ใหม่ไปยังตัวเลือกการตั้งค่าใน application.rb:

config.assets.css_compressor = Transformer.new

6.5 เปลี่ยนเส้นทาง assets

เส้นทางสาธารณะที่ Sprockets ใช้ตามค่าเริ่มต้นคือ /assets

สามารถเปลี่ยนเป็นอย่างอื่นได้:

config.assets.prefix = "/some_other_path"

นี่เป็นตัวเลือกที่ดีถ้าคุณกำลังอัปเดตโปรเจกต์ที่เก่ากว่าที่ไม่ได้ใช้ asset pipeline และใช้เส้นทางนี้อยู่แล้ว หรือหากคุณต้องการใช้เส้นทางนี้สำหรับทรัพยากรใหม่

6.6 ส่วนหัว X-Sendfile

ส่วนหัว X-Sendfile เป็นคำสั่งสำหรับเว็บเซิร์ฟเวอร์ให้ละเว้นการตอบสนองจากแอปพลิเคชันและแทนที่ให้บริการไฟล์ที่ระบุจากดิสก์ ตัวเลือกนี้ถูกปิดใช้งานตามค่าเริ่มต้น แต่สามารถเปิดใช้งานได้หากเซิร์ฟเวอร์ของคุณรองรับ หากเปิดใช้งาน ส่วนหน้าที่ในการให้บริการไฟล์จะถูกส่งต่อไปยังเว็บเซิร์ฟเวอร์ซึ่งเร็วกว่า ดูรายละเอียดเพิ่มเติมที่ send_file เกี่ยวกับวิธีการใช้คุณลักษณะนี้

Apache และ NGINX รองรับตัวเลือกนี้ ซึ่งสามารถเปิดใช้งานได้ใน config/environments/production.rb:

# config.action_dispatch.x_sendfile_header = "X-Sendfile" # สำหรับ Apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # สำหรับ NGINX

คำเตือน: หากคุณกำลังอัปเกรดแอปพลิเคชันที่มีอยู่และตั้งใจใช้ตัวเลือกนี้ ให้ใส่ตัวเลือกการตั้งค่านี้เฉพาะใน production.rb และสภาพแวดล้อมอื่นที่คุณกำหนดโดยมีพฤติกรรมเชิงผลิตภาพ (ไม่ใช่ application.rb)

เคล็ดลับ: สำหรับรายละเอียดเพิ่มเติม ดูเอกสารของเว็บเซิร์ฟเวอร์การผลิตของคุณ:

7 การเก็บแคชทรัพยากร

ตามค่าเริ่มต้น Sprockets จะเก็บแคชทรัพยากรใน tmp/cache/assets ในสภาพแวดล้อมการพัฒนาและการผลิต สามารถเปลี่ยนได้ดังนี้:

config.assets.configure do |env|
  env.cache = ActiveSupport::Cache.lookup_store(:memory_store,
                                                { size: 32.megabytes })
end

หากต้องการปิดใช้งานการเก็บแคชทรัพยากร:

config.assets.configure do |env|
  env.cache = ActiveSupport::Cache.lookup_store(:null_store)
end

8 เพิ่มทรัพยากรใน Gems ของคุณ

ทรัพยากรยังสามารถมาจากแหล่งภายนอกในรูปแบบของ gems

ตัวอย่างที่ดีของนี้คือ gem jquery-rails Gem นี้มีคลาสเอ็นจิ้นที่สืบทอดมาจาก Rails::Engine โดยทำเช่นนี้ Rails จะได้รับทราบว่าไดเร็กทอรี่สำหรับ gem นี้อาจมีทรัพยากรและไดเร็กทอรี่ app/assets lib/assets และ vendor/assets ของเอ็นจิ้นนี้ถูกเพิ่มในเส้นทางการค้นหาของ Sprockets

9 ทำให้ไลบรารีหรือ gem ของคุณเป็นตัวก่อนการประมวลผล

Sprockets ใช้ Processors, Transformers, Compressors, และ Exporters เพื่อขยายความสามารถของ Sprockets ดูที่ Extending Sprockets เพื่อเรียนรู้เพิ่มเติม ที่นี่เราลงทะเบียนตัวก่อนการประมวลผลเพื่อเพิ่มคอมเมนต์ที่สิ้นสุดของไฟล์ text/css (.css) ruby module AddComment def self.call(input) { data: input[:data] + "/* สวัสดีจากส่วนขยายของฉันใน Sprockets */" } end end

ตอนนี้ที่คุณมีโมดูลที่แก้ไขข้อมูลนำเข้าแล้ว เป็นเวลาที่จะลงทะเบียน มันเป็นตัวแปรก่อนการประมวลผลสำหรับประเภท MIME ของคุณ

Sprockets.register_preprocessor 'text/css', AddComment

10 ไลบรารีทางเลือก

ในระหว่างหลายปีที่ผ่านมา มีหลายวิธีที่เราใช้ในการจัดการส่วนประกอบ โลกเว็บได้เติบโตขึ้นและเราเริ่มเห็นแอปพลิเคชันที่มี JavaScript หนักมากขึ้น ใน The Rails Doctrine เราเชื่อว่า เมนูคือ Omakase เพื่อนำเสนอการตั้งค่าเริ่มต้น: Sprockets พร้อม Import Maps.

เราตระหนักว่าไม่มีวิธีที่เหมาะสมสำหรับเฟรมเวิร์กและส่วนขยาย JavaScript และ CSS ที่มีอยู่ มีไลบรารีการรวมแพคเกจอื่น ๆ ในนิเวศของ Rails ที่ควรช่วยให้คุณสามารถทำได้ในกรณีที่การตั้งค่าเริ่มต้นไม่เพียงพอ

10.1 jsbundling-rails

jsbundling-rails เป็นตัวเลือกที่ขึ้นอยู่กับ Node.js สำหรับวิธีการรวมแพคเกจ JavaScript ด้วย esbuild, rollup.js หรือ Webpack แทนวิธีการใช้ importmap-rails.

แพคเกจนี้ให้กระบวนการ yarn build --watch เพื่อสร้างเอาท์พุตโดยอัตโนมัติในระหว่างการพัฒนา สำหรับการใช้งานจริง มันจะเชื่อมต่องาน javascript:build เข้ากับงาน assets:precompile เพื่อให้แน่ใจว่าได้ติดตั้งแพคเกจทั้งหมดที่คุณต้องการและได้สร้าง JavaScript สำหรับทุกจุดเริ่มต้น

เมื่อควรใช้แทน importmap-rails? หากโค้ด JavaScript ของคุณขึ้นอยู่กับการแปลงรหัส หากคุณใช้ Babel, TypeScript หรือรูปแบบ React JSX แล้ว jsbundling-rails เป็นวิธีที่ถูกต้อง

10.2 Webpacker/Shakapacker

Webpacker เป็นตัวก่อนประมวลผล JavaScript และตัวรวมสำหรับ Rails 5 และ 6 แต่ตอนนี้ถูกเลิกใช้งานแล้ว มีตัวสืบทอดที่ชื่อ shakapacker อยู่ แต่ไม่ได้รับการดูแลโดยทีมหรือโครงการ Rails

ไม่เหมือนกับไลบรารีอื่นในรายการนี้ webpacker/shakapacker ไม่เกี่ยวข้องกับ Sprockets และสามารถประมวลผลไฟล์ JavaScript และ CSS ได้ทั้งคู่ อ่านคู่มือ Webpacker เพื่อเรียนรู้เพิ่มเติม

หมายเหตุ: อ่านเอกสาร เปรียบเทียบกับ Webpacker เพื่อเข้าใจความแตกต่างระหว่าง jsbundling-rails และ webpacker/shakapacker.

10.3 cssbundling-rails

cssbundling-rails ช่วยให้คุณรวมและประมวลผล CSS ของคุณโดยใช้ Tailwind CSS, Bootstrap, Bulma, PostCSS หรือ Dart Sass แล้วส่ง CSS ผ่านท่อส่งข้อมูล

มันทำงานในลักษณะเดียวกับ jsbundling-rails ดังนั้นจึงเพิ่มความขึ้นอยู่กับ Node.js เข้าสู่แอปพลิเคชันของคุณด้วยกระบวนการ yarn build:css --watch เพื่อสร้างสไตล์ชีทใหม่ในระหว่างการพัฒนาและเชื่อมต่อกับงาน assets:precompile ในการใช้งานจริง

ความแตกต่างกับ Sprockets อย่างไร? Sprockets เองไม่สามารถแปลงรหัส Sass เป็น CSS ได้ จึงต้องใช้ Node.js เพื่อสร้างไฟล์ .css จากไฟล์ .sass ของคุณ เมื่อไฟล์ .css ถูกสร้างขึ้นแล้ว Sprockets จะสามารถส่งมันให้กับไคลเอ็นต์ของคุณได้

หมายเหตุ: cssbundling-rails ขึ้นอยู่กับ Node เพื่อประมวลผล CSS แพคเกจ dartsass-rails และ tailwindcss-rails ใช้เวอร์ชันแยกต่างหากของ Tailwind CSS และ Dart Sass ซึ่งหมายความว่าไม่ต้องใช้ Node หากคุณใช้ importmap-rails เพื่อจัดการกับ Javascript และ dartsass-rails หรือ tailwindcss-rails สำหรับ CSS คุณสามารถหลีกเลี่ยงการใช้งาน Node ได้ซึ่งจะทำให้ได้ระบบที่ซับซ้อนน้อยลง

10.4 dartsass-rails

หากคุณต้องการใช้ Sass ในแอปพลิเคชันของคุณ dartsass-rails เป็นตัวเลือกที่มาแทนที่แพคเกจเดิม sassc-rails ที่ถูกเลิกใช้งานแล้วในปี 2020 และใช้ Dart Sass ที่เป็นตัวแทนของ LibSass ที่ใช้กับ sassc-rails

ไม่เหมือนกับ sassc-rails แพคเกจใหม่นี้ไม่ได้รวมอยู่ใน Sprockets โปรดอ่านหน้าหลักของ แพคเกจ เพื่อดูคำแนะนำในการติดตั้ง/ย้ายข้อมูล คำเตือน: แพ็กเกจ sassc-rails ที่ได้รับความนิยมไม่ได้รับการบำรุงรักษาตั้งแต่ปี 2019

10.5 tailwindcss-rails

tailwindcss-rails เป็นแพ็กเกจ wrapper สำหรับ เวอร์ชัน standalone executable ของเฟรมเวิร์ก Tailwind CSS v3 ใช้สำหรับแอปพลิเคชันใหม่เมื่อใช้ --css tailwind กับคำสั่ง rails new มีการให้บริการกระบวนการ watch เพื่อสร้างเอาต์พุตของ Tailwind โดยอัตโนมัติในระหว่างการพัฒนา สำหรับการใช้งานในโปรดักชันจะเชื่อมต่อกับงาน assets:precompile

ข้อเสนอแนะ

คุณสามารถช่วยปรับปรุงคุณภาพของคู่มือนี้ได้

กรุณาช่วยเพิ่มเติมหากพบข้อผิดพลาดหรือข้อผิดพลาดทางความจริง เพื่อเริ่มต้นคุณสามารถอ่านส่วน การสนับสนุนเอกสาร ของเราได้

คุณอาจพบเนื้อหาที่ไม่สมบูรณ์หรือเนื้อหาที่ไม่ได้อัปเดต กรุณาเพิ่มเอกสารที่ขาดหายไปสำหรับเนื้อหาหลัก โปรดตรวจสอบ Edge Guides ก่อนเพื่อตรวจสอบ ว่าปัญหาได้รับการแก้ไขหรือไม่ในสาขาหลัก ตรวจสอบ คู่มือแนวทาง Ruby on Rails เพื่อดูรูปแบบและกฎเกณฑ์

หากคุณพบข้อผิดพลาดแต่ไม่สามารถแก้ไขได้เอง กรุณา เปิดปัญหา.

และสุดท้าย การสนทนาใด ๆ เกี่ยวกับ Ruby on Rails เอกสารยินดีต้อนรับที่สุดใน เว็บบอร์ดอย่างเป็นทางการของ Ruby on Rails.