Rails 7 で importmap を使用しライブラリを CDN からダウンロードする方法
Rails 7 では Node.js を使用しないため(することもできます)、npm や yarn でのパッケージインストールをしないことを推しています。
今回はこれらのパッケージインストール方法の代わりとなる importmap を使用して、適当なライブラリを使えるようにしたいと思います。
参考
概要
対象
- importmap を使用した、欲しいライブラリの導入方法がわからない方
前提
- CPU:Mac M1
- Rails 7
- Docker 上で起動
- importmap を使用したダウンロード
手順
JavaScript の CDN を使用できるようにする
今回は slick という画像スライドでよく使用するライブラリを導入してみたいと思います。
以下の通り 2 つありますね。
cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.css
cdn.jsdelivr.net/npm/slick-carousel@1.8.1/slick/slick.min.js
ここではjsdelivr
という CDN プロバイダーを使用しています。
importmap では以下 JSPM の API パッケージを用いてパッケージ依存関係を解消しているので、 JSPM がサポートしているプロバイダーであれば使用できるという理解です。(違っていたらすみません)
サポートオプションは以下の通り ↓↓
'jspm' | 'jspm.system' | 'skypack' | 'jsdelivr' | 'unpkg'
ということで Slick はダウンロードできそうなので、以下のコマンドを叩きます。
./bin/importmap pin slick-carousel --download
すると、以下が追加されました。
-
config/importmap
ファイルにpin "slick-carousel"
-
vendor/javascript/slick-carousel.js
ファイル -
vendor/javascript/jquery.js
ファイル
次に slick メソッドを使用できるように以下を追加します。
window.slick = slick
これで Slick が使用できるようになったので、Slick の画像スライドを使用してみます。
まずは以下を追加。
$(document).ready(function(){
$('.your-class').slick();
});
<div class="your-class">
<div><%= image_tag "photo1.png", class: "w-screen h-screen object-cover" %></div>
<div><%= image_tag "photo2.png", class: "w-screen h-screen object-cover" %></div>
<div><%= image_tag "photo3.png", class: "w-screen h-screen object-cover" %></div>
</div>
基本的には以上で CDN からライブラリをダウンロードして使用することができるようになります。
しかしながら、Slick の場合は、JS に加えて、CSS の CDN もありました。
現状だと、JS のみが適用されているため、これではちゃんと使えるようになったとは言えない状況です。(現状は画面上に「Previous」しか表示されていないと思います)
そこで、次は CSS を適用していきます。
CSS の CDN を使用できるようにする
まずは Slick の公式 GitHub から CSS を取得してきます。(これはもっと良い方法があれば教えてください🙇♂️)slick.css
とslick-theme.css
の 2 つの CSS があるようです。
app/assets/stylesheets
にslick
ディレクトリを追加し、その中に slick.css
とslick-theme.css
ファイルを追加します。
中身は公式をコピーして貼り付けました ↓↓
/* Slider */
.slick-slider
{
position: relative;
display: block;
box-sizing: border-box;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
-webkit-touch-callout: none;
-khtml-user-select: none;
-ms-touch-action: pan-y;
touch-action: pan-y;
-webkit-tap-highlight-color: transparent;
}
.slick-list
{
position: relative;
display: block;
overflow: hidden;
margin: 0;
padding: 0;
}
.slick-list:focus
{
outline: none;
}
.slick-list.dragging
{
cursor: pointer;
cursor: hand;
}
.slick-slider .slick-track,
.slick-slider .slick-list
{
-webkit-transform: translate3d(0, 0, 0);
-moz-transform: translate3d(0, 0, 0);
-ms-transform: translate3d(0, 0, 0);
-o-transform: translate3d(0, 0, 0);
transform: translate3d(0, 0, 0);
}
.slick-track
{
position: relative;
top: 0;
left: 0;
display: block;
margin-left: auto;
margin-right: auto;
}
.slick-track:before,
.slick-track:after
{
display: table;
content: '';
}
.slick-track:after
{
clear: both;
}
.slick-loading .slick-track
{
visibility: hidden;
}
.slick-slide
{
display: none;
float: left;
height: 100%;
min-height: 1px;
}
[dir='rtl'] .slick-slide
{
float: right;
}
.slick-slide img
{
display: block;
}
.slick-slide.slick-loading img
{
display: none;
}
.slick-slide.dragging img
{
pointer-events: none;
}
.slick-initialized .slick-slide
{
display: block;
}
.slick-loading .slick-slide
{
visibility: hidden;
}
.slick-vertical .slick-slide
{
display: block;
height: auto;
border: 1px solid transparent;
}
.slick-arrow.slick-hidden {
display: none;
}
@charset 'UTF-8';
/* Slider */
.slick-loading .slick-list
{
background: #fff url('./ajax-loader.gif') center center no-repeat;
}
/* Icons */
@font-face
{
font-family: 'slick';
font-weight: normal;
font-style: normal;
src: url('./fonts/slick.eot');
src: url('./fonts/slick.eot?#iefix') format('embedded-opentype'), url('./fonts/slick.woff') format('woff'), url('./fonts/slick.ttf') format('truetype'), url('./fonts/slick.svg#slick') format('svg');
}
/* Arrows */
.slick-prev,
.slick-next
{
font-size: 0;
line-height: 0;
position: absolute;
top: 50%;
display: block;
width: 20px;
height: 20px;
padding: 0;
-webkit-transform: translate(0, -50%);
-ms-transform: translate(0, -50%);
transform: translate(0, -50%);
cursor: pointer;
color: transparent;
border: none;
outline: none;
background: transparent;
}
.slick-prev:hover,
.slick-prev:focus,
.slick-next:hover,
.slick-next:focus
{
color: transparent;
outline: none;
background: transparent;
}
.slick-prev:hover:before,
.slick-prev:focus:before,
.slick-next:hover:before,
.slick-next:focus:before
{
opacity: 1;
}
.slick-prev.slick-disabled:before,
.slick-next.slick-disabled:before
{
opacity: .25;
}
.slick-prev:before,
.slick-next:before
{
font-family: 'slick';
font-size: 20px;
line-height: 1;
opacity: .75;
color: white;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.slick-prev
{
left: -25px;
}
[dir='rtl'] .slick-prev
{
right: -25px;
left: auto;
}
.slick-prev:before
{
content: '←';
}
[dir='rtl'] .slick-prev:before
{
content: '→';
}
.slick-next
{
right: -25px;
}
[dir='rtl'] .slick-next
{
right: auto;
left: -25px;
}
.slick-next:before
{
content: '→';
}
[dir='rtl'] .slick-next:before
{
content: '←';
}
/* Dots */
.slick-dotted.slick-slider
{
margin-bottom: 30px;
}
.slick-dots
{
position: absolute;
bottom: -25px;
display: block;
width: 100%;
padding: 0;
margin: 0;
list-style: none;
text-align: center;
}
.slick-dots li
{
position: relative;
display: inline-block;
width: 20px;
height: 20px;
margin: 0 5px;
padding: 0;
cursor: pointer;
}
.slick-dots li button
{
font-size: 0;
line-height: 0;
display: block;
width: 20px;
height: 20px;
padding: 5px;
cursor: pointer;
color: transparent;
border: 0;
outline: none;
background: transparent;
}
.slick-dots li button:hover,
.slick-dots li button:focus
{
outline: none;
}
.slick-dots li button:hover:before,
.slick-dots li button:focus:before
{
opacity: 1;
}
.slick-dots li button:before
{
font-family: 'slick';
font-size: 6px;
line-height: 20px;
position: absolute;
top: 0;
left: 0;
width: 20px;
height: 20px;
content: '•';
text-align: center;
opacity: .25;
color: black;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
.slick-dots li.slick-active button:before
{
opacity: .75;
color: black;
}
上記を追加するだけでは CSS が読み込まれないので、以下を追加し slick ディレクトリ以下を全て読み込むようにします。
//= link_tree ../stylesheets/slick
そして画面を表示すると、うまく画像が表示され、クリックしながら画像をスライドすると次の画像に遷移するようになりました!
しかしながら、検証ツールを見ると以下のエラーが、、、
これらはslick-theme.css
で「ajax-loader.gif
, slick.woff
, slick.ttf
」の 3 つのファイルを読み込むコードが書いてあるが、ファイルがないよということでエラーを出しています。
以下の箇所です ↓↓
src: url('./fonts/slick.eot');
src: url('./fonts/slick.eot?#iefix') format('embedded-opentype'), url('./slick/fonts/slick.woff') format('woff'), url('./slick/fonts/slick.ttf') format('truetype'), url('./fonts/slick.svg#slick') format('svg');
ちなみに、これらは画像の左右にある矢印ボタンです ↓↓
特に必要なければ上記の箇所をコメントアウト、もしくはslick-theme.css
ファイル自体を削除してしまっても良いと思います。
矢印がほしい場合は公式 GitHub からファイルをダウンロードすることが可能です。
しかしながら結論として、僕の場合はエラーを解消することはできましたが、うまく公式のように矢印を表示させることができませんでした。
以下のように画像の右端に空白のスペースができて、赤枠らへんの場所に透明ボタンが設置されてそれをクリックすると次の画像に遷移する感じになります。
この箇所では次に紹介する手順で追加した SVG ファイルをちゃんと読み込んではいたので、自分で CSS をいじって表示できるようにすることは可能だと思います。
僕の場合は特に矢印が必要なかったので、最終的には上記の読み込み箇所をコメントアウトしてしまいました。
一応以下に途中まで試した手順を記載しておきます。
画像スライドの矢印を表示させるために試した手順
僕の場合は、
-
ajax-loader.gif
はapp/assets/images/
に格納 -
slick.woff
,slick.ttf
はapp/assets/stylesheets/slick/
にfonts
ディレクトリを作成し、その中に格納(公式にあるslick.eot
,slick.svg
も一緒に格納しました)
なお、上記のようにfonts
ディレクトリ以下に格納する場合、読み込む側のパスも以下のように修正が必要です。
src: url('./fonts/slick.eot');
src: url('./fonts/slick.eot?#iefix') format('embedded-opentype'), url('./slick/fonts/slick.woff') format('woff'), url('./slick/fonts/slick.ttf') format('truetype'), url('./fonts/slick.svg#slick') format('svg');
これでエラーは消えて、矢印が表示されると思いましたが、これだけだとちゃんと表示されないようです。
自分で CSS を編集したりすれば表示できそうな感じではあるので、矢印が必要な方はぜひやってみてください。
もしできた方は教えていただけると嬉しいです!
まとめ
今回は slick を例にライブラリをダウンロードしました。
他のライブラリでは CSS の CDN がない場合もあるので、その場合はもっと簡単に追加することができると思います。
お疲れ様でした◎
Discussion