Computer >> บทช่วยสอนคอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

ทำให้ Turbolinks จาก Nightmare กลาย Advantage ใน Rails Applications

Turbolinks - คำที่เกลียดชังที่สุดใน Rails universe

อาจลอง用 include turbolinks ใน new project หรือ existing app เร็วๆ app เริ่ม fail แปลกๆ วิธีแก้ง่าย: ปิด turbolinks

...แตบริษัทบางแห่งทำงานได้ ที่ Honeybadger เราทำงาน - และเราไม่ใช่ geniuses

คำตอบ simple เกือบไม่กล้าบอก แต่หลังพูดเรื่องนี้ Ruby Nation และ Madison+Ruby คนๆ หา useful มาขุดกัน

ทำให้ Turbolinks จาก Nightmare กลาย Advantage ใน Rails Applications

Turbolinks และ PJAX ทำงานเหมือนกันคล้ายกันมาก แค่บอก PJAX ตั้งแต่ตอนนี้ :)

เข้าใจ PJAX ใน terms ของ two page requests ครั้งแรก user request page served เหมือน "traditional" Rails page แต่เวลา user click PJAX-enabled link 發生特別事: แทนที่ reload หน้าทั้งหมด แค่ portion ของ page updated ผ่าน AJAX

ได้ advantages ของ single page app หลีกเลี่ยง difficulties บางอย่าง:

  • PJAX apps มัก snappy เท่า single page apps เพราะหน้าไม่ต้อง reload ทุก request
  • 用 same stack front-end และ back-end development
  • PJAX apps degrade gracefully default เมื่อ user disable JS
  • PJAX apps ทำ accessible และ SEO friendly ได้ง่าย

Libraries 多做 PJAX heavy lifting Turbolinks well-known Setup: include turbolinks gem ใน Gemfile:


gem 'turbolinks'

...และ include JS ใน app/assets/javascripts/application.js


//= require turbolinks

ตอน reload app ทุก internal links จะเป็น turbolinks click พวกมัน new page requested via AJAX inserted 當前 document

Implementing jquery-pjax

ที่ Honeybadger 用 PJAX library developed by Github ต้อง config มากกว่า Turbolinks แต flexible มาก

แทนที่ assume all links เป็น PJAX ให้ control ได้ 也控制 PJAX content inserted ที่ไหนใน page

First 加 container HTML:


Go to next page.

Setup PJAX link:


$(document).pjax('a', '#pjax-container')

Finally บอก Rails ไม่ render layout on PJAX requests ต้อง做อย่างนี้ ไม่งั้น duplicate headers/footers website 长像 Inception


def index
  if request.headers['X-PJAX']
    render :layout => false
  end
end

It's not that easy!

Ok ซับซ้อนกว่าที่บอก เพราะ giant pitfall 少人พูดถึง

เวลา DOM ไม่ได้ cleared ทุก page load JS ที่ work traditional Rails app ตอนนี้ break แปลกๆ

เหตุผล: 多學寫 JS 方式鼓勵 accidental naming conflicts insidious culprit 簡單 jQuery selector


// 我看起來 innocent 但不!
$(".something")

Writing JS for Pages That Don't Reload

Conflicts #1 problem 寫 JS for pages that never reload weirdest, hard-to-debug problems 發生當 JS manipulates HTML 它不該 touch 例 ordinary jQuery event handler:


$(document).on("click", ".hide-form", function() {
  $(".the-form").hide();
});

Perfectly reasonable ถ้ารันหน้าเดียว แต่ DOM ไม่ reload 遲早有人加 element class .hide-form อีก conflict

Conflicts 發生當有 global references 多 Reduce global references ยังไง? 用 namespaces

Namespacing Selectors

Ruby class 下面 用 one global name - class name - 隱藏 method names 多


# One global name 隱藏 two method names
class MyClass
  def method1; end
  def method2; end
end

雖然無 built-in support namespacing DOM elements (至少直到 ES6 WebComponents) 但 simulate namespaces 用 coding conventions ได้

เช่น implement tag editing widget 沒有 namespacing อาจเป็นแบบนี้ สาม global references:


// 
// 
// 
$(".tag-submit").click(function(){
  save($(".tags").val());
  $(".tag-status").html("Tags were saved");
});

แต่สร้าง "namespace" ทำ element lookups relative to it 減 global references เหลือหนึ่ง ก็ลบ classes 多:


// 
// // // //
$container = $("#tags-component") $container.on("click", "button", function(){ save($container.find("input").val()); $container.find("span").html("Tags were saved"); });

บอกแล้ว simple

ตัวอย่าง namespace DOM elements ใส่ใน container class "tags-component" ไม่มีอะไรพิเศษชื่อนั้น แต่ถ้า adopt naming convention ทุก namespace container class 結尾 "-component" 事情有趣發生

Recognize Incorrect Global Selectors at a Glance

ถ้า global selectors ที่อนุญาตคือ components และทุก components class 結尾 "-component" มองได้ทันทีว่ามี bad global selectors ไหม


// Bad
$(".foo").blah()
// Ok
$(".foo-component").blah()

Easy to Find JS That Controls HTML

Revisit interactive tag form เขียน HTML form ต้อง加 JS 和 CSS 但放ไหน? Luckily naming scheme namespaces แปลง่ายเป็น naming scheme JS/CSS files directory tree:


.
├── javascripts
│   ├── application.coffee
│   └── components
│       └── tags.coffee
└── stylesheets
    ├── application.scss
    └── components
        └── tags.scss

Automatic Initialization

Traditional web app 正常 initialize all JS on page load แต่ PJAX/Turbolinks elements added/removed from DOM ตลอด 益處 code auto-detect 新 components 進 DOM initialize JS needed on the fly

Consistent naming scheme ทำ easy มาก Approaches auto-initialization 无数 一個:


Initializers = {
  tags: function(el){
    $(el).on("click", "button", function(){
      // setup component
    });
  }
  // Other initializers can go here
}

// Handler เรียกทุก normal 和 pjax page load
$(document).on("load, pjax:load", function(){
  for(var key in Initializers){
    $("." + key + "-component").each(Initializers[key]);
  }
})

It Makes Your CSS Better Too!

JavaScript ไม่ใช่แหล่ง conflicts เดียว CSS แย่กว่า! โชคดี naming system 也使 CSS conflict-free 容易 更好在 SCSS:


.tags-component {
  input { ... }
  button { ... }
  span { ... }
}