dwyl / learn-flutter

🦋 Learn how to use Flutter to Build Cross-platform Native Mobile Apps
https://flutter.dev
GNU General Public License v2.0
87 stars 8 forks source link

flutter web boosting guide: patch on flutter_service_worker fails #86

Closed layerzzzio closed 1 year ago

layerzzzio commented 1 year ago

Hi,

First of all, thank you so much for the research on boosting the loading time in flutter web apps. I tried to apply the patch described here: https://github.com/dwyl/learn-flutter/tree/main/guides/flutter-web-speed-boost.

The patch specific to flutter_service_worker.js does not seem to work for me as shown in the GitHub actions flow here: image

I have double-checked my version of flutter_service_worker.js compared to yours; it is identical. The hunk at 32 seems to be the removal of the CORE variable as suggested in the guide. Have you experienced the same error lately?

Thank you Best

LuchoTurtle commented 1 year ago

Hey @layerzzzio , thanks for opening the issue!

Have you tried using the --ignore-whitespace flag?

- name: Run post-build script to download files concurrently
    run: | 
        chmod +x ./build_tools/patch_web.sh
        sh ./build_tools/patch_web.sh --ignore-whitespace

The error you're getting is that one of the blocks of lines is having trouble being patched. It might be the indentation, hence why using this flag might help. If that doesn't hep, I recommend the following:

If everything else fails, I recommend taking a look at https://github.com/dwyl/app/pull/330/files. It has all the files and changes needed. These patch files should work in your application the same way it does in ours! :D

If you can show how your flutter_service_worker.js file is generated and what your .patch file looks like, I can take a look for ye, if ye want to!

layerzzzio commented 1 year ago

Thank you for helping @LuchoTurtle.

I regenerated the patch according to your suggestion (https://github.com/dwyl/app/pull/330/files). I then executed the patch command and no error occurred. Given it was successful, I merged the code to the main branch, and the action got triggered. However, I got the same result as the issue described here above.

Here is my flutter_sercice_worker.js after modifications if you don't mind having a look at it.

Thank you again

'use strict';
const MANIFEST = 'flutter-app-manifest';
const TEMP = 'flutter-temp-cache';
const CACHE_NAME = 'flutter-app-cache';
const RESOURCES = {
  "favicon-16x16.png": "2c345a67017095dddc2d2fe03c7298a2",
"version.json": "f71421e9e87ea25eed3ced1343d744cb",
"index.html": "7d776ff804bb72fd212fa9f258ed06bc",
"/": "7d776ff804bb72fd212fa9f258ed06bc",
"main.dart.js": "38e66988b0845b311816cbc8e3927ab9",
"flutter.js": "a85fcf6324d3c4d3ae3be1ae4931e9c5",
"favicon.png": "2c345a67017095dddc2d2fe03c7298a2",
"main-icon.png": "81308712f0709e138202e575607b5561",
"icons/Icon-192.png": "81308712f0709e138202e575607b5561",
"manifest.json": "b52e966a1cca28127af75bce85c08a1a",
"assets/AssetManifest.json": "52ed57dde7e14ba90f9573d8d80b14c0",
"assets/NOTICES": "35814a12fe722223b2cc311e68f17af5",
"assets/FontManifest.json": "3ddd9b2ab1c2ae162d46e3cc7b78ba88",
"assets/packages/font_awesome_flutter/lib/fonts/fa-solid-900.ttf": "9cda082bd7cc5642096b56fa8db15b45",
"assets/packages/font_awesome_flutter/lib/fonts/fa-regular-400.ttf": "0a94bab8e306520dc6ae14c2573972ad",
"assets/packages/font_awesome_flutter/lib/fonts/fa-brands-400.ttf": "b00363533ebe0bfdb95f3694d7647f6d",
"assets/packages/fluttertoast/assets/toastify.js": "e7006a0a033d834ef9414d48db3be6fc",
"assets/packages/fluttertoast/assets/toastify.css": "a85675050054f179444bc5ad70ffc635",
"assets/packages/flex_color_picker/assets/opacity.png": "49c4f3bcb1b25364bb4c255edcaaf5b2",
"assets/fonts/MaterialIcons-Regular.otf": "e7069dfd19b331be16bed984668fe080",
"assets/assets/img/logo.png": "3c02e5b3c8266660e9711c4a25684a92",
"favicon-32x32.png": "5b6d962a3de82a7553aca772a06ac7a5",
"canvaskit/canvaskit.js": "97937cb4c2c2073c968525a3e08c86a3",
"canvaskit/profiling/canvaskit.js": "c21852696bc1cc82e8894d851c01921a",
"canvaskit/profiling/canvaskit.wasm": "371bc4e204443b0d5e774d64a046eb99",
"canvaskit/canvaskit.wasm": "3de12d898ec208a5f31362cc00f09b9e"
};

// The application shell files that are downloaded before a service worker can
// start.

// During activate, the cache is populated with the temp files downloaded in
// install. If this service worker is upgrading from one with a saved
// MANIFEST, then use this to retain unchanged resource files.
self.addEventListener("activate", function(event) {
  return event.waitUntil(async function() {
    try {
      var contentCache = await caches.open(CACHE_NAME);
      var tempCache = await caches.open(TEMP);
      var manifestCache = await caches.open(MANIFEST);
      var manifest = await manifestCache.match('manifest');
      // When there is no prior manifest, clear the entire cache.
      if (!manifest) {
        await caches.delete(CACHE_NAME);
        contentCache = await caches.open(CACHE_NAME);
        for (var request of await tempCache.keys()) {
          var response = await tempCache.match(request);
          await contentCache.put(request, response);
        }
        await caches.delete(TEMP);
        // Save the manifest to make future upgrades efficient.
        await manifestCache.put('manifest', new Response(JSON.stringify(RESOURCES)));
        return;
      }
      var oldManifest = await manifest.json();
      var origin = self.location.origin;
      for (var request of await contentCache.keys()) {
        var key = request.url.substring(origin.length + 1);
        if (key == "") {
          key = "/";
        }
        // If a resource from the old manifest is not in the new cache, or if
        // the MD5 sum has changed, delete it. Otherwise the resource is left
        // in the cache and can be reused by the new service worker.
        if (!RESOURCES[key] || RESOURCES[key] != oldManifest[key]) {
          await contentCache.delete(request);
        }
      }
      // Populate the cache with the app shell TEMP files, potentially overwriting
      // cache files preserved above.
      for (var request of await tempCache.keys()) {
        var response = await tempCache.match(request);
        await contentCache.put(request, response);
      }
      await caches.delete(TEMP);
      // Save the manifest to make future upgrades efficient.
      await manifestCache.put('manifest', new Response(JSON.stringify(RESOURCES)));
      return;
    } catch (err) {
      // On an unhandled exception the state of the cache cannot be guaranteed.
      console.error('Failed to upgrade service worker: ' + err);
      await caches.delete(CACHE_NAME);
      await caches.delete(TEMP);
      await caches.delete(MANIFEST);
    }
  }());
});

// The fetch handler redirects requests for RESOURCE files to the service
// worker cache.
self.addEventListener("fetch", (event) => {
  if (event.request.method !== 'GET') {
    return;
  }
  var origin = self.location.origin;
  var key = event.request.url.substring(origin.length + 1);
  // Redirect URLs to the index.html
  if (key.indexOf('?v=') != -1) {
    key = key.split('?v=')[0];
  }
  if (event.request.url == origin || event.request.url.startsWith(origin + '/#') || key == '') {
    key = '/';
  }
  // If the URL is not the RESOURCE list then return to signal that the
  // browser should take over.
  if (!RESOURCES[key]) {
    return;
  }
  // If the URL is the index.html, perform an online-first request.
  if (key == '/') {
    return onlineFirst(event);
  }
  event.respondWith(caches.open(CACHE_NAME)
    .then((cache) =>  {
      return cache.match(event.request).then((response) => {
        // Either respond with the cached resource, or perform a fetch and
        // lazily populate the cache only if the resource was successfully fetched.

        if (response) {
          return response;
        }

        if (IN_PROCESSING_REQUESTS[key]) {
          return IN_PROCESSING_REQUESTS[key].clone();
        }

        return fetch(event.request).then((response) => {
           if (response && Boolean(response.ok)) {
            cache.put(event.request, response.clone())
                 .then(() => delete IN_PROCESSING_REQUESTS[key]);
           }

          IN_PROCESSING_REQUESTS[key] = response.clone();
           return response;
        });
      })
    })
  );
});

self.addEventListener('message', (event) => {
  // SkipWaiting can be used to immediately activate a waiting service worker.
  // This will also require a page refresh triggered by the main worker.
  if (event.data === 'skipWaiting') {
    self.skipWaiting();
    return;
  }
  if (event.data === 'downloadOffline') {
    downloadOffline();
    return;
  }
});

// Download offline will check the RESOURCES for all files not in the cache
// and populate them.
async function downloadOffline() {
  var resources = [];
  var contentCache = await caches.open(CACHE_NAME);
  var currentContent = {};
  for (var request of await contentCache.keys()) {
    var key = request.url.substring(origin.length + 1);
    if (key == "") {
      key = "/";
    }
    currentContent[key] = true;
  }
  for (var resourceKey of Object.keys(RESOURCES)) {
    if (!currentContent[resourceKey]) {
      resources.push(resourceKey);
    }
  }
  return contentCache.addAll(resources);
}

// Attempt to download the resource online before falling back to
// the offline cache.
function onlineFirst(event) {
  return event.respondWith(
    fetch(event.request).then((response) => {
      return caches.open(CACHE_NAME).then((cache) => {
        cache.put(event.request, response.clone());
        return response;
      });
    }).catch((error) => {
      return caches.open(CACHE_NAME).then((cache) => {
        return cache.match(event.request).then((response) => {
          if (response != null) {
            return response;
          }
          throw error;
        });
      });
    })
  );
}
LuchoTurtle commented 1 year ago

Hey @layerzzzio !

Sorry for responding now. I have some suspicions that I know where the issue is, I just gotta check it and try to find a solution. I'll get back to you :)

LuchoTurtle commented 1 year ago

I think I found the problem. It was due to a commit made to the patch files that was not properly tested and was causing errors. Please check https://github.com/dwyl/learn-flutter/pull/89.

Your patch files should now look like this:

Assuming you have the patch files like so and you're running the patch_web.sh script with the --ignore-whitespace, you should be sorted :)

LuchoTurtle commented 1 year ago

@layerzzzio if this works for you, give us a heads-up so we can close the issue 🙂

layerzzzio commented 1 year ago

@LuchoTurtle thank you for the reply. Let me try that now and get back to you asap.

layerzzzio commented 1 year ago

tldr: I tried the patch and it works now.

Details:

instead of having the below lines from the original file

const RESOURCES = {
  "favicon-16x16.png": "1008ad5aa5a962c6eb4bcf4890f30c32",
"version.json": "f71421e9e87ea25eed3ced1343d744cb",
"index.html": "0ed800609e6693da7c14c24fb191602e",
"/": "0ed800609e6693da7c14c24fb191602e",
"main.dart.js": "10e433a081744a1ed484aa1e4659e4d2",
"favicon.png": "1008ad5aa5a962c6eb4bcf4890f30c32",
"main-icon.png": "5cb874bdca3c2e1a5a43f3f3145a181e",
"icons/Icon-192.png": "796f69f8cf5dc14374bed1e5d4093ba7",
"manifest.json": "b52e966a1cca28127af75bce85c08a1a",
"assets/AssetManifest.json": "a590953f8b10431c8c980d07d1473060",
"assets/NOTICES": "8c16603774227a26d9e85be3531f9afa",
"assets/FontManifest.json": "3ddd9b2ab1c2ae162d46e3cc7b78ba88",
"assets/packages/font_awesome_flutter/lib/fonts/fa-solid-900.ttf": "9cda082bd7cc5642096b56fa8db15b45",
"assets/packages/font_awesome_flutter/lib/fonts/fa-regular-400.ttf": "0a94bab8e306520dc6ae14c2573972ad",
"assets/packages/font_awesome_flutter/lib/fonts/fa-brands-400.ttf": "b00363533ebe0bfdb95f3694d7647f6d",
"assets/packages/fluttertoast/assets/toastify.js": "e7006a0a033d834ef9414d48db3be6fc",
"assets/packages/fluttertoast/assets/toastify.css": "a85675050054f179444bc5ad70ffc635",
"assets/packages/flex_color_picker/assets/opacity.png": "49c4f3bcb1b25364bb4c255edcaaf5b2",
"assets/fonts/MaterialIcons-Regular.otf": "e7069dfd19b331be16bed984668fe080",
"assets/assets/img/logo.png": "796f69f8cf5dc14374bed1e5d4093ba7",
"assets/assets/img/logo.svg": "d01d892294ff2826277daae0930737cc",
"favicon-32x32.png": "e3d70457bf40eaa4b9e0f4471160cb87"
};

I had the below variable in the copied file (you can see the whitespace at the beginning of each line):

const RESOURCES = {
  "favicon-16x16.png": "1008ad5aa5a962c6eb4bcf4890f30c32",
  "version.json": "f71421e9e87ea25eed3ced1343d744cb",
  "index.html": "0ed800609e6693da7c14c24fb191602e",
  "/": "0ed800609e6693da7c14c24fb191602e",
  "main.dart.js": "10e433a081744a1ed484aa1e4659e4d2",
  "favicon.png": "1008ad5aa5a962c6eb4bcf4890f30c32",
  "main-icon.png": "5cb874bdca3c2e1a5a43f3f3145a181e",
  "icons/Icon-192.png": "796f69f8cf5dc14374bed1e5d4093ba7",
  "manifest.json": "b52e966a1cca28127af75bce85c08a1a",
  "assets/AssetManifest.json": "a590953f8b10431c8c980d07d1473060",
  "assets/NOTICES": "8c16603774227a26d9e85be3531f9afa",
  "assets/FontManifest.json": "3ddd9b2ab1c2ae162d46e3cc7b78ba88",
  "assets/packages/font_awesome_flutter/lib/fonts/fa-solid-900.ttf": "9cda082bd7cc5642096b56fa8db15b45",
  "assets/packages/font_awesome_flutter/lib/fonts/fa-regular-400.ttf": "0a94bab8e306520dc6ae14c2573972ad",
  "assets/packages/font_awesome_flutter/lib/fonts/fa-brands-400.ttf": "b00363533ebe0bfdb95f3694d7647f6d",
  "assets/packages/fluttertoast/assets/toastify.js": "e7006a0a033d834ef9414d48db3be6fc",
  "assets/packages/fluttertoast/assets/toastify.css": "a85675050054f179444bc5ad70ffc635",
  "assets/packages/flex_color_picker/assets/opacity.png": "49c4f3bcb1b25364bb4c255edcaaf5b2",
  "assets/fonts/MaterialIcons-Regular.otf": "e7069dfd19b331be16bed984668fe080",
  "assets/assets/img/logo.png": "796f69f8cf5dc14374bed1e5d4093ba7",
  "assets/assets/img/logo.svg": "d01d892294ff2826277daae0930737cc",
  "favicon-32x32.png": "e3d70457bf40eaa4b9e0f4471160cb87"
};
LuchoTurtle commented 1 year ago

Awesome @layerzzzio! Super happy to hear you got it working! And thanks for detailing your process, it will certainly be helpful for other folks who come across similar issues in GitHub Actions.

Closing this off as completed :D

nelsonic commented 1 year ago

@layerzzzio thanks very much for confirming you got it all working with @LuchoTurtle's help. 🎉 Very good to get additional verification on this. ✅