ããã«ã¡ã¯ãã¬ã·ãäºæ¥é¨ãããã¯ãéçºã°ã«ã¼ãã®æ¸¡éï¼@taso0096ï¼ã§ãã ã¯ãã¯ãããã¯æè¿ãOne Experienceã¨ããããã¸ã§ã¯ãã«ãã£ã¦æ¥æ¬çã¨ã°ãã¼ãã«çã®ã·ã¹ãã ãçµ±åããã¾ããã ã©ã¡ãã®ã·ã¹ãã ãRailsã§å®è£ ããã¦ããã¨ããç¹ã¯åãã§ãããçµ±åå ã¨ãªã£ãã°ãã¼ãã«çã§ã¯Hotwireã使ããã¦ãã¾ãã*1ããã®ãããOne Experienceé¢é£ã®éçºã§ã¯Hotwireãç©æ¥µçã«æ´»ç¨ããã¦ãã¾ããæ¬è¨äºã§ã¯ãããªHotwireã®å¤ãã®æ©è½ã使ããããã¹ã¯ãããçã®ãµã¤ããã¼ã«ã¤ãã¦ãç´¹ä»ãã¾ãã
ã¡ãã£ã¨è¤éãªãµã¤ããã¼
One Experienceã«ä¼´ããã°ãã¼ãã«çã«ãã¨ãã¨åå¨ããUIã®ã¾ã¾ç§»è¡ããã®ã§ã¯ãªããããã¤ãç»é¢æ§æã®å¤æ´ãå ¥ããäºã«ãªãã¾ãããç¹ã«ãã¹ã¯ãããçã«ããã¦ã¯ãèªåã®ã³ã³ãã³ãã«ããç´ æ©ãã¢ã¯ã»ã¹ã§ããããã«ããããã«ãµã¤ããã¼ã®å°å ¥ã決ã¾ãã¾ããã
ãã®ãµã¤ããã¼ã§ã¯ãä¸è¬çãªããã²ã¼ã·ã§ã³ã¡ãã¥ã¼ã®ã»ãã«ãããããã¨å¼ã°ããã³ã³ãã³ãã表示ãã¦ãã¾ãããããããã¨ã¯ã¦ã¼ã¶ã®ä¿åã¬ã·ããæ稿ã¬ã·ããªã©ãæ´çããããã®æ©è½ã§ããã¾ãããããããã«ä¿åããã¬ã·ãã¯ã¦ã¼ã¶ã¼ããã®æã§ããã©ã«ããä½æãã¦åé¡ã§ãã¾ãããã®ã¨ããã¬ã·ãããã©ã«ãã®æ°ãå¤ãã¦ã¼ã¶ã¼ããã§ãå åç´ æ©ã表示ããããã§ããæ´ã«ããµã¤ããã¼ã®å¤ã§ã¬ã·ããä¿åãããã¨ãããªãã¼ãããã¨ããµã¤ããã¼ã®ä¸ã®è¡¨ç¤ºã追å¾ããå¿ è¦ãããã¾ãã以ä¸ãæ´çããã¨ãä½ããããã®ã¯ä»¥ä¸ã®ãããªãã®ã¨ãããã¨ã«ãªãã¾ãã
- ã³ã³ãã³ããå¤ãèªã¿è¾¼ã¿ã«æéããããå ´åãèæ ®ãã¦éåæã§èªã¿è¾¼ã
- ãã©ã«ããå¤ãå ´åã§ãå ¨ã¦ã®ãã©ã«ããèªã¿è¾¼ãã
- ã¬ã·ãã®ä¿åããã©ã«ãã®ä½æãªã©ã®æä½æã«è¡¨ç¤ºãåæãã
ãããã®è¦ä»¶ã¯Hotwireã使ãã°ç°¡åã«å®è£ ãããã¨ãã§ãã¾ããããã§ã¯Hotwireã®åæ©è½ã軽ã説æãã¤ã¤ãããããã©ããã£ãå®è£ ãããã®ããç´¹ä»ãã¾ãã
Turbo Frames
Turbo Framesã¨ã¯ãã¼ã¸å ¨ä½ããªãã¼ãããã«é¨åçãªæ´æ°ãå¯è½ã«ããããã®æ©è½ã§ããé¨åæ´æ°ãããç®æãTurbo Framesã®ã¿ã°ã§å²ããã¨ã§ããã®ã¿ã°å ã®é¨åæ´æ°ãè¡ããã¾ããã¾ããiframeã®ããã«URLãæå®ãããã¨ã§å ¨ãå¥ã®ãã¼ã¸ãåãè¾¼ããã¨ãå¯è½ã§ãããã®å ´åã¯ã¿ã°ã®ä¸èº«ãæåã«ã¬ã³ããªã³ã°ããããã®å¾ã«éåæã§å¥ã®ãã¼ã¸ãèªã¿è¾¼ã¾ãã¾ãã
ä»åå®è£ ãããµã¤ããã¼ã§ã¯ãéåæã§ã³ã³ãã³ããèªã¿è¾¼ãããã«Turbo Framesãå©ç¨ãã¾ããããã®ããã«Turbo Framesã§è¡¨ç¤ºãããå°ç¨ãã¼ã¸ãæ°è¦ä½æããå³ã®èµ¤æ å ã§èªã¿è¾¼ãããã«ãã¾ããããã®èµ¤æ ã®é¨åã§ã¯ãã¼ãã£ã³ã°ãæåã«è¡¨ç¤ºããããã¼ã¸ã®èªã¿è¾¼ã¿å¾ã«éåæã§ã³ã³ãã³ããèªã¿è¾¼ã¾ãã¾ãã
å¤ãã®å ´åãRailså´ã§å®è£ ãã¦ããæ¢åã®ãã¼ã¸ã®ãã¸ãã¯ãªã©ããã®ã¾ã¾æµç¨ãã¦ç°¡åã«åãè¾¼ããã¨ããã®ãTurbo Framesã®ã¡ãªãããã¨æãã¾ããä¸æ¹ããã®ä¾ã§ã¯æ°è¦ãã¼ã¸ãããããä½æãã¾ãããããã¯ãã©ã«ãã®ãã¼ã¸ãã¼ã·ã§ã³å®è£ ãã·ã³ãã«ã«ããããã§ãStimulus ã§å®è£ ãã¦ãã¾ãã詳細ã¯å¾ã»ã©è§£èª¬ãã¾ãã
ãªããTurbo Framesã¯lazy loadingãå¯è½ã§ãããä»åãè¨å®ãã¦ãã¾ãããµã¤ããã¼ã¯ãã¹ã¯ãããçã§ã¯ã¹ã¯ãã¼ã«ä½ç½®ãªã©ã«é¢ä¿ãªã常ã«è¡¨ç¤ºããããã®ã§ãããã¹ããçã ã¨ããã§ã¯ãªãããã§ãã
ãã¼ã¸é·ç§»ã«ä¼´ããªã»ãã
Turbo Framesã«ãã£ã¦éåæã§ã®ã³ã³ãã³ãã®åå¾ãå®ç¾ã§ãã¾ããããããããã®ã¾ã¾ã§ã¯ãã¼ã¸é·ç§»ãããã³ã«ã³ã³ãã³ãã®ååå¾ãè¡ããã¦ãã¾ãã¾ããå ´åã«ãã£ã¦ã¯ããã§ãåé¡ãªãã§ãããä»åã¯ãã¼ã¸ãã¼ã·ã§ã³ã«ãã£ã¦èªã¿è¾¼ã¾ãããã©ã«ãã®æ å ±ããªã»ããããããã¨ãé¿ãããã¨èãã¾ãããããã§ãªãã¨ããã¼ã¸é·ç§»ãã度ã«ãµã¤ããã¼ããã¼ãã£ã³ã°ã«ãã£ã¦ä¸ç¬ä½¿ããªããªããã¨ã¯ããªãä¸ä¾¿ã ã¨æãã¾ãã
ããã§data-turbo-permanentå±æ§ã¨ãããã®ã使ç¨ãã¾ãã*2ã以ä¸ã®ããã«ãã®å±æ§ãä»ä¸ãããDOMã¯ãã¼ã¸é·ç§»æã«ãDOMãç¶æããã¾ãã
<div data-turbo-permanent>sidebar</div>
ããã«ããä¸åº¦èªã¿è¾¼ãã Turbo Framesã®ã³ã³ãã³ãã¯é常ã®ç»é¢é·ç§»ã§ã¯ãªã»ãããããªããªãã¾ãããããå度èªã¿è¾¼ãã«ã¯ãã©ã¦ã¶ã®ãªãã¼ããJavaScriptã«ããåèªã¿è¾¼ã¿ã®å¦çãå¿ è¦ã«ãªãã¾ãã
ã¬ã¹ãã³ã¹
Turbo Framesãåå¾ããHTMLã¯ãã¼ã¸ã«åãè¾¼ã¾ããé¨åã ãã§ã¯ããã¾ãããlayoutãã³ãã¬ã¼ããã使ç¨ããã¾ãããActionViewã§ã¬ã³ããªã³ã°ããããã¼ã¸å ¨ä½ãã¬ã¹ãã³ã¹ã¨ãã¦è¿ããã¾ãããã®ãããActionViewã®ä¸ã®ä¸è¦ç´ ã®ã¿ãåãè¾¼ã¿ããã¨ãã£ãå ´åã¯ãã以å¤ã®ã¬ã¹ãã³ã¹ã¯ç ´æ£ããã¦ãã¾ãã¾ããããããã®ã¬ã¹ãã³ã¹ã¯ä»¥ä¸ã®ããã«ãªã£ã¦ããããã©ã¦ã¶å´ã®Hotwireã©ã³ã¿ã¤ã ã§è§£éããã¦ç»é¢ã«åãè¾¼ã¾ãã¾ãã
<html> <head></head> <body> <div>ç ´æ£ãããè¦ç´ </div> <turbo-frame id="dom_id">åãè¾¼ã¿ããè¦ç´ </turbo-frame> </body> </html>
å¤å°ã®ç¡é§ã¯çãã¦ãã¾ãã¾ãããä¸ã§ãæ¸ããããã«æ¢åã®ãã¼ã¸ãã»ã¼ãã®ã¾ã¾æµç¨å¯è½ã§ããã¨ããã¡ãªããã®æ¹ã大ããã¨èãã¾ãããªããä»åã¯æ°è¦ãã¼ã¸ãä½æãActionViewå ¨ä½ãåãè¾¼ã¾ããå½¢ã«ãããããããããç ´æ£ãããè¦ç´ ã¯åå¨ãã¾ããã
Turbo Streams
Turbo Streamsã¨ã¯ãªã¢ã«ã¿ã¤ã ã§ã®ãã¼ã¿æ´æ°ãç°¡åã«ããããã®æ©è½ã§ãããã¼ã¸ã«å¯¾ãã¦DOMã®è¿½å ã»å¤æ´ã»åé¤ãªã©ãå¯è½ã§ãããè¤æ°ç®æãåæã«æ´æ°ãããã¨ãã§ãã¾ããä»åã¯ã¬ã·ããæ°è¦ã§ä¿åããéã®ã¬ã·ãæ°ã®æ´æ°ãããã©ã«ãèªä½ã®ç·¨éãåæ ããããã«ä½¿ç¨ãã¾ããã
ã¬ã¹ãã³ã¹
Turbo Framesã¨éããTurbo Streamsã§ã¯ãã¼ã¸å ¨ä½ã§ã¯ãªããå·®åã®ã¿ããµã¼ãã¼ããã¬ã¹ãã³ã¹ãã¾ããDOMãã©ã®ããã«æ±ããã«ã¤ãã¦ã¯Turbo Streamsã®ã¢ã¯ã·ã§ã³ã«ãã£ã¦æ示ããã¾ããä¾ãã°ã¦ã¼ã¶ãæ°è¦ã§ã¬ã·ãããã©ã«ãã«è¿½å ããå ´åãèãã¾ãããã®å ´åã¯ç»é¢ã®èµ¤æ é¨åãå ¨ã¦æ´æ°ããã¾ãã
ãã®æã«è¿ãããã¬ã¹ãã³ã¹ã¯ãããã以ä¸ã®ããã«ãªãã¾ãã
<turbo-stream action="replace" target="dom_id">ä¿åãã¿ã³ã®HTML</turbo-stream> <turbo-stream action="replace" target="dom_id">ãããããã¦ã³ã®HTML</turbo-stream> <turbo-stream action="replace" target="dom_id">ãããããã®ããã¹ã¦ãã®HTML</turbo-stream> <turbo-stream action="replace" target="dom_id">ãããããã®ãä¿åæ¸ã¿ãã®HTML</turbo-stream> <turbo-stream action="prepend" target="dom_id">ãããããã®ãæ°è¦ãã©ã«ããã®HTML</turbo-stream> <turbo-stream action="replace" target="dom_id">éç¥ã®HTML</turbo-stream>
ãã®ã¬ã¹ãã³ã¹ãHotwireã©ã³ã¿ã¤ã ã解éãã¦ç»é¢ã®æ´æ°ãè¡ããã¾ãã
ãªãã¤ã¬ã¯ã
ãµã¤ããã¼ã®åæãå®è£ ããã«ããã£ã¦ãããã¾ã§ã¯ç»é¢ã®æ´æ°ãä¸è¦ã ã£ãããã¤ãã®æ¢åã®ãªã¯ã¨ã¹ãã®formatãHTMLããTurbo Streamsã«ç½®ãæããå¿ è¦ãããã¾ãããåºæ¬çã«åé¡ãªãç½®ãæãããã¨ãå¯è½ã§ãããããªãã¤ã¬ã¯ããå¿ è¦ãªå ´åã¯å°ã工夫ããå¿ è¦ãããã¾ããã
ä¾ãã°ã¦ã¼ã¶ããã©ã«ãã®ãã¼ã¸ãããã®ãã©ã«ããåé¤ããå ´åãèãã¾ãããã®å ´åã¯ãµã¤ããã¼ã®ããããããã対象ã®ãã©ã«ãã®DOMãåé¤ããä¸ã§ãããããã®ãããã«ãªãã¤ã¬ã¯ãããã¨ããä»æ§ã«ãªã£ã¦ãã¾ããããã¯ããã©ã«ãã®ã¢ã¯ã·ã§ã³ã§ã¯å¯¾å¿ã§ããªãããã以ä¸ã®ãããªãªãã¤ã¬ã¯ãã®ããã®ã«ã¹ã¿ã ã¢ã¯ã·ã§ã³ã追å ãããã¨ã§å¯¾å¿ãã¾ããã
Turbo.StreamActions.redirect = function () { Turbo.visit(this.target) }
Viewå´ã§ã¯é常ã®ã¢ã¯ã·ã§ã³ã¨ã»ã¨ãã©åãããã«å¼ã³åºããã¨ãå¯è½ã§ãã
<%= turbo_stream.action :redirect, path %>
å®éã®ã¬ã¹ãã³ã¹ã¯ä»¥ä¸ã®ããã«ãªããHotwireã©ã³ã¿ã¤ã ã§è§£éããã¦ãªãã¤ã¬ã¯ããå®è¡ããã¾ãã
<turbo-stream action="redirect" target="path"></turbo-stream>
ã«ã¹ã¿ã ã¢ã¯ã·ã§ã³ã¯ä»»æã®JavaScriptãç°¡åã«å®è¡ã§ããããããªã便å©ãªæ©è½ã§ããããããã ããã¨è¨ã£ã¦ããã©ã«ãã¢ã¯ã·ã§ã³ã§å¯¾å¦å¯è½ãªæ©è½ã«å¯¾ãã¦ã«ã¹ã¿ã ã¢ã¯ã·ã§ã³ãä½æãã¦ãã¾ãã¨ã³ã¼ãã®ä¸è²«æ§ã失ããã¦ãã¾ããã注æãå¿ è¦ã§ãã
Stimulus
Stimulusã¨ã¯HTMLã¨JavaScriptãé©åã«åãé¢ãã¦æ¸ãããã®æ çµã¿ã§ããããã«ãã£ã¦HTMLã ããè¦ãæã«ã©ããªæåãããã®ãããããããããããã³ã¼ãèªä½ã®åå©ç¨æ§ãé«ããã¡ãªãããããã¾ããCSSãHTMLã®classå±æ§ãä»ãã¦ç´ã¥ãã¦ããããã«ãStimulusã§ã¯HTMLã®ãã¼ã¿å±æ§ãä»ãã¦ä»»æã®JavaScriptã«ããæä½ãå¯è½ã«ãã¾ãããã®JavaScriptã¯controllerã¨ããåä½ã§åãããã¦ãããcontrollerã®ã¡ã½ãããDOMã®ã©ã¤ããµã¤ã¯ã«ãã¤ãã³ããããã¯ã«å®è¡ããã¨ããã®ã主ãªæ©è½ã§ããããã«ãã£ã¦åå©ç¨ããããJavaScriptã«ãªããããªä»çµã¿ã«ãªã£ã¦ãã¾ããä»åã¯ãã¼ã¸ãã¼ã·ã§ã³ã®ããã®ç¡éã¹ã¯ãã¼ã«ã¨ã¢ã¯ãã£ãç¶æ ã®æ´æ°ã®ããã«ä½¿ããã¾ããã
ç¡éã¹ã¯ãã¼ã«
Turbo Framesã®ã»ã¯ã·ã§ã³ã§ãã©ã«ãã®ãã¼ã¸ãã¼ã·ã§ã³ã«ã¤ãã¦è§£èª¬ãã¾ãããããã使ããããããããã«ç¡éã¹ã¯ãã¼ã«ã«å¯¾å¿ãã¾ããã°ãã¼ãã«çã«ã¯å ã ç¡éã¹ã¯ãã¼ã«ç¨ã®controllerãå®è£ ããã¦ããããããããã®ã¾ã¾ä½¿ç¨ãã¾ãããå®è£ ã¨ãã¦ã¯ã·ã³ãã«ã§ãã¹ã¯ãã¼ã«ã¤ãã³ããç£è¦ãé¾å¤ãè¶ ããã次ã®ãã¼ã¸ãéåæéä¿¡ã§èªã¿è¾¼ãã¨ãããã®ã§ããStimulusã®targetsã¨valuesã®æ©è½ã使ã£ã¦ãªã¹ãã®ä¸èº«ã¯ã©ã®DOMãªã®ãã次ã®ãã¼ã¸ã®URLã¯ä½ãªã®ãã¨ãã£ãæ å ±ã管çãã¦ãã¾ãã
ãªããHotwireã«ãããç¡éã¹ã¯ãã¼ã«ã®å®è£ ã¨ãã¦Turbo Framesã®é 延èªã¿è¾¼ã¿ãæ´»ç¨ãããã®ãããã¾ãããã®å ´åã¯èªåã§ã¯JavaScriptãä¸åæ¸ããã«ç¡éã¹ã¯ãã¼ã«ã®å®è£ ãå¯è½ã§ãããã ããåç´ãªãã¼ã¸ãã¼ã·ã§ã³ã«controllerãç»é²ã ãããã°æ¸ãStimulusã¨æ¯è¼ããã¨ãViewã«å°ãæãå ¥ããå¿ è¦ãããç¹ã«ã¯æ³¨æãå¿ è¦ã§ããä»åã¯ä¾¿å©ã«ä½¿ããæ¢åå®è£ ããã£ãã®ã§Turbo Framesã«ããç¡éã¹ã¯ãã¼ã«ãããã¦æ¡ç¨ãããããªãã¨ã¯ãã¾ããã§ããã
ã¢ã¯ãã£ãç¶æ ã®æ´æ°
Turbo Framesã®ã»ã¯ã·ã§ã³ã§èª¬æããããã«ããµã¤ããã¼ã¯ç»é¢é·ç§»ã«ãããªã»ãããåé¿ããããã«data-turbo-permanentå±æ§ãæå®ããã¦ãã¾ããããããããã«ãã£ã¦ç¾å¨ã®ãã¼ã¸ã«å¿ãã¦ãããããã®ãªã³ã¯ã®ã¢ã¯ãã£ãç¶æ
ãæ´æ°ããæ©è½ãå£ãã¦ãã¾ãã¾ãããããã«å¯¾å¦ããã«ã¯JavaScriptã«ãã£ã¦ãã¼ã¸é·ç§»ãæ¤åºãã¦ã¢ã¯ãã£ãç¶æ
ãæ´æ°ããå¿
è¦ãããã¾ããä½æããcontrollerã®ä¸èº«èªä½ã¯åç´ãªãã®ã§ãããã¡ã½ãããå¼ã³åºãããã®ã¤ãã³ãã®æå®ã ãå°ãç¹æ®ã«ãªã£ã¦ãã¾ããStimulusã§ã¯data-actionå±æ§ã使ã£ã¦ã©ã®ã¤ãã³ãã«ããã¯ãã¦ã¡ã½ãããå®è¡ãããæå®ãããã¨ãã§ãã¾ãããã®ã¨ããåºæ¬çã«ã¯å±æ§ãæå®ãããDOMã«å¯¾ããã¤ãã³ããåç
§ãã¾ããããã¼ã¸é·ç§»ã®ãããªã°ãã¼ãã«ã®ã¤ãã³ãããã¯ãããå ´åã¯@document
ã®ãããªsuffixãæå®ãããã¨ã§å¯¾å¿ã§ãã¾ã*3ã
<div data-action="turbo:visit@document->controller#method"></div>
ã¾ã¨ã
Hotwireãæ´»ç¨ããã¡ãã£ã¨è¤éãªãµã¤ããã¼ã®å®è£ ã«ã¤ãã¦ãç´¹ä»ãã¾ãããHotwireã®ä»çµã¿ãå©ç¨ãããã¨ã§ã¤ã³ã¿ã©ã¯ãã£ããªUIã®ããã®JavaScriptãã»ã¨ãã©æ¸ããã«ä¸»è¦ãªæ©è½ã®å®è£ ãã§ãããã¨æãã¾ããå人çã«ã¯å ã ã¯Next.jsãæ¸ãã¦ãããã¨ãããJavaScriptã¯å¥½ãã§ãããRailsãæ¸ãä¸ã§Hotwireã¯ããªãè¯ãã§ããä»çµã¿ã ã¨æãã¦ãã¾ããHotwireã¯ã¾ã 使ãå§ããã°ããã®æè¡ã§ãã®ã§ãæ°ããç¥è¦ãæºã¾ã£ããã¾ãå ±æãããã¨æãã¾ãã
*1:æ¥æ¬çã®ã¹ãã¼ããã©ã³Webã®ä¸»è¦ãã¼ã¸ã§ã¯Next.jsãæ¡ç¨ããã¦ãã¾ããï¼ https://techlife.cookpad.com/entry/2020/12/01/093000 ï¼
*2:https://turbo.hotwired.dev/handbook/building#persisting-elements-across-page-loads
*3:https://stimulus.hotwired.dev/reference/actions#global-events