애셋 파이프라인

이 가이드는 애셋 파이프라인을 다룹니다.

이 가이드를 읽고 나면 다음을 알 수 있습니다:

  • 애셋 파이프라인이 무엇이며 무엇을 하는지.
  • 애플리케이션 애셋을 적절하게 구성하는 방법.
  • 애셋 파이프라인의 이점.
  • 파이프라인에 전처리기를 추가하는 방법.
  • 젬으로 애셋을 패키징하는 방법.

애셋 파이프라인이란 무엇인가?

애셋 파이프라인은 JavaScript와 CSS 애셋의 전달을 처리하는 프레임워크입니다. 이는 HTTP/2와 같은 기술과 연결 및 축소와 같은 기술을 활용하여 수행됩니다. 마지막으로 애플리케이션이 다른 젬의 애셋과 자동으로 결합될 수 있습니다.

애셋 파이프라인은 importmap-rails, sprocketssprockets-rails 젬에 의해 구현되며 기본적으로 활성화됩니다. 새 애플리케이션을 만들 때 --skip-asset-pipeline 옵션을 전달하여 비활성화할 수 있습니다.

$ rails new appname --skip-asset-pipeline

주의: 이 가이드는 CSS의 경우 sprockets만, JavaScript의 경우 importmap-rails만 사용하는 기본 애셋 파이프라인에 초점을 맞춥니다. 이 두 가지의 주요 제한은 트랜스파일링을 지원하지 않는다는 것입니다. 따라서 Babel, TypeScript, Sass, React JSX 형식 또는 Tailwind CSS와 같은 것을 사용할 수 없습니다. 대체 라이브러리 섹션을 읽어보시기 바랍니다.

주요 기능

애셋 파이프라인의 첫 번째 기능은 각 파일 이름에 SHA256 지문을 삽입하여 웹 브라우저와 CDN에 의해 캐싱되도록 하는 것입니다. 이 지문은 파일 내용이 변경될 때 자동으로 업데이트되어 캐시를 무효화합니다.

애셋 파이프라인의 두 번째 기능은 import maps를 사용하여 JavaScript 파일을 제공하는 것입니다. 이를 통해 ES 모듈(ESM)용으로 만들어진 JavaScript 라이브러리를 트랜스파일링과 번들링 없이 사용할 수 있습니다. 결과적으로 Webpack, yarn, node 또는 JavaScript 도구 체인의 다른 부분이 필요하지 않습니다.

애셋 파이프라인의 세 번째 기능은 모든 CSS 파일을 하나의 메인 .css 파일로 결합하고 이를 축소하거나 압축하는 것입니다. 이 전략은 나중에 이 가이드에서 설명하는 대로 파일을 원하는 방식으로 그룹화할 수 있습니다. 프로덕션에서 Rails는 각 파일 이름에 SHA256 지문을 삽입하여 웹 브라우저에 의해 캐싱되도록 합니다. 파일 내용을 변경하면 이 지문이 자동으로 변경되어 캐시를 무효화할 수 있습니다.

애셋 파이프라인의 네 번째 기능은 CSS에 대한 고급 언어를 통해 애셋을 코딩할 수 있게 해줍니다.

지문이란 무엇이며 왜 중요한가?

지문은 파일 내용에 따라 파일 이름이 달라지는 기술입니다. 파일 내용이 변경되면 파일 이름도 변경됩니다. 정적이거나 자주 변경되지 않는 콘텐츠의 경우 이 방법을 사용하면 다른 서버나 배포 날짜에도 두 파일 버전이 동일한지 쉽게 알 수 있습니다.

콘텐츠에 따라 고유하고 고유한 파일 이름을 사용하면 HTTP 헤더를 설정하여 CDN, ISP, 네트워킹 장비 또는 웹 브라우저 등 모든 캐시가 자체 사본을 보관하도록 할 수 있습니다. 콘텐츠가 업데이트되면 지문이 변경됩니다. 이로 인해 원격 클라이언트가 새 사본을 요청하게 됩니다. 이를 일반적으로 캐시 무효화라고 합니다.

Sprockets가 사용하는 지문 기술은 내용의 해시를 일반적으로 이름 끝에 삽입하는 것입니다. 예를 들어 CSS 파일 global.css는 다음과 같습니다.

global-908e25f4bf641868d8683022a5b62f54.css

이것이 Rails 애셋 파이프라인이 채택한 전략입니다.

지문은 기본적으로 개발 및 프로덕션 환경에 대해 활성화됩니다. config.assets.digest 옵션을 통해 활성화하거나 비활성화할 수 있습니다.

Import Maps란 무엇이며 왜 중요한가?

Import Maps를 사용하면 논리적 이름을 사용하여 JavaScript 모듈을 직접 브라우저에서 가져올 수 있습니다. 이 이름은 버전화된/지문화된 파일에 매핑됩니다. 따라서 트랜스파일링이나 번들링 없이도 ES 모듈(ESM)용으로 만들어진 JavaScript 라이브러리를 사용하여 현대적인 JavaScript 애플리케이션을 구축할 수 있습니다.

이 접근 방식에서는 하나의 큰 JavaScript 파일 대신 많은 작은 JavaScript 파일을 보냅니다. HTTP/2 덕분에 초기 전송 중에 더 이상 중요한 성능 저하가 없으며 장기적으로 더 나은 캐싱 동적으로 인해 상당한 이점을 제공합니다.

JavaScript 애셋 파이프라인으로 Import Maps 사용하기

Import Maps는 기본 JavaScript 프로세서이며 import map 생성 로직은 importmap-rails 젬에서 처리합니다.

경고: Import Maps는 JavaScript 파일에만 사용되며 CSS 전달에는 사용할 수 없습니다. CSS에 대해서는 Sprockets 섹션을 참조하세요.

사용 지침은 젬 홈페이지에서 자세히 확인할 수 있지만 importmap-rails의 기본 사항을 이해하는 것이 중요합니다.

작동 방식

Import Maps는 일반적으로 “bare module specifiers"라고 하는 것에 대한 문자열 대체입니다. 이를 통해 JavaScript 모듈 가져오기의 이름을 표준화할 수 있습니다.

예를 들어 다음과 같은 가져오기 정의가 있습니다. Import Map 없이는 작동하지 않습니다:

import React from "react"

Import Map을 사용하려면 다음과 같이 정의해야 합니다:

import React from "https://ga.jspm.io/npm:react@17.0.2/index.js"

여기에 Import Map이 등장합니다. react 이름을 https://ga.jspm.io/npm:react@17.0.2/index.js 주소에 고정시킵니다. 이러한 정보로 브라우저는 간단한 import React from "react" 정의를 허용합니다. Import Map을 라이브러리 소스 주소에 대한 별칭으로 생각하면 됩니다.

사용법

importmap-rails를 사용하면 라이브러리 경로를 이름에 고정하는 Import Map 구성 파일을 만들 수 있습니다:

# config/importmap.rb
pin "application"
pin "react", to: "https://ga.jspm.io/npm:react@17.0.2/index.js"

구성된 모든 Import Map은 <%= javascript_importmap_tags %> 를 추가하여 애플리케이션의 <head> 요소에 연결해야 합니다. javascript_importmap_tagshead 요소에 다음과 같은 스크립트를 렌더링합니다:

  • 구성된 모든 Import Map이 포함된 JSON:
<script type="importmap">
{
  "imports": {
    "application": "/assets/application-39f16dc3f3....js"
    "react": "https://ga.jspm.io/npm:react@17.0.2/index.js"
  }
}
</script>
  • app/javascript/application.js에서 JavaScript를 로드하는 진입점:
<script type="module">import "application"</script>

주의: v2.0.0 이전에는 importmap-rails가 Import Maps에 대한 지원을 보장하기 위해 Es-module-shimsjavascript_importmap_tags 출력에 포함했습니다. 그러나 주요 브라우저의 Import Maps에 대한 기본 지원으로 인해 v2.0.0에서는 번들된 shim이 제거되었습니다. 레거시 브라우저(iOS 15의 Safari 등)를 지원하려면 수동으로 Es-module-shimsjavascript_importmap_tags 앞에 삽입해야 합니다. 자세한 내용은 importmap-rails README를 참조하세요.

JavaScript CDN을 통해 npm 패키지 사용하기

importmap-rails 설치의 일부로 추가된 bin/importmap 명령을 사용하여 Import Map에 npm 패키지를 고정, 고정 해제 또는 업데이트할 수 있습니다. 이 binstub은 JSPM.org를 사용합니다.

다음과 같이 작동합니다:

$ bin/importmap pin react react-dom
Pinning "react" to https://ga.jspm.io/npm:react@17.0.2/index.js
Pinning "react-dom" to https://ga.jspm.io/npm:react-dom@17.0.2/index.js
Pinning "object-assign" to https://ga.jspm.io/npm:object-assign@4.1.1/index.js
Pinning "scheduler" to https://ga.jspm.io/npm:scheduler@0.20.2/index.js

bin/importmap json

{
  "imports": {
    "application": "/assets/application-37f365cbecf1fa2810a8303f4b6571676fa1f9c56c248528bc14ddb857531b95.js",
    "react": "https://ga.jspm.io/npm:react@17.0.2/index.js",
    "react-dom": "https://ga.jspm.io/npm:react-dom@17.0.2/index.js",
    "object-assign": "https://ga.jspm.io/npm:object-assign@4.1.1/index.js",
    "scheduler": "https://ga.jspm.io/npm:scheduler@0.20.2/index.js"
  }
}

보시다시피 react와 react-dom 두 개의 패키지가 총 네 개의 종속성으로 해결됩니다. jspm 기본값을 통해 해결됩니다.

이제 application.js 진입점에서 다른 모듈처럼 이를 사용할 수 있습니다:

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

특정 버전을 고정할 수도 있습니다:

$ bin/importmap pin react@17.0.1
Pinning "react" to https://ga.jspm.io/npm:react@17.0.1/index.js
Pinning "object-assign" to https://ga.jspm.io/npm:object-assign@4.1.1/index.js

또는 고정을 해제할 수도 있습니다:

$ bin/importmap unpin react
Unpinning "react"
Unpinning "object-assign"

패키지에 네, 계속해서 번역하겠습니다.

패키지에 별도의 "production”(기본값) 및 “development” 빌드가 있는 경우 환경을 제어할 수 있습니다:

$ bin/importmap pin react --env development
Pinning "react" to https://ga.jspm.io/npm:react@17.0.2/dev.index.js
Pinning "object-assign" to https://ga.jspm.io/npm:object-assign@4.1.1/index.js

또한 고정할 때 unpkg 또는 jsdelivr 등 다른 지원되는 CDN 공급자를 선택할 수 있습니다(jspm이 기본값):

$ bin/importmap pin react --from jsdelivr
Pinning "react" to https://cdn.jsdelivr.net/npm/react@17.0.2/index.js

그러나 한 공급자에서 다른 공급자로 핀을 전환하는 경우 첫 번째 공급자에서 추가된 종속성을 정리해야 할 수 있습니다.

bin/importmap을 실행하여 모든 옵션을 확인하세요.

이 명령은 논리적 패키지 이름을 CDN URL로 확인하는 편의 래퍼일 뿐입니다. CDN URL을 직접 조회한 다음 고정할 수도 있습니다. 예를 들어 Skypack을 사용하여 React를 사용하려면 다음과 같이 config/importmap.rb에 추가할 수 있습니다:

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

고정된 모듈 사전 로드하기

브라우저가 하나의 파일을 다른 파일 다음에 로드해야 하는 폭포 효과를 피하기 위해 importmap-rails는 modulepreload 링크를 지원합니다. 고정된 모듈은 핀에 preload: true를 추가하여 사전 로드될 수 있습니다.

전체 앱에서 사용되는 라이브러리나 프레임워크를 사전 로드하는 것이 좋습니다. 이렇게 하면 브라우저가 이를 더 빨리 다운로드할 수 있습니다.

예:

# config/importmap.rb
pin "@github/hotkey", to: "https://ga.jspm.io/npm:@github/hotkey@1.4.4/dist/index.js", preload: true
pin "md5", to: "https://cdn.jsdelivr.net/npm/md5@2.3.0/md5.js"
<%# app/views/layouts/application.html.erb %>
<%= javascript_importmap_tags %>

<%# Import Map이 설정되기 전에 다음 링크가 포함됩니다: %>
<link rel="modulepreload" href="https://ga.jspm.io/npm:@github/hotkey@1.4.4/dist/index.js">
...

주의: 가장 최신 문서는 importmap-rails 리포지토리를 참조하세요.

Sprockets 사용하기

웹에 애플리케이션 애셋을 노출하는 가장 단순한 방법은 public 폴더의 하위 디렉토리(예: imagesstylesheets)에 저장하는 것입니다. 그렇게 하면 대부분의 현대 웹 애플리케이션에 필요한 애셋을 특정 방식으로 처리하기 어려울 것입니다(예: 압축 및 애셋에 지문 추가).

Sprockets은 구성된 디렉토리에 저장된 애셋을 자동으로 전처리하고 지문, 압축, 소스 맵 생성 및 기타 구성 가능한 기능을 적용하여 public/assets 폴더에 노출하도록 설계되었습니다.

애셋은 여전히 public 계층 구조에 배치될 수 있습니다. public 아래의 모든 애셋은 config.public_file_server.enabled이 true로 설정된 경우 애플리케이션 또는 웹 서버에 의해 정적 파일로 제공됩니다. 전처리를 거쳐야 하는 파일에 대해 manifest.js 지시문을 정의해야 합니다.

프로덕션에서 Rails는 기본적으로 이 파일을 public/assets에 사전 컴파일합니다. 사전 컴파일된 사본은 그 다음 정적 애셋으로 웹 서버에 의해 제공됩니다. app/assets 파일은 프로덕션에서 직접 제공되지 않습니다.

매니페스트 파일 및 지시문

Sprockets으로 애셋을 컴파일할 때 Sprockets는 일반적으로 application.css 및 이미지와 같은 최상위 대상을 컴파일해야 합니다. 최상위 대상은 기본적으로 Sprockets manifest.js 파일에 정의됩니다. 이 파일은 다음과 같습니다:

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

이 파일에는 지시문 - Sprockets에 어떤 파일을 요구해야 하는지 알려주는 지침 - 이 포함되어 있습니다.

이는 ./app/assets/images 디렉토리 또는 하위 디렉토리에 있는 모든 파일의 내용을 포함하고 ./app/javascript 또는 ./vendor/javascript에 직접 있는 모든 JS 파일을 로드하도록 의도된 것입니다.

./app/assets/stylesheets 디렉토리(하위 디렉토리 제외)의 모든 CSS를 로드합니다. ./app/assets/stylesheets 폴더에 application.cssmarketing.css 파일이 있다고 가정하면 <%= stylesheet_link_tag "application" %> 또는 <%= stylesheet_link_tag "marketing" %> 를 사용하여 뷰에서 이러한 스타일시트를 로드할 수 있습니다.

JavaScript 파일이 기본적으로 assets 디렉토리에서 로드되지 않는 것을 알 수 있습니다. 이는 ./app/javascriptimportmap-rails 젬의 기본 진입점이고 vendor 폴더가 다운로드된 JS 패키지가 저장되는 장소이기 때문입니다.

manifest.js에서 특정 파일을 로드하도록 link 지시문을 지정할 수도 있습니다. link 지시문에는 명시적 파일 확장자가 필요합니다.

Sprockets은 지정된 파일을 로드하고, 필요한 경우 처리하며, 하나의 파일로 결합한 다음 압축합니다(config.assets.css_compressor 또는 config.assets.js_compressor의 값에 따라). 압축은 파일 크기를 줄여 브라우저가 더 빨리 다운로드할 수 있게 합니다.

컨트롤러별 애셋

스캐폴드나 컨트롤러를 생성하면 Rails에서 해당 컨트롤러에 대한 Cascading Style Sheet 파일도 생성합니다. 또한 스캐폴드를 생성할 때 Rails는 scaffolds.css 파일을 생성합니다.

예를 들어 ProjectsController를 생성하면 Rails에서 app/assets/stylesheets/projects.css라는 새 파일을 추가합니다. 기본적으로 이러한 파일은 manifest.js 파일의 link_directory 지시문을 통해 즉시 애플리케이션에서 사용할 수 있습니다.

또한 다음과 같이 컨트롤러별 스타일시트 파일을 해당 컨트롤러에서만 포함하도록 선택할 수 있습니다:

<%= stylesheet_link_tag params[:controller] %>

이렇게 하는 경우 application.cssrequire_tree 지시문을 사용하지 않도록 주의해야 합니다. 그렇지 않으면 컨트롤러별 애셋이 두 번 포함될 수 있습니다.

애셋 구성

파이프라인 애셋은 애플리케이션 내에 세 가지 위치 중 하나에 배치할 수 있습니다: app/assets, lib/assets 또는 vendor/assets.

  • app/assets는 애플리케이션이 소유한 애셋(예: 사용자 지정 이미지 또는 스타일시트)에 사용됩니다.

  • app/javascript는 JavaScript 코드에 사용됩니다.

  • vendor/[assets|javascript]는 외부 엔터티가 소유한 애셋(예: CSS 프레임워크 또는 JavaScript 라이브러리)에 사용됩니다. 다른 파이프라인 애셋(이미지, 스타일시트 등)을 참조하는 타사 코드는 asset_path 같은 도우미를 사용하도록 다시 작성해야 합니다.

기타 위치는 manifest.js 파일에서 구성할 수 있습니다. 매니페스트 파일 및 지시문을 참조하세요.

검색 경로

매니페스트 또는 도우미에서 파일이 참조되면 Sprockets은 manifest.js에 지정된 모든 위치를 검색합니다. Rails 콘솔에서 Rails.application.config.assets.paths를 확인하여 검색 경로를 볼 수 있습니다.

폴더의 프록시로 인덱스 파일 사용하기

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
*/

이렇게 하면 유지 관리가 간소화되고 관련 코드를 그룹화하여 다른 곳에 포함할 수 있습니다.

애셋에 대한 링크 코딩

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 해시가 포함된 파일 이름 `public/assets/rails-f90d8a84c707a8dc네, 계속해서 번역하겠습니다.

또는 SHA256 해시가 포함된 파일 이름 public/assets/rails-f90d8a84c707a8dc923fca1ca1895ae8ed0a09237f6992015fef1e11be77c023.png에 대한 요청도 동일하게 처리됩니다. 이러한 해시가 생성되는 방식은 이 가이드의 프로덕션에서 섹션에서 다룹니다.

이미지는 필요에 따라 하위 디렉토리로 구성할 수 있으며 태그에서 디렉토리 이름을 지정하여 액세스할 수 있습니다:

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

경고: 애셋을 프로덕션에서 사전 컴파일하는 경우(아래 참조) 존재하지 않는 애셋을 참조하면 호출 페이지에서 예외가 발생합니다. 이는 빈 문자열을 참조하는 것도 포함됩니다. 따라서 사용자 제공 데이터를 사용할 때 image_tag 및 기타 도우미를 사용할 때 주의해야 합니다.

CSS와 ERB

애셋 파이프라인은 자동으로 ERB를 평가합니다. 즉, CSS 애셋에 erb 확장자를 추가하면(application.css.erb) asset_path와 같은 도우미를 CSS 규칙에서 사용할 수 있습니다:

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

이는 참조된 특정 애셋의 경로를 작성합니다. 이 예에서는 app/assets/images/image.png와 같은 애셋 로드 경로에 이미지가 있어야 합니다. 이 이미지가 이미 public/assets에 지문화된 파일로 있는 경우 해당 경로가 참조됩니다.

데이터 URI - CSS 파일에 직접 이미지 데이터를 포함하는 방법 - 를 사용하려면 asset_data_uri 도우미를 사용할 수 있습니다.

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

이렇게 하면 CSS 소스에 올바르게 형식화된 데이터 URI가 삽입됩니다.

닫는 태그는 -%> 스타일이 될 수 없습니다.

애셋을 찾을 수 없을 때 오류 발생

sprockets-rails >= 3.2.0을 사용하는 경우 애셋 조회를 수행할 때 아무것도 찾지 못하면 어떻게 할지 구성할 수 있습니다. “애셋 폴백"을 끄면 애셋을 찾을 수 없을 때 오류가 발생합니다.

config.assets.unknown_asset_fallback = false

"애셋 폴백"이 활성화된 경우 애셋을 찾을 수 없으면 경로가 출력되고 오류가 발생하지 않습니다. 기본적으로 애셋 폴백 동작은 비활성화됩니다.

지문 끄기

config/environments/development.rb에서 다음을 업데이트하여 지문을 끌 수 있습니다:

config.assets.digest = false

이 옵션이 true이면 애셋 URL에 지문이 생성됩니다.

소스 맵 켜기

config/environments/development.rb에서 다음을 업데이트하여 소스 맵을 켤 수 있습니다:

config.assets.debug = true

디버그 모드가 켜져 있으면 Sprockets가 각 애셋에 대한 소스 맵을 생성합니다. 이를 통해 브라우저의 개발자 도구에서 각 파일을 개별적으로 디버깅할 수 있습니다.

애셋은 서버가 시작된 후 첫 번째 요청 시 컴파일되고 캐시됩니다. Sprockets는 후속 요청에서 요청 오버헤드를 줄이기 위해 must-revalidate Cache-Control HTTP 헤더를 설정합니다. 이러한 요청에서 브라우저는 304(Not Modified) 응답을 받습니다.

매니페스트의 파일 중 하나라도 요청 사이에 변경되면 서버는 새로 컴파일된 파일로 응답합니다.

프로덕션에서

프로덕션 환경에서 Sprockets는 위에서 설명한 지문 체계를 사용합니다. 기본적으로 Rails는 애셋이 사전 컴파일되었고 웹 서버에 의해 정적 애셋으로 제공될 것으로 가정합니다.

사전 컴파일 단계에서 컴파일된 파일의 SHA256이 생성되고 디스크에 기록되는 파일 이름에 삽입됩니다. 이러한 지문화된 이름은 Rails 도우미에 의해 매니페스트 이름 대신 사용됩니다.

예를 들어 다음과 같은 것이:

<%= stylesheet_link_tag "application" %>

다음과 같이 생성됩니다:

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

지문 동작은 config.assets.digest 초기화 옵션(기본값은 true)에 의해 제어됩니다.

주의: 일반적인 상황에서 기본 config.assets.digest 옵션을 변경해서는 안 됩니다. 파일 이름에 지문이 없고 원격 클라이언트에 대한 원격 헤더가 설정된 경우 콘텐츠가 변경되어도 이를 알 수 없습니다.

애셋 사전 컴파일

Rails에는 애셋 매니페스트와 파이프라인의 다른 파일을 컴파일하는 명령이 번들로 제공됩니다.

컴파일된 애셋은 config.assets.prefix에 지정된 위치에 기록됩니다. 기본적으로 이는 /assets 디렉토리입니다.

배포 중에 서버에서 이 명령을 호출하여 서버에 직접 컴파일된 버전의 애셋을 만들 수 있습니다. 로컬에서 컴파일하는 방법은 다음 섹션을 참조하세요.

이 명령은 다음과 같습니다:

$ RAILS_ENV=production rails assets:precompile

이 명령은 config.assets.prefix에 지정된 폴더를 shared/assets에 링크합니다. 이 공유 폴더를 이미 사용하는 경우 자체 배포 명령을 작성해야 합니다.

이 폴더는 배포 간에 공유되어야 하므로 오래된 컴파일된 애셋에 대한 원격 캐시된 페이지가 계속 작동합니다.

주의. 항상 .js 또는 .css로 끝나는 예상된 컴파일된 파일 이름을 지정하세요.

이 명령은 또한 모든 애셋과 해당 지문이 포함된 .sprockets-manifest-randomhex.json(여기서 randomhex는 16바이트 무작위 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 예외가 발생하여 누락된 파일 이름을 나타냅니다.

원격 만료 헤더

사전 컴파일된 애셋은 파일 시스템에 존재하며 웹 서버에 의해 직접 제공됩니다. 기본적으로 원격 만료 헤더가 없으므로 지문의 이점을 얻으려면 서버 구성을 업데이트하여 이러한 헤더를 추가해야 합니다.

Apache의 경우:

# The Expires* directives requires the Apache module
# `mod_expires` to be enabled.
<Location /assets/>
  # Use of ETag is discouraged when Last-Modified is present
  Header unset ETag
  FileETag None
  # RFC says only cache for 1 year
  ExpiresActive On
  ExpiresDefault "access plus 1 year"
</Location>

NGINX의 경우:

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

  add_header ETag "";
}

로컬 사전 컴파일

때로는 프로덕션 서버에서 애셋을 컴파일하고 싶지 않을 수 있습니다. 예를 들어 프로덕션 파일 시스템에 대한 쓰기 액세스 권한이 제한적이거나 애셋을 변경하지 않고 자주 배포할 계획일 수 있습니다.

이러한 경우 로컬로 애셋을 사전 컴파일 - 즉, 프로덕션 준비 상태의 컴파일된 애셋 집합을 소스 코드 리포지토리에 추가할 수 있습니다. 이렇게 하면 각 배포 시 프로덕션 서버에서 별도로 사전 컴파일할 필요가 없습니다.

위와 같이 다음 명령을 사용할 수 있습니다:

$ RAILS_ENV=production rails assets:precompile

다음과 같은 주의 사항이 있습니다:

  • 사전 컴파일된 애셋을 사용할 수 있는 경우 원래(컴파일되지 않은) 애셋과 더 이상 일치하지 않더라도 해당 애셋이 제공됩니다. 심지어 개발 서버에서도 그렇습니다.

    개발 서버가 항상 온더플라이 애셋을 컴파일하도록(따라서 코드의 가장 최근 상태를 항상 반영하도록) 하려면 개발 환경이 프로덕션과 다른 위치에 사전 컴파일된 애셋을 보관하도록 구성해야 합니다. 그렇지 않으면 프로덕션용으로 컴파일된 애셋이 개발 요청을 덮어쓰게 됩니다(즉, 애셋에 대한 후속 변경 사항이 브라우저에 반영되지 않습니다).

    이를 위해 config/environments/development.rb에 다음 줄을 추가할 수 있습니다:

    config.assets.prefix = "/dev-assets"
    
  • 배포 도구(예: Capistrano)의 애셋 사전 컴파일 작업을 비활성화해야 합니다.

  • 필요한 압축기 또는 축소기가 개발 시스템에 있어야 합니다.

또한 ENV["SECRET_KEY_BASE_DUMMY"]를 설정하여 임시 파일에 저장된 무작위로 생성된 secret_key_base를 사용하도록 할 수 있습니다. 이는 프로덕션 비밀을 필요로 하지 않는 빌드 단계의 일부로 프로덕션용 애셋을 사전 컴파일할 때 유용합니다.

$ SECRET_KEY_BASE_DUMMY=1 bundle exec rails assets:precompile

실시간 컴파일

특정 상황에서는 실시간 컴파일을 사용하고 네, 계속해서 번역하겠습니다.

실시간 컴파일

특정 상황에서는 실시간 컴파일을 사용하고 싶을 수 있습니다. 이 모드에서는 파이프라인의 모든 애셋 요청이 Sprockets에 의해 직접 처리됩니다.

이 옵션을 활성화하려면 다음을 설정하세요:

config.assets.compile = true

첫 번째 요청에서 애셋이 컴파일되고 애셋 캐시 저장소에 캐시됩니다. 그리고 도우미에 사용되는 매니페스트 이름에 SHA256 해시가 포함됩니다.

Sprockets는 또한 Cache-Control HTTP 헤더를 max-age=31536000으로 설정합니다. 이는 클라이언트 브라우저와 서버 사이의 모든 캐시에 이 콘텐츠(제공된 파일)를 1년 동안 캐시할 수 있음을 알립니다. 이 효과는 이 애셋에 대한 서버 요청 수를 줄이는 것입니다. 애셋이 로컬 브라우저 캐시 또는 중간 캐시에 있을 가능성이 높습니다.

이 모드는 더 많은 메모리를 사용하고 기본 모드보다 성능이 떨어지므로 권장되지 않습니다.

CDN

CDN은 콘텐츠 전송 네트워크의 약자로, 주로 전 세계에 애셋을 캐시하여 브라우저가 애셋을 요청할 때 캐시된 복사본이 브라우저에 가까운 곳에서 제공되도록 하는 것이 목적입니다. 프로덕션에서 Rails 서버에서 직접 애셋을 제공하는 경우 가장 좋은 방법은 애플리케이션 앞에 CDN을 사용하는 것입니다.

CDN을 사용하는 일반적인 패턴은 프로덕션 애플리케이션을 "원본” 서버로 설정하는 것입니다. 이는 CDN에 애셋에 대한 요청이 있고 캐시 누락이 발생하면 즉시 서버에서 파일을 가져와 캐시하는 것을 의미합니다. 예를 들어 example.com에서 Rails 애플리케이션을 실행하고 mycdnsubdomain.fictional-cdn.com에 CDN을 구성한 경우 mycdnsubdomain.fictional-cdn.com/assets/smile.png에 대한 요청이 있으면 CDN이 example.com/assets/smile.png를 한 번 쿼리하고 캐시합니다. 동일한 URL에 대한 다음 CDN 요청은 캐시된 복사본을 사용합니다. CDN이 애셋을 직접 제공할 수 있는 경우 요청이 Rails 서버에 도달하지 않습니다. CDN의 애셋이 브라우저에 지리적으로 더 가깝기 때문에 요청 속도가 빨라지며, 서버가 애셋을 제공할 필요가 없기 때문에 애플리케이션 코드를 더 빨리 제공할 수 있습니다.

CDN을 사용하여 정적 애셋 제공 설정

CDN을 설정하려면 example.com과 같은 공개적으로 액세스 가능한 URL에서 프로덕션 환경에서 애플리케이션을 실행해야 합니다. 그런 다음 클라우드 호스팅 공급자에게서 CDN 서비스에 가입해야 합니다. 이 작업을 수행할 때 CDN의 “원본"을 웹사이트 example.com을 가리키도록 구성해야 합니다. 공급자의 설명서를 확인하여 원본 서버 구성 방법을 확인하세요.

프로비저닝한 CDN에서 mycdnsubdomain.fictional-cdn.com과 같은 사용자 지정 하위 도메인을 제공할 것입니다(fictional-cdn.com은 현재 유효한 CDN 공급자가 아님). 이제 CDN 서버를 구성했으므로 브라우저가 Rails 서버 대신 CDN에서 애셋을 가져오도록 해야 합니다. 이를 위해 Rails에서 애셋 호스트를 상대 경로 대신 CDN으로 설정해야 합니다. Rails에서 애셋 호스트를 설정하려면 config/environments/production.rb에서 config.asset_host를 설정해야 합니다:

config.asset_host = 'mycdnsubdomain.fictional-cdn.com'

주의: "호스트"만 제공하면 됩니다. 이는 하위 도메인과 루트 도메인입니다. http:// 또는 https://와 같은 프로토콜 또는 "스키마"를 지정할 필요는 없습니다. 웹 페이지가 요청될 때 애셋에 대한 링크의 프로토콜은 기본적으로 웹 페이지에 액세스하는 방식과 일치합니다.

환경 변수를 통해 이 값을 설정할 수도 있어 스테이징 사본을 실행하기 더 쉽습니다:

config.asset_host = ENV['CDN_HOST']

주의: 이 경우 서버에 CDN_HOSTmycdnsubdomain.fictional-cdn.com으로 설정해야 합니다.

서버와 CDN을 구성하면 다음과 같은 도우미에서 애셋 경로:

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

http://mycdnsubdomain.fictional-cdn.com/assets/smile.png(가독성을 위해 지문 생략)와 같은 전체 CDN URL로 렌더링됩니다.

CDN에 smile.png가 있는 경우 브라우저에 제공하고 서버는 요청을 알지 못합니다. CDN에 사본이 없는 경우 "원본” example.com/assets/smile.png에서 찾아 향후 사용을 위해 저장합니다.

일부 애셋만 CDN에서 제공하려면 애셋 도우미에 사용자 지정 :host 옵션을 사용할 수 있습니다. 이는 config.action_controller.asset_host에 설정된 값을 덮어씁니다.

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

CDN 캐싱 동작 사용자 지정

CDN은 콘텐츠를 캐싱하여 작동합니다. CDN에 오래된 또는 잘못된 콘텐츠가 있는 경우 애플리케이션에 도움이 되지 않습니다. 이 섹션의 목적은 대부분의 CDN의 일반적인 캐싱 동작을 설명하는 것입니다. 특정 공급자의 동작은 약간 다를 수 있습니다.

CDN 요청 캐싱

CDN은 애셋 자체만 캐싱하는 것이 아니라 전체 요청을 캐싱한다고 설명됩니다. 이에는 본문과 Cache-Control과 같은 헤더가 포함됩니다. Cache-Control은 CDN(및 웹 브라우저)에 콘텐츠를 어떻게 캐싱할지 알려줍니다. 즉, /assets/i-dont-exist.png와 같이 존재하지 않는 애셋을 요청하고 Rails 애플리케이션이 404를 반환하는 경우 유효한 Cache-Control 헤더가 있으면 CDN이 404 페이지를 캐시할 가능성이 높습니다.

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 또는 추가 헤더와 같은 추가 정보를 확인하세요.

CDN과 Cache-Control 헤더

Cache-Control 헤더는 요청을 캐시할 수 있는 방법을 설명합니다. CDN을 사용하지 않는 경우 브라우저는 이 정보를 사용하여 콘텐츠를 캐시합니다. 이는 수정되지 않는 애셋의 경우 브라우저가 웹사이트의 CSS 또는 JavaScript를 매번 다시 다운로드할 필요가 없도록 하는 데 매우 유용합니다. 일반적으로 Rails 서버가 CDN(및 브라우저)에 애셋이 “public"임을 알려주기를 원합니다. 즉, 어떤 캐시든 요청을 저장할 수 있습니다. 또한 일반적으로 max-age를 설정하여 캐시가 개체를 저장하기 전에 기다리는 시간(초)을 지정합니다. max-age 값의 최대값은 31536000(1년)입니다. Rails 애플리케이션에서 다음과 같이 설정할 수 있습니다:

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

이제 프로덕션에서 애플리케이션이 애셋을 제공할 때 CDN이 최대 1년 동안 애셋을 저장합니다. 대부분의 CDN도 요청 헤더를 캐시하므로 이 Cache-Control이 이 애셋을 찾는 모든 향후 브라우저에 전달됩니다. 브라우저는 애셋을 다시 요청하기 전에 매우 오랫동안 이를 저장할 수 있습니다.

CDN과 URL 기반 캐시 무효화

대부분의 CDN은 전체 URL을 기반으로 애셋 콘텐츠를 캐시합니다. 즉,

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

에 대한 요청은

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

에 대한 요청과 완전히 다른 캐시입니다.

max-age가 먼 Cache-Control을 설정하려면(그렇게 해야 합니다) 애셋을 변경할 때 캐시를 무효화해야 합니다. 예를 들어 이미지의 노란색 웃는 얼굴을 파란색으로 변경하는 경우 사이트의 모든 방문자가 새 파란색 얼굴을 받도록 하려고 합니다. Rails 애셋 네, 계속해서 번역하겠습니다.

Rails 애셋 파이프라인에서 config.assets.digest가 기본적으로 true로 설정되어 있으므로 애셋이 변경될 때마다 고유한 애셋 이름이 생성됩니다. 이렇게 하면 캐시를 수동으로 무효화할 필요가 없습니다. 고유한 애셋 이름을 사용하면 사용자가 최신 애셋을 받게 됩니다.

파이프라인 사용자 지정

CSS 압축

CSS 압축 옵션 중 하나는 YUI입니다. YUI CSS 압축기는 축소 기능을 제공합니다.

다음 줄은 YUI 압축을 활성화하며 yui-compressor 젬이 필요합니다.

config.assets.css_compressor = :yui

JavaScript 압축

JavaScript 압축을 위한 옵션은 :terser, :closure:yui입니다. 이들은 각각 terser, closure-compiler 또는 yui-compressor 젬을 사용해야 합니다.

terser 젬을 예로 들어 보겠습니다. 이 젬은 Ruby에서 Terser(Node.js용으로 작성됨)를 래핑합니다. 공백과 주석을 제거하고 지역 변수 이름을 단축하며 삼항 연산자로 ifelse 문을 변경하는 등의 마이크로 최적화를 수행하여 코드를 압축합니다.

다음 줄은 JavaScript 압축에 terser를 호출합니다.

config.assets.js_compressor = :terser

주의: ExecJS가 지원하는 런타임이 필요합니다. macOS 또는 Windows를 사용하는 경우 운영 체제에 JavaScript 런타임이 설치되어 있습니다.

주의: JavaScript 압축은 importmap-rails 또는 jsbundling-rails 젬을 통해 애셋을 로드할 때도 작동합니다.

애셋 gzip 압축

기본적으로 컴파일된 애셋의 gzip 버전과 gzip되지 않은 버전이 모두 생성됩니다. gzip된 애셋은 전송되는 데이터 양을 줄이는 데 도움이 됩니다. gzip 플래그를 설정하여 이를 구성할 수 있습니다.

config.assets.gzip = false # gzip된 애셋 생성 비활성화

웹 서버 문서를 참조하여 gzip된 애셋을 제공하는 방법을 확인하세요.

사용자 정의 압축기 사용

CSS와 JavaScript에 대한 압축기 구성 설정은 모든 객체를 허용합니다. 이 객체에는 문자열을 유일한 인수로 받아 문자열을 반환하는 compress 메서드가 있어야 합니다.

class Transformer
  def compress(string)
    do_something_returning_a_string(string)
  end
end

이를 활성화하려면 application.rb에서 새 객체를 구성 옵션에 전달하세요:

config.assets.css_compressor = Transformer.new

assets 경로 변경

Sprockets가 기본적으로 사용하는 공개 경로는 /assets입니다.

이를 다른 것으로 변경할 수 있습니다:

config.assets.prefix = "/some_other_path"

이는 애셋 파이프라인을 사용하지 않고 이 경로를 이미 사용하고 있거나 새 리소스에 이 경로를 사용하려는 경우 유용한 옵션입니다.

X-Sendfile 헤더

X-Sendfile 헤더는 웹 서버에 대한 지시로, 애플리케이션의 응답을 무시하고 대신 디스크의 지정된 파일을 제공하도록 합니다. 이 옵션은 기본적으로 꺼져 있지만 서버에서 지원하는 경우 활성화할 수 있습니다. 활성화하면 파일 제공 책임을 웹 서버로 전달하여 더 빠릅니다. send_file을 참조하여 이 기능을 사용하는 방법을 확인하세요.

Apache와 NGINX는 이 옵션을 지원하며 config/environments/production.rb에서 활성화할 수 있습니다:

# config.action_dispatch.x_sendfile_header = "X-Sendfile" # for Apache
# config.action_dispatch.x_sendfile_header = 'X-Accel-Redirect' # for NGINX

경고: 기존 애플리케이션을 업그레이드하고 이 옵션을 사용하려는 경우 production.rb와 프로덕션 동작을 정의하는 다른 환경(application.rb가 아님)에만 이 구성 옵션을 붙여넣으세요.

팁: 자세한 내용은 프로덕션 웹 서버 문서를 참조하세요:

애셋 캐시 저장소

기본적으로 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

젬에 애셋 추가

애셋은 젬 형태의 외부 소스에서도 올 수 있습니다.

jquery-rails 젬의 좋은 예입니다. 이 젬에는 Rails::Engine를 상속하는 엔진 클래스가 포함되어 있습니다. 이렇게 하면 Rails에 이 젬의 디렉토리에 애셋이 포함될 수 있음이 알려지고 app/assets, lib/assetsvendor/assets 디렉토리가 Sprockets의 검색 경로에 추가됩니다.

라이브러리 또는 젬을 전처리기로 만들기

Sprockets는 프로세서, 변환기, 압축기 및 내보내기 도구를 사용하여 Sprockets 기능을 확장합니다. 자세한 내용은 Sprockets 확장을 참조하세요. 여기서는 text/css(.css) 파일 끝에 주석을 추가하는 전처리기를 등록했습니다.

module AddComment
  def self.call(input)
    { data: input[:data] + "/* Hello From my sprockets extension */" }
  end
end

이제 입력 데이터를 수정하는 모듈이 있으므로 MIME 유형에 대한 전처리기로 등록할 수 있습니다.

Sprockets.register_preprocessor 'text/css', AddComment

대체 라이브러리

시간이 지남에 따라 애셋 처리를 위한 기본 접근 방식이 여러 번 변경되었습니다. 웹이 발전하면서 점점 더 많은 JavaScript 중심 애플리케이션이 등장했습니다. Rails 교리에서는 메뉴는 오마카세라고 믿기 때문에 기본 설정인 Sprockets와 Import Maps에 초점을 맞추었습니다.

다양한 JavaScript 및 CSS 프레임워크/확장에 대한 일괄 적용 솔루션은 없다는 것을 알고 있습니다. Rails 생태계에는 기본 설정으로는 충분하지 않은 경우 사용할 수 있는 다른 번들링 라이브러리가 있습니다.

jsbundling-rails

jsbundling-rails는 JavaScript 런타임 종속성이 있는 importmap-rails의 대안입니다. Bun, esbuild, rollup.js 또는 Webpack을 사용하여 JS를 번들링합니다.

이 젬은 변경 사항을 감시하고 개발 중에 자동으로 출력을 생성하는 package.json 빌드 작업을 제공합니다. 프로덕션의 경우 자동으로 javascript:build 작업을 assets:precompile 작업에 연결하여 모든 패키지 종속성이 설치되고 모든 진입점에 대해 JavaScript가 빌드되도록 합니다.

importmap-rails 대신 언제 사용해야 하나요? JavaScript 코드가 트랜스파일링에 의존하는 경우, 즉 Babel, TypeScript 또는 React JSX 형식을 사용하는 경우 jsbundling-rails가 올바른 방법입니다.

Webpacker/Shakapacker

Webpacker는 Rails 5와 6의 기본 JavaScript 전처리기 및 번들러였습니다. 이제 폐기되었습니다. webpacker의 후속 버전인 shakapacker가 있지만 Rails 팀이나 프로젝트에서 유지 관리되지 않습니다.

이 목록의 다른 라이브러리와 달리 webpacker/shakapacker는 Sprockets와 완전히 독립적이며 JavaScript와 CSS 파일을 모두 처리할 수 있습니다.

주의: jsbundling-railswebpacker/shakapacker의 차이점을 이해하려면 Webpacker와의 비교 문서를 읽어보세요.

cssbundling-rails

cssbundling-rails를 사용하면 Tailwind CSS, Bootstrap, Bulma, PostCSS 또는 Dart Sass를 사용하여 CSS를 번들링하고 처리한 다음 애셋 파이프라인을 통해 전달할 수 있습니다.

jsbundling-rails와 유사한 방식으로 작동하므로 개발 중 yarn build:css --watch 프로세스를 추가하여 스타일시트를 다시 생성하고 프로덕션에서 assets:precompile 작업에 연결합니다.

Sprockets와의 차이점은 무엇인가요? Sprockets 자체로는 Sass를 CSS로 트랜스파일할 수 없습니다. .sass 파일에서 .css 파일을 생성하려면 Node.js가 필요합니다. .css 파일이 생성되면 Sprockets이 이를 클라이언트에 전달할 수 있습니다.

주의: cssbundling-rails에는 Node.js 종속성이 필요합니다. dartsass-railstailwindcss-rails 젬은 Tailwind CSS와 Dart Sass의 독립형 버전을 사용하므로 Node 종속성이 필요 없습니다. importmap-rails를 사용하여 JavaScript를 처리하고 dartsass-rails 또는 tailwindcss-rails를 사용하여 CSS를 처리하는 경우 Node 종속성을 완전히 피할 수 있어 더 간단한 솔루션이 됩니다.

dartsass-rails

Sass를 애플리케이션에서 사용하려면 dartsass-rails를 사용하는 것이 좋습니다. dartsass-rails는 2020년에 더 네, 계속해서 번역하겠습니다.

dartsass-rails

Sass를 애플리케이션에서 사용하려면 dartsass-rails를 사용하는 것이 좋습니다. dartsass-rails는 2020년에 더 이상 유지 관리되지 않는 LibSass를 사용하는 sassc-rails 젬을 대체합니다.

sassc-rails 젬과 달리 새 젬은 Sprockets와 직접 통합되지 않습니다. 설치/마이그레이션 지침은 젬 홈페이지를 참조하세요.

경고: 인기 있는 sassc-rails 젬은 2019년 이후 유지 관리되지 않습니다.

tailwindcss-rails

tailwindcss-rails는 Tailwind CSS v3 프레임워크의 독립형 실행 가능 버전에 대한 래퍼 젬입니다. --css tailwind 옵션을 사용하여 새 애플리케이션을 만들 때 사용됩니다. 개발 중 Tailwind 출력을 자동으로 생성하는 watch 프로세스를 제공합니다. 프로덕션의 경우 assets:precompile 작업에 연결됩니다.