Skip to content

Instantly share code, notes, and snippets.

@alexamies
Last active October 16, 2018 23:32
Show Gist options
  • Save alexamies/db324bfdf8a7cd25493bce47be0fdc5d to your computer and use it in GitHub Desktop.
Save alexamies/db324bfdf8a7cd25493bce47be0fdc5d to your computer and use it in GitHub Desktop.

Revisions

  1. @alexpamies alexpamies revised this gist Oct 16, 2018. 1 changed file with 2 additions and 1 deletion.
    3 changes: 2 additions & 1 deletion README.md
    Original file line number Diff line number Diff line change
    @@ -31,7 +31,7 @@ gsutil cp *.js gs://${BUCKET}

    Enable the bucket as a web site
    ```
    gsutil web set -m index.html -e 404.html gs://${BUCKET}
    gsutil web set -m index.html -e notfound.html gs://${BUCKET}
    ```

    Make the pages [public](https://cloud.google.com/storage/docs/access-control/making-data-public#buckets)
    @@ -147,3 +147,4 @@ the service worker included. You should find that the No. 1
    (no 200 offline) and No. 3 (no HTTPS) problems are now obsent from the list of
    Progressive Web App problems. The top problem is now 'User will not be prompted
    to Install the Web App.'

  2. @alexpamies alexpamies renamed this gist Oct 16, 2018. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  3. @alexpamies alexpamies revised this gist Oct 16, 2018. 1 changed file with 11 additions and 0 deletions.
    11 changes: 11 additions & 0 deletions 404.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,11 @@
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>Sorry</title>
    </head>
    <h1>Sorry</h1>
    <body>
    <p>We could not find that page</p>
    </body>
    </html>
  4. @alexpamies alexpamies revised this gist Oct 16, 2018. 1 changed file with 0 additions and 20 deletions.
    20 changes: 0 additions & 20 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -147,23 +147,3 @@ the service worker included. You should find that the No. 1
    (no 200 offline) and No. 3 (no HTTPS) problems are now obsent from the list of
    Progressive Web App problems. The top problem is now 'User will not be prompted
    to Install the Web App.'

    ## Network Performance
    So far our network performance looks pretty good. That is because the are
    no big files in our app. The HTML and JavaScript files are few and small.
    However, apps typically introduce performance problems as the code base
    increases and they collect more assets as the business grows. The
    [Lighthouse](https://developers.google.com/web/tools/lighthouse/audits/text-compression)
    reference has a list of suggestions for improving performance and these relate
    to measurements reported in Chrome Dev Tools. One common example of a suggested
    improvement is to [Enable Text
    Compression](https://developers.google.com/web/tools/lighthouse/audits/text-compression).


    ## Serving Compressed Text with Google Cloud Storage



    ==========
    Domain
    alexamiestest.esodemoapp2.com
  5. @alexpamies alexpamies created this gist Oct 16, 2018.
    169 changes: 169 additions & 0 deletions README.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,169 @@
    # Using Chrome Dev Tools with Google Cloud
    This file contains instructions for optimizing a static web site on
    [Google Cloud Platform](https://cloud.google.com/) with Chrome Developer Tools.
    The final solution is contained in index.html. Intermediate solutions have are
    given in files index1.html, etc.

    ## Setting up a Static Website on Google Cloud Storage
    Static content can be easily hosted on GCP using the
    GCS features for [Hosting a Static
    Website](https://cloud.google.com/storage/docs/hosting-static-website).
    You will need a domain and point that to Cloud Storage by using a CNAME record.

    Check that the right project is set
    ```
    PROJECT=[Your project]
    gcloud config set project $PROJECT
    ```

    To create a bucket matching the domain you need to perform [Domain-Named Bucket
    Verification](https://cloud.google.com/storage/docs/domain-name-verification).
    After doing that, create the bucket with the command
    ```
    BUCKET=[Your domain]
    gsutil mb gs://${BUCKET}
    ```
    Copy the web site files
    ```
    gsutil cp *.html gs://${BUCKET}
    gsutil cp *.js gs://${BUCKET}
    ```

    Enable the bucket as a web site
    ```
    gsutil web set -m index.html -e 404.html gs://${BUCKET}
    ```

    Make the pages [public](https://cloud.google.com/storage/docs/access-control/making-data-public#buckets)
    ```
    gsutil iam ch allUsers:objectViewer gs://${BUCKET}
    gsutil acl ch -u AllUsers:R gs://${BUCKET}
    ```

    Test the initial solution:
    ```
    curl http://${BUCKET}/index1.html
    ```

    ## Analyze the Website with Lighthouse
    Navigate to the page http://${BUCKET}/index1.html in Chrome and
    ppen up [Lighthouse](https://developers.google.com/web/tools/lighthouse/) in
    Chrome Developer Tools by clicking on the Audit tab. Run the
    analysis by clicking the 'Run Audits' button.

    When I ran this in October 2019 the top item on the list was 'Does not respond
    with a 200 when offline.' You
    can enable a static website to be accessed offline by using a [Service
    Worker](https://developers.google.com/web/fundamentals/primers/service-workers/)
    to cache. The files main.js and sw.js implement that. However,
    service workers [require
    HTTPS](https://developers.google.com/web/fundamentals/primers/service-workers/#you_need_https).
    This also the third item on the Lighthouse audit list: 'Does not use HTTPS.'
    So we will start by enabling HTTPS.

    ## Enabling HTTPS for a Static Website wit an L7 Load Balancer
    Here are the instructions to add HTTPS to a static web site in Google Cloud
    Storage by adding a HTTPS load balancer with the storage bucket as a backend.

    Create a global static IP address:
    ```
    IP_NAME=lb-ip
    gcloud compute addresses create $IP_NAME \
    --ip-version=IPV4 \
    --global
    ```

    Now add a [Cloud Storage Bucket backend](https://cloud.google.com/load-balancing/docs/https/adding-a-backend-bucket-to-content-based-load-balancing) to the load balancer
    using the
    [gcloud compute backend-buckets create](https://cloud.google.com/sdk/gcloud/reference/compute/backend-buckets/create)
    command:
    ```
    BACKEND_BUCKET_NAME=static-bucket
    gcloud compute backend-buckets create $BACKEND_BUCKET_NAME \
    --gcs-bucket-name $BUCKET
    ```
    Create a URL Map for content based load balancing using the
    [gcloud compute url-maps create](https://cloud.google.com/sdk/gcloud/reference/compute/url-maps/create) command:

    ```
    URL_MAP_NAME=web-map
    gcloud compute url-maps create $URL_MAP_NAME \
    --default-backend-bucket=$BACKEND_BUCKET_NAME
    ```

    Add a path matcher using the [gcloud compute url-maps
    add-path-matcher](https://cloud.google.com/sdk/gcloud/reference/compute/url-maps/add-path-matcher) command:
    ```
    PATH_MATCHER_NAME=bucket-matcher
    gcloud compute url-maps add-path-matcher $URL_MAP_NAME \
    --default-backend-bucket=$BACKEND_BUCKET_NAME \
    --path-matcher-name $PATH_MATCHER_NAME \
    ```

    Create a Google managed TLS certificate with the
    [gcloud beta compute ssl-certificates create](https://cloud.google.com/sdk/gcloud/reference/beta/compute/ssl-certificates/create) command:
    ```
    CERT_NAME=${PROJECT}-cert
    DOMAIN=[Your domain]
    gcloud beta compute ssl-certificates create $CERT_NAME \
    --domains $DOMAIN
    ```

    Create a target proxy with the [gcloud compute target-https-proxies create](https://cloud.google.com/sdk/gcloud/reference/compute/target-https-proxies/create) command
    ```
    PROXY_NAME=https-lb-proxy
    gcloud compute target-https-proxies create $PROXY_NAME \
    --url-map $URL_MAP_NAME --ssl-certificates $CERT_NAME
    ```

    Enable QUIC for the proxy
    ```
    gcloud compute target-https-proxies update $PROXY_NAME \
    --quic-override=ENABLE
    ```

    Create a forwarding rule with the [gcloud compute forwarding-rules create](https://cloud.google.com/sdk/gcloud/reference/compute/forwarding-rules/create) command:
    ```
    FWD_NAME=https-content-rule
    gcloud compute forwarding-rules create $FWD_NAME \
    --address $IP_NAME \
    --global \
    --target-https-proxy $PROXY_NAME \
    --ports 443
    ```

    Now that you are using a load balancer for the site, change the DNS record
    to an A record that refers to the static IP address used by the load balancer.
    You might need to wait for a while for this to take effect, depending on your
    DNS TTL.

    Send traffic to the load balancer
    ```
    curl https://$DOMAIN/index2.html
    ```

    Run the analysis again in Chrome Dev Tools for the page index2.html, which has
    the service worker included. You should find that the No. 1
    (no 200 offline) and No. 3 (no HTTPS) problems are now obsent from the list of
    Progressive Web App problems. The top problem is now 'User will not be prompted
    to Install the Web App.'

    ## Network Performance
    So far our network performance looks pretty good. That is because the are
    no big files in our app. The HTML and JavaScript files are few and small.
    However, apps typically introduce performance problems as the code base
    increases and they collect more assets as the business grows. The
    [Lighthouse](https://developers.google.com/web/tools/lighthouse/audits/text-compression)
    reference has a list of suggestions for improving performance and these relate
    to measurements reported in Chrome Dev Tools. One common example of a suggested
    improvement is to [Enable Text
    Compression](https://developers.google.com/web/tools/lighthouse/audits/text-compression).


    ## Serving Compressed Text with Google Cloud Storage



    ==========
    Domain
    alexamiestest.esodemoapp2.com
    23 changes: 23 additions & 0 deletions index.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,23 @@
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>GCS Static Page</title>
    </head>
    <h1>GCS Static Page</h1>
    <body>
    <p>This is a GCS Static Page</p>
    <p><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1f/Understory_state_park.jpg/1920px-Understory_state_park.jpg"/></p>
    <div>Source: <a href="https://en.wikipedia.org/wiki/Stokes_State_Forest"
    >https://en.wikipedia.org/wiki/Stokes_State_Forest</a>
    </div>
    <p>
    Previous pages:
    <ul>
    <ol><a href="index1.html">index1.html - initial version</a></ol>
    <ol><a href="index2.html">index2.html - with service worker</a></ol>
    </ul>
    </p>
    <script src=/main.js></script>
    </body>
    </html>
    15 changes: 15 additions & 0 deletions index1.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,15 @@
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>GCS Static Page</title>
    </head>
    <h1>GCS Static Page</h1>
    <body>
    <p>This is a GCS Static Page</p>
    <p><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1f/Understory_state_park.jpg/1920px-Understory_state_park.jpg"/></p>
    <div>Source: <a href="https://en.wikipedia.org/wiki/Stokes_State_Forest"
    >https://en.wikipedia.org/wiki/Stokes_State_Forest</a>
    </div>
    </body>
    </html>
    16 changes: 16 additions & 0 deletions index2.html
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,16 @@
    <!DOCTYPE html>
    <html>
    <head>
    <meta charset="utf-8">
    <title>GCS Static Page</title>
    </head>
    <h1>GCS Static Page</h1>
    <body>
    <p>This is a GCS Static Page</p>
    <p><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/1f/Understory_state_park.jpg/1920px-Understory_state_park.jpg"/></p>
    <div>Source: <a href="https://en.wikipedia.org/wiki/Stokes_State_Forest"
    >https://en.wikipedia.org/wiki/Stokes_State_Forest</a>
    </div>
    <script src=/main2.js></script>
    </body>
    </html>
    38 changes: 38 additions & 0 deletions main.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,38 @@
    /*
    * Copyright 2018 Google Inc. All rights reserved.
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    * https://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License
    *
    */

    'use strict';

    // Log performance timings
    let pageNav = performance.getEntriesByType("navigation")[0];
    let dnsTime = pageNav.domainLookupEnd - pageNav.domainLookupStart;
    let connectTime = pageNav.connectEnd - pageNav.connectStart;
    let tlsTime = 0;
    if (pageNav.secureConnectionStart > 0) {
    tlsTime = pageNav.connectEnd - pageNav.secureConnectionStart;
    }
    let ttfb = pageNav.responseStart - pageNav.requestStart;
    let dt = pageNav.responseEnd - pageNav.responseStart;
    let transferSize = pageNav.transferSize;
    let nextHopProtocol = pageNav.nextHopProtocol;
    console.log(`DNS lookup: ${ dnsTime }`);
    console.log(`Connect Time: ${ connectTime }`);
    console.log(`TLS negotiation: ${ tlsTime }`);
    console.log(`Time to first byte: ${ ttfb }`);
    console.log(`Download time: ${ dt }`);
    console.log(`Response size: ${ transferSize }`);
    console.log(`nextHopProtocol: ${ nextHopProtocol }`);
    31 changes: 31 additions & 0 deletions main2.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,31 @@
    /*
    * Copyright 2018 Google Inc. All rights reserved.
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    * https://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License
    *
    */

    'use strict';

    console.log('Starting');
    if ('serviceWorker' in navigator) {
    window.addEventListener('load', function() {
    navigator.serviceWorker.register('/sw.js').then(function(registration) {
    console.log('ServiceWorker registration successful with scope: ', registration.scope);
    }, function(err) {
    console.log('ServiceWorker registration failed: ', err);
    });
    });
    } else {
    console.log('serviceWorker is not in navigator');
    }
    45 changes: 45 additions & 0 deletions sw.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,45 @@
    /*
    * Copyright 2018 Google Inc. All rights reserved.
    *
    * Licensed under the Apache License, Version 2.0 (the "License");
    * you may not use this file except in compliance with the License.
    * You may obtain a copy of the License at
    *
    * https://www.apache.org/licenses/LICENSE-2.0
    *
    * Unless required by applicable law or agreed to in writing, software
    * distributed under the License is distributed on an "AS IS" BASIS,
    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    * See the License for the specific language governing permissions and
    * limitations under the License
    *
    */
    console.log('Starting service worker');
    const version = "0.001";
    const cacheName = `gcs-static-${version}`;
    self.addEventListener('install', e => {
    e.waitUntil(
    caches.open(cacheName).then(cache => {
    return cache.addAll([
    `/`,
    `/index2.html`,
    `/main2.js`
    ])
    .then(() => self.skipWaiting());
    })
    );
    });

    self.addEventListener('activate', event => {
    event.waitUntil(self.clients.claim());
    });

    self.addEventListener('fetch', event => {
    event.respondWith(
    caches.open(cacheName)
    .then(cache => cache.match(event.request, {ignoreSearch: true}))
    .then(response => {
    return response || fetch(event.request);
    })
    );
    });