Slide 1

Slide 1 text

No content

Slide 2

Slide 2 text

RAILS FRONTEND: 2016 and That Sprockets Talk

Slide 3

Slide 3 text

Vipul A M @vipulnsward

Slide 4

Slide 4 text

No content

Slide 5

Slide 5 text

timezones 1.Mumbai TimeZone (UTC+05:30) 2.Taiwan TimeZone (UTC+08:00) 3.Pacific Time Zone (UTC-08:00) 4.Singapore Time Zone (UTC+08:00)

Slide 6

Slide 6 text

timezones

Slide 7

Slide 7 text

timezones

Slide 8

Slide 8 text

timezones +

Slide 9

Slide 9 text

timezones +=

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

No content

Slide 14

Slide 14 text

No content

Slide 15

Slide 15 text

No content

Slide 16

Slide 16 text

No content

Slide 17

Slide 17 text

Rails 5

Slide 18

Slide 18 text

http://blog.bigbinary.com/categories/Rails-5 Rails 5 Blog Series (55+ and counting)

Slide 19

Slide 19 text

Sprockets: *Spotlight

Slide 20

Slide 20 text

Sprockets https://speakerdeck.com/rafaelfranca/how-sprockets-works

Slide 21

Slide 21 text

Sprockets 1. sprockets 2. sprockets-rails 3. sass-rails 4. execjs 5. coffee-rails

Slide 22

Slide 22 text

manifest.js # In Rails configuration
 config.assets.precompile += [“payment.css”, “advertising.css"] <%= stylesheet_link_tag "advertising" %> 


Slide 23

Slide 23 text

manifest.js config.assets.precompile = [“manifest.js”] // app/assets/config/manifest.js //= link_tree ../images
 //= link_directory ../stylesheets .css //= link application.css
 //= link advertising.css
 //= link payment.css
 //= link application.js


Slide 24

Slide 24 text

manifest.js <%= stylesheet_link_tag "advertising" %> .logo {
 background: url(<%= asset_url("logo.png") %>)
 }

Slide 25

Slide 25 text

folders as modules foo/index.js <%= asset_path("foo/index.js") %>
 <%= asset_path("foo.js") %>

Slide 26

Slide 26 text

folders as modules //= require_tree . foo/jquery-ui.js and foo/jquery.min.js Now: //= require foo.js # foo/index.js //= require foo.min.js
 //= require foo-ui.js


Slide 27

Slide 27 text

sourcemaps.js

Slide 28

Slide 28 text

sourcemaps.js

Slide 29

Slide 29 text

sourcemaps.js //# sourceMappingURL= File: public/assets/application.js Map: public/assets/application.js.map //# sourceMappingURL=/assets/application.js.map /*# sourceMappingURL=application.css.map */

Slide 30

Slide 30 text

sourcemaps.js

Slide 31

Slide 31 text

sourcemaps.js

Slide 32

Slide 32 text

ES2016!

Slide 33

Slide 33 text

ES2016! 1. Arrows and Lexical This 2. Classes 3. Enhanced Object Literals 4. Template Strings 5. Destructuring 6. Default + Rest + Spread 7. Let + Const 8. Iterators + For..Of 9. Symbols, etc

Slide 34

Slide 34 text

ES2016!

Slide 35

Slide 35 text

ES2016!

Slide 36

Slide 36 text

ES2016!

Slide 37

Slide 37 text

12x @schneems https://engineering.heroku.com/blogs/2016-02-18- speeding-up-sprockets/

Slide 38

Slide 38 text

1.raw asset 2.processed asset 3.bundled 4.compressed 5.asset fingerprint 6.minified 7.etc 12x

Slide 39

Slide 39 text

# https://github.com/rails/sprockets/blob/543a5a27190c26de8f3a1b03e18aed8da0367c63/lib/sprockets/base.rb#L46-L57
 
 def file_digest(path)
 if stat = File.stat(path)
 cache.fetch("file_digest:#{path}:#{stat.mtime.to_i}") do
 Digest::SHA256.file(path.to_s).digest
 end
 end
 end 12x

Slide 40

Slide 40 text

“file_digest:/Users/schneems/my_project/app/assets/javascripts/application.js: 123456” "file_digest:/+Other/path/+my_project/app/assets/javascripts/application.js: 123456" 12x

Slide 41

Slide 41 text

# https://github.com/rails/sprockets/blob/9ca80fe00971d45ccfacb6414c73d5ffad96275f/lib/sprockets/loader.rb#L55-L58 digest = DigestUtils.digest(resolve_dependencies(paths))
 if uri_from_cache = cache.get(unloaded.digest_key(digest), true)
 asset_from_cache(UnloadedAsset.new(uri_from_cache, self).asset_key)
 end 12x!

Slide 42

Slide 42 text

<%= javascript_include_tag :application, integrity: true %> 


Slide 43

Slide 43 text

*Headers

Slide 44

Slide 44 text

*Header

Slide 45

Slide 45 text

ETag

Slide 46

Slide 46 text

class ItemsController < ApplicationController
 def show
 @item = Item.find(params[:id])
 fresh_when @item
 end
 end Etag

Slide 47

Slide 47 text

$ curl -i http://localhost:3000/items/1
 
 HTTP/1.1 200 OK
 X-Frame-Options: SAMEORIGIN
 X-Xss-Protection: 1; mode=block
 X-Content-Type-Options: nosniff
 Etag: "618bbc92e2d35ea1945008b42799b0e7"
 Last-Modified: Sat, 30 Jan 2016 08:02:12 GMT
 Content-Type: text/html; charset=utf-8
 Cache-Control: max-age=0, private, must-revalidate
 X-Request-Id: 98359119-14ae-4e4e-8174-708abbc3fd4b
 X-Runtime: 0.412232
 Server: WEBrick/1.3.1 (Ruby/2.2.2/2015-04-13)
 Date: Fri, 04 Mar 2016 10:50:38 GMT
 Content-Length: 1014
 Connection: Keep-Alive Etag

Slide 48

Slide 48 text

$ curl -i -H 'If-None-Match: "618bbc92e2d35ea1945008b42799b0e7"' http:// localhost:3000/items/1
 
 HTTP/1.1 304 Not Modified
 X-Frame-Options: SAMEORIGIN
 X-Xss-Protection: 1; mode=block
 X-Content-Type-Options: nosniff
 Etag: "618bbc92e2d35ea1945008b42799b0e7"
 Last-Modified: Sat, 30 Jan 2016 08:02:12 GMT
 Cache-Control: max-age=0, private, must-revalidate
 X-Request-Id: e4447f82-b96c-4482-a5ff-4f5003910c18
 X-Runtime: 0.012878
 Server: WEBrick/1.3.1 (Ruby/2.2.2/2015-04-13)
 Date: Fri, 04 Mar 2016 10:51:22 GMT
 Connection: Keep-Alive Etag

Slide 49

Slide 49 text

Strong Etag: ”543b39c23d8d34c232b457297d38ad99" Weak ETag: W/“543b39c23d8d34c232b457297d38ad99" Etag

Slide 50

Slide 50 text

# app/controllers/home_controller.rb
 class HomeController < ApplicationController
 def index
 render
 end
 end
 
 # app/views/home/index.html.erb


Welcome

http_cache_forever

Slide 51

Slide 51 text

Processing by HomeController#index as HTML
 Rendered home/index.html.erb within layouts/ application (1.3ms)
 Completed 200 OK in 224ms (Views: 212.4ms | ActiveRecord: 0.0ms)
 
 And so on for every request for this action.
 http_cache_forever

Slide 52

Slide 52 text

# app/controllers/home_controller.rb
 class HomeController < ApplicationController
 def index
 http_cache_forever(public: true) {}
 end
 end
 
 # OR
 class HomeController < ApplicationController
 def index
 http_cache_forever(public: true) do
 render
 end
 end
 end
 
 
 # app/views/home/index.html.erb


Welcome

http_cache_forever

Slide 53

Slide 53 text

# When request is made for the first time.
 
 Processing by HomeController#index as HTML
 Rendered home/index.html.erb within layouts/ application (1.3ms)
 Completed 200 OK in 224ms (Views: 212.4ms | ActiveRecord: 0.0ms)
 
 # For consecutive requests for the same page
 
 Processing by HomeController#index as HTML
 Completed 304 Not Modified in 2ms (ActiveRecord: 0.0ms) http_cache_forever

Slide 54

Slide 54 text

⛔ Cache-Control: max-age=3155760000 http_cache_forever

Slide 55

Slide 55 text

Asset Headers

Slide 56

Slide 56 text

response.headers['X-Tracking-ID'] = '123456' Headers in Simple Responses

Slide 57

Slide 57 text

# open config/environments/production.rb and add following line
 config.static_cache_control = 'public, max-age=1000' Asset Headers

Slide 58

Slide 58 text

PageSpeed Warnings

Slide 59

Slide 59 text

Missing Expires header

Slide 60

Slide 60 text

# production.rb
 
 config.public_file_server.headers = {
 'Cache-Control' => 'public, s-maxage=31536000, maxage=15552000',
 'Expires' => "#{1.year.from_now.to_formatted_s(:rfc822)}"
 } Public Asset Header

Slide 61

Slide 61 text

Result

Slide 62

Slide 62 text

Caching

Slide 63

Slide 63 text

1.Page Caching 2.Action Caching 3.Fragment Caching 4.Russian Doll Caching 5.Low-Level Caching 6.SQL Caching http://edgeguides.rubyonrails.org/ caching_with_rails.html Caching

Slide 64

Slide 64 text

# index.html.erb
 <%= render partial: 'todo', collection: @todos %>
 
 # _todo.html.erb
 <% cache todo do %>
 <%= todo.name %>
 <% end %>
 Partial rendering from cache

Slide 65

Slide 65 text

# index.html.erb
 <%= render partial: 'todo', collection: @todos, cached: true %>
 
 # _todo.html.erb
 <% cache todo do %>
 <%= todo.name %>
 <% end %> multi_fetch_fragments

Slide 66

Slide 66 text

cached: true => read_multi Rendered collection of todos/_todo.html.erb [100 / 100 cache hits] (339.5ms) multi_fetch_fragments

Slide 67

Slide 67 text

72% read_multi

Slide 68

Slide 68 text

config.action_mailer.perform_caching = true ActionMailer Fragment Caching

Slide 69

Slide 69 text


 
 <% cache 'signup-text' do %>


Welcome to <%= @company.name %>

You have successfully signed up to <%= @company.name %>, Your username is:
 <% end %>
 
 <%= @user.login %>.



 
 <%= render :partial => 'footer' %>
 
 ActionMailer Fragment Caching

Slide 70

Slide 70 text

Cache digest for app/views/user_mailer/_footer.erb: 7313427d26cc1f701b1e0212498cee38
 Cache digest for app/views/user_mailer/welcome_email.html.erb: 30efff0173fd5f29a88ffe79a9eab617
 Rendered user_mailer/_footer.erb (0.3ms)
 Rendered user_mailer/welcome_email.html.erb (26.1ms)
 Cache digest for app/views/user_mailer/welcome_email.text.erb: 77f41fe6159c5736ab2026a44bc8de55
 Rendered user_mailer/welcome_email.text.erb (0.2ms)
 UserMailer#welcome_email: processed outbound mail in 190.3ms ActionMailer Fragment Caching

Slide 71

Slide 71 text

ActiveRecord::Relation#cache_key Caching result sets and collection

Slide 72

Slide 72 text

@users = User.where(city: 'miami') 1.The query statement doesn’t change. If we change city name from “Miami” to “Boston” then result might change. 2.No record is deleted. 3.No record is added. Caching result sets and collection

Slide 73

Slide 73 text

@users = User.where(city: 'Miami')
 @users.cache_key
 => "users/query-67ed32b36805c4b1ec1948b4eef8d58f-3-20160116111659084027" # users.html.erb cache @users do 
 #content here
 end Caching result sets and collection

Slide 74

Slide 74 text

*Layouts and Tags.

Slide 75

Slide 75 text

async-defer www.growingwiththeweb.com/2014/02/async-vs-defer-attributes.html

Slide 76

Slide 76 text

simple

Slide 77

Slide 77 text

Slide 78

Slide 78 text

Slide 79

Slide 79 text

Defaults

Slide 80

Slide 80 text

Pagespeed

Slide 81

Slide 81 text

1.Placement of JS/CSS imports 2.Font imports 3.Analytics tags 4.Proper viewports 5.responsive 6.Inlining resources, css/js, etc PageSpeed

Slide 82

Slide 82 text


 
 
 … 
 <%= @page_title || default_page_title %> | BigBinary
 
 <%= stylesheet_link_tag "application.css", 'data-turbolinks- track' => true %>
 …
 <%= csrf_meta_tags %>
 
 
 <%= yield %>
 
 try{Typekit.load({ async: true });}catch(e){}
 
 <%= javascript_include_tag "application.js", media: 'all', 'data-turbolinks-track' => true, async: true, defer: true %>
 
 
 


Slide 83

Slide 83 text

No content

Slide 84

Slide 84 text

Fin.

Slide 85

Slide 85 text

Fin.

Slide 86

Slide 86 text

Images: flickr.com/search/? text=singapore&license=2%2C3%2C4%2C5%2C6%2C9 http://blog.bigbinary.com/categories/Rails%205 https://www.packtpub.com/web-development/reactjs-example-building- modern-web-applications-react http://www.growingwiththeweb.com/2014/02/async-vs-defer- attributes.html https://speakerdeck.com/rafaelfranca/how-sprockets-works https://thenounproject.com/search/?q=sprocket&i=283880 References