Web chạy offline với gem service worker
Bài đăng này đã không được cập nhật trong 5 năm
Service worker là công nghệ mới cho phép chạy script bên phía trình duyệt mà không cần có mạng, qua đó giảm khoảng cách của app và web. Giờ đây người dùng chỉ cần vào web và web sẽ trở thành app có thẻ chạy offline và dễ dàng update ngay trên trình duyệt. Nếu bạn muốn tìm hiểu thêm về service worker bạn có thể xem qua bài viết này: Giới thiệu về Service Worker. Trong bài viết này mình sẽ thử làm 1 web có thể chạy offline bằng gem serviceworker-rails với 1 web đọc bài viết trên viblo offline.
Tạo project
Tạo project rails
$ rails new offline --skip-active-record --skip-action-mailer
Thêm 2 gem cần sử dụng vào Gemfile
gem 'httparty'
gem 'serviceworker-rails'
Bundle install thôi
Setup service worker
Install gem trước đã
$ rails g serviceworker:install
Giờ trong project sẽ sinh ra vài file mới.
- config/initializers/serviceworker.rb - Config service worker cho rails app
- app/assets/javascripts/serviceworker.js.erb - Ví dụ về 1 service worker
- app/assets/javascripts/serviceworker-companion.js - Register service worker
- app/assets/javascripts/manifest.json.erb - file manifest cơ bản
- public/offline.html - page sẽ show khi offline
Đồng thời nội dụng các file dưới đây cũng được sửa:
- application.js - require serviceworker-companion.js
- Thêm serviceworker.js và manifest.json vào list compiled assets trong config/initializers/assets.rb
- thêm tag vào head của app/views/layouts/application.html.erb để linking manifest file
Ok giờ thử chạy rails s, vào localhost:3000 để web load về.
Nếu làm đúng bạn sẽ thấy service worker được đăng kí trong application của chrome
Ok giờ tắt thử rails server đi xem, vào lại trang sẽ thấy trang offline hiện ra chứ không phải lỗi của trình duyệt.
Thử cache để chạy offline
Tạo 1 controller đơn giản lấy bài viết từ viblo:
$ rails g controller home index fetch
Tạo route vào controller này:
Rails.application.routes.draw do
root "home#index"
get "/:id", to: "home#fetch", as: "fetch"
end
Dùng HTTParty để lấy bài viết từ viblo ở home_controller.rb:
class HomeController < ApplicationController
def index
response = HTTParty.get('https://viblo.asia/api/posts/newest?limit=20')
json = JSON.parse(response.body)
@data = json["data"].collect {|d| {slug: d["slug"], title: d["title"]} }
end
def fetch
response = HTTParty.get('https://viblo.asia/api/p/' + params[:id])
json = JSON.parse(response.body)
@data = json["contents"]
end
end
index.html.erb:
<ul>
<% @data.each do |data| %>
<li>
<%= link_to data[:title], fetch_path(data[:slug]) %>
</li>
<% end %>
</ul>
fetch.html.erb
<%= @data %>
Ok giờ web chạy online được rồi dù xấu mù, chưa có tí css nào cả. Giờ đến vụ cache. Mặc định sẽ cache trang index, thêm '/' vào cache.addAll trong function onInstall(event) ở file serviceworker.js.erb.
function onInstall(event) {
console.log('[Serviceworker]', "Installing!", event);
event.waitUntil(
caches.open(CACHE_NAME).then(function prefill(cache) {
return cache.addAll([
'<%#= asset_path "application.js" %>',
'<%= asset_path "application.css" %>',
'/offline.html',
'/'
]);
})
);
}
Rồi giờ nếu làm cho vào đọc bài viết nào thì bài viết đò sẽ được cache lại. Thêm 1 đoạn script vào fetch.html.erb thôi:
<script>
caches.open(CACHE_NAME).then(function prefill(cache) {
return cache.addAll([
window.location.pathname
]);
});
</script>
Giờ thử chạy rails, vào ra 1 vài trang bài viết. rồi cắt mạng và chạy thử offline xem.
Tổng kết
Thấy nhiều bài viết phần này nên viết vào cho đúng form. Service worker khá hay và nhiều ứng dụng mà mình mới thấy có vài web lớn như google, youtube... sử dụng. Hi vọng service worker sẽ phổ biến hơn.
All rights reserved