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.