#390 Turbolinks
- Download:
- source codeProject Files in Zip (63.9 KB)
- mp4Full Size H.264 Video (21.5 MB)
- m4vSmaller H.264 Video (9.41 MB)
- webmFull Size VP8 Video (10.9 MB)
- ogvFull Size Theora Video (22.9 MB)
Turbolinks는 레일스 4 어플리케이션에 디폴트로 포함될 젬입니다. 레일스 3와도 호환성을 가지고 있어서 현재 개발 중인 앱에서도 사용할 수 있습니다. 이 젬을 이용하면 페이지 전체를 로드하지 않고 자바스크립트를 이용하여 새로운 페이지의 HTML body 부분만을 대체하여 사용자들에게 어플리케이션을 보다 빠르게 보일 수 있도록 해 줍니다. 이번 연제에서는 레일스 3 어플리케이션에서 이 젬을 사용해 보도록 하겠습니다. 사용하게 될 어플리케이션은 Todo_list 어플리케이션으로 각각 작업 셋을 가지는 여러개의 프로젝트를 관리하게 됩니다. 새로운 작업은 incomplete(작업중) 상태로 시작하게 되지만 각 항목 옆에 있는 checkbox를 체크하여 complete(완료) 상태로 표시할 수 있습니다.
Turbolinks 추가하기
Turbolinks를 이 어플리케이션에 추가해서 어떻게 작동하는지 알아보도록 하겠습니다. 우선 gemfile 리스트에 이것을 추가하고 설치를 위해 bundle 명령을 실행합니다.
gem 'turbolinks'
다음에는 어플리케이션의 자바스크립트 manifest 파일을 열어서 require turbolinks
라인을 추가할 것입니다. Turbolinks는 jQuery와 연관이 없어서 어플리케이션에서 jQuery를 사용하지 않아도 사용할 수 있습니다.
//= require jquery //= require jquery_ujs //= require turbolinks //= require_tree .
이제 어플리케이션을 재시작하면 이전과 별다른 차이를 느끼지 못하지만 이전과 같이 페이지 이동을 할 수 있습니다. 네트워크 inspector를 열어서 사이트내의 페이지로 이동을 할 때 Turbolinks가 작동하는지 여부를 확인할 수 있습니다. 이 때 임의의 링크를 클릭할 때마다 페이지 전체가 로드된다면 Turbolinks가 작동하지 않고 있다는 것을 의미합니다. 이런 경우는 사용하는 브라우저 버전을 Turbolinks가 지원하지 않기 때문이므로 버전 업을 하거나 다른 종류의 브라우저를 사용해 보기 바랍니다. Turbolinks는 최신 버전의 브라우저를 지원하지만 그렇지 못할 경우에도 Turbolinks의 기능이 없는 상태로 제대로 작동하게 될 것입니다. 대신에 최신 버전의 크롬에서 다시 시도해 보기 바랍니다. 그러면 임의의 링크를 클릭했을 때 전체 페이지가 로드되지 않는다는 것을 알게 될 것입니다. 이것은 turbolinks.js
파일이 동작하여 다음 페이지로 AJAX 요청이 이루어지기 때문입니다.
이것은 페이지가 로드될 때마다 브라우저가 자바스크립트와 CSS 자원을 반복해서 로드하여 해석하지 않기 때문에 사용자들은 보다 빠르게 느끼게 해 줄 수 있습니다. 그러다면 어떻게 이러한 일이 가능할까요? Turbolinks가 해당 페이지 상의 모든 링크의 click
이벤트에 대해서 대응할 준비를 항상 하고 있기 때문입니다. 따라서 임의의 링크에 대한 클릭 이벤트가 발생하면 자바스크립가 요청을 수행하고 Turbolinks는 응답내용의 body 부분을 검토하게 됩니다. 그리고 나서 자바스크립를 이용하여 현재 페이지를 새로운 컨테츠로 업데이트하게 되며 title
와 body
엘리먼트가 변경되므로써 마치 새로운 페이지인 것처럼 보이게 해 줍니다. 또한 Push State API를 이용해서 현재의 URL을 새로운 페이지의 것으로 변경해 주게 됩니다. 이러한 기술은 294 연제에서 다루었던 PJAX와 매우 비슷합니다.
기존 자바스크립트의 작동시 문제점
어플리케이션이 Turbolinks와 함께 잘 동작하는 것 같지만 기존의 자바스크립트가 동작을 하지 않는 경우가 있을 수 있습니다. 예를 들면, 임의의 작업을 완료 상태로 표시하고자 한다면 현재로서는 아무런 동작이 발생하지 않습니다. 현재의 페이지를 다시 로드한 후에 checkbox를 다시 체크한다면 이번에는 제대로 동작하게 될 것입니다. 이 페이지에 대한 Coffeescript 코드는 아래와 같습니다.
jQuery -> $('.edit_task input[type=checkbox]').click -> $(this).parent('form').submit()
이 코드는 어플리케이션을 각 작업의 checkbox의 click
이벤트에 대한 대기상태로 만들어 줍니다. 누군가가 클릭하게 되면 해당 checkbox를 포함하는 폼은 서밋되어 작업이 완료상태로 표시됩니다. 이 코드에서 중요한 코드라인은 첫번째 줄인데, jQuery
함수를 호출하게 됩니다. 이 코드는 페이지의 DOM 로드가 완료됨 시점에서 발생하는 문서상의 ready
이벤트에 대해 대기상태로 만들어 줍니다. 만약 코드의 나머지 부분을 감싸주지 않으면 checkbox들이 로드되기 전에 jQuery가 해당 checkbox에 대해서 click
이벤트를 연결하려고 시도할 것입니다.
Turbolinks를 사용하면, 페이지가 처음으로 로드될 때에만 이 콜백이 실행됩니다. 다시 말해서, 다른 페이지에서 시작하여 임의의 작업을 위해 이 페이지로 이동하게 될때, DOM의 ready
이벤트는 실행되지 않게 되는데, 기술적으로 여전이 동일한 페이지에 머므르기 때문인 것입니다. Turbolinks가 호출하는 여러가지 이벤트가 있습니다. 그 중에 page:load
라는 이벤트가 있습니다. 여기서 이 이벤트를 사용하면 Coffeescript 파일에서 DOM의 ready 함수를 시뮬레이션할 수 있습니다.
ready = -> $('.edit_task input[type=checkbox]').click -> $(this).parent('form').submit() $(document).ready(ready) $(document).on('page:load', ready)
이제 ready
라는 변수에 checkbox를 체크하는 함수를 할당하고 document.ready
와 page:load
로 넘겨 줍니다. 이런 식으로 하여 Turbolinks에 상관없이 페이지가 로드될 때 checkbox에 대한 이벤트가 작동하게 됩니다. 이후부터는 checkbox가 다시 이전과 같이 작동하게 될 것이고 작성 중인 작업이 완료 작업 목록으로 이동하게 될 것입니다.
이러한 기능을 자동으로 구현하고 싶을 경우 JQuery Turbolinks gem을 사용할 수 있습니다. 이러한 문제에 대한 또 다른 해결책이 있습니다. 엘리먼트를 선택해서 해당 엘리먼트의 click
이벤트에 대응하는 대신에, document의 click
이벤트에 대응하도록 하여 이벤트가 발생할 때 해당 이벤트를 유발한 엘리먼트가 특정 작업에 대한 checkbox인지를 확인할 수 있습니다.
$('document').on 'click', '.edit_task input[type=checkbox]', -> $(this).parent('form').submit()
이와 같이 자바스크립트가 실행된 후에는 HTML에 추가된 모든 checkbox에 대해서 이벤트 콜백이 호출될 것이기 때문에 DOM-ready 이벤트에서 이 코드를 호출할 필요가 없게 되는 것입니다. 이렇게 하면 또 하나 장점이 있는데, AJAX를 이용해서 더 많은 작업을 추가하더라도 이 이벤트가 자동으로 적용되게 된다는 것입니다.
알아두어야 할 몇가지 문제점들이 있기 때문에 Turbolinks 이슈 트랙커를 지속적으로 확인할 필요가 있습니다. Twitter Bootstrap과 jQuery UI Calendar와 같은 외부 라이브러리는 현재 Turbolinks와 호환성이 없지만 해결을 위한 작업이 진행 중이어서 조만간 문제 없이 사용할 수 있을 것입니다. 또한 어떤 브라우저에서는 페이지를 다시 로드한다던지 back 버튼을 클릭했을 때 가끔 GET 대신에 POST 요청으로 서밋되는 이상한 현상이 발생하기도 합니다. 이런 경우에는 Turbolinks을 사용할 수 없게 되는데 향후 업그레이드 버전에서는 해결이 될 것입니다.
이 모든 문제를 감안해 볼 때, 아마도 Turbolinks를 사용할 만한 가치가 있는지에 대해 의아해 할 것입니다. 그러나 Turbolinks Test를 사용하면 미리 Turbolinks의 효과를 테스트해 볼 수 있습니다. 이 테스트는 벤치마그를 통해서 Turbolinks가 반응시간을 50%까지 줄여 속도향상을 도와줄 수 있는 상황을 알아 볼 수 있게 됩니다. 물론 모든 어플리케이션에 같은 효과를 볼 수 있는 것을 아니지만, 반응시간의 향상 여부를 알아 보기 위해 특정 어플리케이션에서 이 테스트를 쉽게 사용할 수 있습니다.
레일스 4 어플리케이션을 생성하고 Turbolinks를 사용하지 않을 경우에는, gemfile에서 해당 젬과 application.js 파일에서 require
문장을 코멘트 처리하면 쉽게 제거할 수 있습니다.