Skip to content

Commit

Permalink
Migrate to streaming app shell via serviceworkers (forem#5020) [deploy]
Browse files Browse the repository at this point in the history
* Initial work for streaming app shell way of using serviceworkers

* Close in on serviceworker adjustment finalization

* Add docs and loading indicator

* Remove useless code

* Don't run on API

* Update app/javascript/contentDisplayPolicy/hideBlockedContent.js

* Fix small details

* Don't run serviceworker.js code in test env

* Fix JS in serviceworker

* Move private keyword to proper place in async controller

* Change shell_version to HEROKU_SLUG_COMMIT

* Update caching config

* Add test for async_info/shell_version
  • Loading branch information
benhalpern authored Dec 16, 2019
1 parent 70e1ffb commit 630c1b7
Show file tree
Hide file tree
Showing 32 changed files with 403 additions and 341 deletions.
31 changes: 31 additions & 0 deletions app/assets/stylesheets/scaffolds.scss
Original file line number Diff line number Diff line change
Expand Up @@ -267,6 +267,7 @@ body.trusted-status-true .trusted-visible-block {
color: white;
display: inline-block;
margin-bottom: 0px;
border-radius: 3px;
}
h2 {
font-size: 22px;
Expand All @@ -281,4 +282,34 @@ body.trusted-status-true .trusted-visible-block {
opacity: 0.9;
}
}
form button {
background: $red;
color: white;
font-size: 1.5em;
border: 0px;
border-radius: 3px;
padding: 6px 12px;
}
}

.app-shell-loader {
position: absolute;
top: 200px;
text-align: center;
left: 0;
right: 0;
opacity: 0;
animation: loading-fadein 1.5s;
animation-delay: 0.6s;
font-size: 1.2em;
z-index: -1;
}

.base-background-color {
@include themeable(background, theme-background, $lightest-gray);
}

@keyframes loading-fadein {
from { opacity: 0; }
to { opacity: 0.6; }
}
7 changes: 7 additions & 0 deletions app/assets/stylesheets/settings.scss
Original file line number Diff line number Diff line change
Expand Up @@ -670,6 +670,13 @@
.signout_confirm-wrapper {
padding: calc(15% + 50px) 2% 30%;
text-align: center;
form button {
font-size: 1.5em;
padding: 8px 15px;
border: 0px;
border-radius: 3px;
margin-top: 15px;
}
}

.org-widget-preview .primary-sticky-nav {
Expand Down
2 changes: 1 addition & 1 deletion app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def customize_params
def after_sign_in_path_for(resource)
return "/onboarding?referrer=#{request.env['omniauth.origin'] || 'none'}" unless current_user.saw_onboarding

request.env["omniauth.origin"] || stored_location_for(resource) || "/dashboard"
(request.env["omniauth.origin"] || stored_location_for(resource) || "/dashboard") + "?signin=true" # This signin=true param is used by frontend
end

def raise_banned
Expand Down
8 changes: 8 additions & 0 deletions app/controllers/async_info_controller.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
class AsyncInfoController < ApplicationController
include Devise::Controllers::Rememberable
# No pundit policy. All actions are unrestricted.
before_action :set_cache_control_headers, only: %i[shell_version]

def base_data
flash.discard(:notice)
Expand Down Expand Up @@ -29,6 +30,13 @@ def base_data
end
end

def shell_version
set_surrogate_key_header "shell-version-endpoint"
# shell_version will change on every deploy. *Technically* could be only on changes to assets and shell, but this is more fool-proof.
shell_version = ApplicationConfig["HEROKU_SLUG_COMMIT"]
render json: { version: Rails.env.production? ? shell_version : rand(1000) }.to_json
end

def user_data
Rails.cache.fetch(user_cache_key, expires_in: 15.minutes) do
{
Expand Down
13 changes: 13 additions & 0 deletions app/controllers/shell_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
class ShellController < ApplicationController
layout false

def top
@shell = true
render partial: "top"
end

def bottom
@shell = true
render partial: "bottom"
end
end
32 changes: 0 additions & 32 deletions app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -15,38 +15,6 @@ def view_class
end
end

def core_pages?
%w[
articles
podcast_episodes
events
tags
registrations
users
pages
chat_channels
dashboards
moderations
videos
badges
stories
comments
notifications
reading_list_items
html_variants
classified_listings
credits
partnerships
pro_memberships
].include?(controller_name)
end

def render_js?
article_pages = controller_name == "articles" && %(index show).include?(controller.action_name)
pulses_pages = controller_name == "pulses"
!(article_pages || pulses_pages)
end

def title(page_title)
derived_title = if page_title.include?(ApplicationConfig["COMMUNITY_NAME"])
page_title
Expand Down
3 changes: 3 additions & 0 deletions app/javascript/chat/chat.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,9 @@ export default class Chat extends Component {
channel => `open-channel-${channel.chat_channel_id}`,
);
setupObserver(this.observerCallback);
if (!window.currentUser) {
window.currentUser = JSON.parse(document.body.dataset.user)
}
this.subscribePusher(
`private-message-notifications-${window.currentUser.id}`,
);
Expand Down
4 changes: 2 additions & 2 deletions app/javascript/contentDisplayPolicy/hideBlockedContent.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@ export default function hideBlockedContent() {
const contentUserElements = Array.from(
document.querySelectorAll('div[data-content-user-id]'),
);
/* eslint-disable-next-line no-undef */
const blockedUserIds = userData().blocked_user_ids;
const user = userData(); //global var
const blockedUserIds = user ? user.blocked_user_ids : [];

const divsToHide = contentUserElements.filter(div => {
const { contentUserId } = div.dataset;
Expand Down
9 changes: 3 additions & 6 deletions app/views/articles/delete_confirm.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
<%= javascript_include_tag "application" %>

<div class="container delete-confirm">
<h4><%= @article.title %></h4>
<h1>Are you sure you want to delete this article?</h1>
Expand All @@ -11,8 +9,7 @@
</a>
instead?
</h2>

<h2>
<a class="delete-link" data-no-instant rel="nofollow" data-method="delete" href="/articles/<%= @article.id %>">DELETE</a>
</h2>
<%= form_tag "/articles/#{@article.id}", method: :delete do %>
<button class="cta">DELETE</button>
<% end %>
</div>
1 change: 0 additions & 1 deletion app/views/articles/index.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
<% end %>
<%= javascript_pack_tag "homePage", defer: true %>

<% params.delete(:i) %>
<% cache("main-stories-index-#{params}-#{user_signed_in?}", expires_in: 3.minutes) do %>
<div class="home" id="index-container"
data-params="<%= params.to_json(only: %i[tag username q]) %>" data-which="<%= @list_of %>"
Expand Down
1 change: 0 additions & 1 deletion app/views/articles/tag_index.html.erb
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
<%= content_for :page_meta do %>
<%= render "articles/tags/meta" %>
<% end %>
<% params.delete(:i) %>
<% expiry_minutes = params[:timeframe].blank? || params[:timeframe] == "latest" ? 4 : 20 %>
<% flag = true %>
<% cache("tag-stories-index-#{params}-#{flag}-#{@tag_model.updated_at}", expires_in: expiry_minutes.minutes) do %>
Expand Down
6 changes: 3 additions & 3 deletions app/views/classified_listings/delete_confirm.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
instead?
</h2>

<h2>
<a class="delete-link" data-no-instant rel="nofollow" data-method="delete" href="/listings/<%= @classified_listing.id %>">DELETE</a>
</h2>
<%= form_tag "/listings/#{@classified_listing.id}", method: :delete do %>
<button class="cta">DELETE</button>
<% end %>
</div>
8 changes: 3 additions & 5 deletions app/views/comments/delete_confirm.html.erb
Original file line number Diff line number Diff line change
@@ -1,14 +1,12 @@
<%= javascript_include_tag "application" %>

<div class="container delete-confirm">

<h4><%= truncate(strip_tags(@comment.processed_html.html_safe), length: 80) %></h4>
<h1>Are you sure you want to delete this comment?</h1>
<h2>You cannot undo this action, perhaps you just want to
<a data-no-instant href="<%= @comment.path %>/edit">EDIT</a> instead?</h2>

<h2>
<a class="delete-link" data-no-instant rel="nofollow" data-method="delete" href="/comments/<%= @comment.id %>">DELETE</a>
</h2>
<%= form_tag "/comments/#{@comment.id}", method: :delete do %>
<button class="cta">DELETE</button>
<% end %>

</div>
2 changes: 1 addition & 1 deletion app/views/layouts/_nav_menu.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
Key Links
</div>
</a>
<a href="/signout_confirm" data-no-instant id="last-nav-link">
<a href="/signout_confirm" id="last-nav-link">
<div class="option">
Sign Out
</div>
Expand Down
13 changes: 8 additions & 5 deletions app/views/layouts/_styles.html.erb
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
<% cache "base_inline_styles_#{@story_show}_#{@article_index}_#{@home_page}_#{@article_show}_#{view_class}_#{@notifications_index}_#{core_pages?}_#{@tags_index}_#{@reading_list_items_index}_#{@history_index}_#{ApplicationConfig['HEROKU_SLUG_COMMIT']}_#{user_signed_in?}", expires_in: 8.hours do %>
<% if @story_show %>
<% cache "base_inline_styles_#{@story_show}_#{@article_index}_#{@home_page}_#{@article_show}_#{view_class}_#{@notifications_index}_#{@tags_index}_#{@reading_list_items_index}_#{@history_index}_#{ApplicationConfig['HEROKU_SLUG_COMMIT']}_#{user_signed_in?}_#{@shell}", expires_in: 8.hours do %>
<% if @shell %>
<style>
<% Rails.application.config.assets.compile = true %>
<%= Rails.application.assets["minimal.css"].to_s.html_safe %>
</style>
<% elsif @story_show %>
<style>
<% Rails.application.config.assets.compile = true %>
<%= Rails.application.assets["scaffolds.css"].to_s.html_safe %>
Expand Down Expand Up @@ -100,9 +105,7 @@
<style>
<%= Rails.application.assets["badges.css"].to_s.html_safe %>
</style>
<% elsif core_pages? %>
<%= stylesheet_link_tag "minimal", media: "all" %>
<% else %>
<%= stylesheet_link_tag "application", media: "all" %>
<%= stylesheet_link_tag "minimal", media: "all" %>
<% end %>
<% end %>
121 changes: 12 additions & 109 deletions app/views/layouts/application.html.erb
Original file line number Diff line number Diff line change
@@ -1,110 +1,13 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<% title = yield(:title) %>
<title><%= title || "#{ApplicationConfig['COMMUNITY_NAME']} Community" %></title>
<% if internal_navigation? %>
<style>
.universal-page-content-wrapper {
visibility: hidden;
}
</style>
<% else %>
<meta name="last-updated" content="<%= Time.current %>">
<meta name="user-signed-in" content="<%= user_signed_in? %>">
<meta name="algolia-public-id" content="<%= ApplicationConfig["ALGOLIASEARCH_APPLICATION_ID"] %>">
<meta name="algolia-public-key" content="<%= ALGOLIASEARCH_PUBLIC_SEARCH_ONLY_KEY %>">
<meta name="environment" content="<%= Rails.env %>">
<%= render "layouts/styles" %>
<style>
.home {
overflow: hidden;
position: relative;
text-align: center;
min-height: 440px;
margin: auto;
max-width: 1250px;
}

@media screen and (min-width: 950px) {
.home {
margin-top: 26px;
}
}
</style>
<%= javascript_pack_tag "manifest", defer: true %>
<%= javascript_pack_tag "vendor", defer: true %>
<%= javascript_pack_tag "Search", defer: true %>
<% if core_pages? %>
<%= javascript_include_tag "base", defer: true %>
<% if user_signed_in? %>
<%= javascript_pack_tag "onboardingRedirectCheck", defer: true %>
<%= javascript_pack_tag "contentDisplayPolicy", defer: true %>
<% end %>
<% end %>
<% if !core_pages? %>
<%= stylesheet_link_tag "application", media: "all" %>
<% if render_js? %>
<link href='https://fonts.googleapis.com/css?family=Roboto' rel='stylesheet' type='text/css'>
<%= javascript_include_tag "application" %>
<% end %>
<% end %>
<% if view_class == "users users-signout_confirm" %>
<%= javascript_include_tag "application" %>
<% end %>
<%= yield(:page_meta) %>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<%= favicon_link_tag ApplicationConfig["FAVICON_URL"] %>
<link rel="apple-touch-icon" href="<%= asset_path "apple-icon.png" %>">
<link rel="apple-touch-icon" sizes="152x152" href="<%= asset_path "apple-icon-152x152.png" %>">
<link rel="apple-touch-icon" sizes="180x180" href="<%= asset_path "apple-icon-180x180.png" %>">
<link rel="apple-touch-icon" sizes="167x167" href="<%= asset_path "apple-icon-167x167.png" %>">
<link href="<%= asset_path "android-icon-192x192.png" %>" rel="icon" sizes="192x192" />
<link href="<%= asset_path "android-icon-128x128.png" %>" rel="icon" sizes="128x128" />
<meta name="apple-mobile-web-app-title" content="dev.to">
<meta name="application-name" content="dev.to">
<meta property="fb:pages" content="568966383279687" />
<meta name="theme-color" content="#000000" />
<% if view_class.include? "users-signout_confirm" %>
<%= csrf_meta_tags %>
<% end %>
<link rel="manifest" href="/manifest.json" />
<link rel="search" href="https://dev.to/search.xml" type="application/opensearchdescription+xml" title="<%= community_qualified_name %>" />
<% end %>
</head>
<body data-user-status="<%= user_logged_in_status %>" data-pusher-key="<%= ApplicationConfig["PUSHER_KEY"] %>">
<div id="body-styles"></div>
<% if user_signed_in? && !internal_navigation? %>
<%= render "layouts/user_config" %>
<% end %>
<% unless internal_navigation? %>
<div id="audiocontent">
<%= yield(:audio) %>
</div>
<% end %>
<% cache("application-top-bar--#{user_signed_in?}--#{internal_navigation?}", expires_in: 100.hours) do %>
<%= render "layouts/top_bar" unless internal_navigation? %>
<% end %>
<div id="message-notice"></div>
<div id="page-content" class="universal-page-content-wrapper <%= view_class %>" data-current-page="<%= current_page %>">
<% if flash[:global_notice] %>
<div class="global-notice">
<%= flash[:global_notice] %>
</div>
<% end %>
<div id="page-content-inner">
<%= yield %>
</div>
<%= render "shell/top" %>
<style>.app-shell-loader {display: none;}</style>
<div id="page-content" class="universal-page-content-wrapper <%= view_class %>" data-current-page="<%= current_page %>">
<% if flash[:global_notice] %>
<div class="global-notice">
<%= flash[:global_notice] %>
</div>
<% unless internal_navigation? %>
<% cache("footer-and-signup-modal--#{user_signed_in?}--#{ApplicationConfig['HEROKU_SLUG_COMMIT']}", expires_in: 24.hours) do %>
<%= render "layouts/footer" %>
<%= render "layouts/signup_modal" unless user_signed_in? %>
<% end %>
<div id="live-article-indicator" class="live-article-indicator"></div>
<%= image_tag("twitter-logo.svg", class: "icon-img", style: "display:none", alt: "twitter logo") %>
<%= image_tag("github-logo.svg", class: "icon-img", style: "display:none", alt: "github logo") %>
<% end %>
</body>
</html>
<% end %>
<div id="page-content-inner">
<%= yield %>
</div>
</div>
<%= render "shell/bottom" %>
Loading

0 comments on commit 630c1b7

Please sign in to comment.