Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Serving the ServiceWorker #103

Closed
dandrei opened this issue Dec 20, 2018 · 14 comments
Closed

Serving the ServiceWorker #103

dandrei opened this issue Dec 20, 2018 · 14 comments

Comments

@dandrei
Copy link

dandrei commented Dec 20, 2018

Hey everyone,

I'm trying to add offline support to my Next.js app. I did the following so far:

  1. Installed next-offline
  2. Wrapped the config in next.config.js (module.exports = withOffline(__config__);
  3. Added the following to the config in next.config.js:
generateInDevMode: true,
workboxOpts: [as in README.md]
  1. Ran yarn dev.

Here I ran into a bit of trouble. I get:

SW registration failed: TypeError: Failed to register a ServiceWorker: A bad HTTP response code (404) was received when fetching the script.

Looks like the script is trying to fetch the SW from /service-worker.js, but Next.js doesn't serve it on that route and just returns a 404.

So that's the first question: how to get the SW to be served? Is it supposed to be automatically generated by next-offline, or should I manually create this file myself?

The second question has to do with the protocol. Next.js runs out of the box on HTTP (not HTTPS). But SWs are designed to run on HTTPS. How is this usually addressed?

Thanks!

@jonesjaycob
Copy link

I have the same problem. Any help would be great!

@hanford
Copy link
Owner

hanford commented Dec 20, 2018

@PatrickSachs can you maybe clarify how you're using the generateInDevMode flag?

@SachsKaylee
Copy link
Contributor

SachsKaylee commented Dec 20, 2018

@dandrei Which setting are you using for importWorkboxFrom? If it is local see #97 - I haven't tried to proposed option yet but my workarounds works aswell.

For easy HTTPS support I'd recommend you to take a look at my redoubt library which handles all the HTTPS stuff in the background for you: https://github.com/PatrickSachs/redoubt
This exposes an express server to you which you can use like in this example:
https://github.com/zeit/next.js/blob/canary/examples/custom-server-express/server.js

@hanford By default a stub file is used as device worker if dev: true is set. The generateInDevMode flag compiles the service worker as normal. I don't recommend setting this flag unless you are aware of how(and when!) service workers a reloaded since this can make things a bit annoying to debug.

@dandrei
Copy link
Author

dandrei commented Dec 20, 2018

I didn't have it set before. I set the two variables to the values suggested in #97, but now I have another issue, the client compilation gets stuck at 95%:

  • client █████████████████████████ emitting (95%) GenerateSW

Here's the relevant part of the config (not sure about the items in runtimeCaching):

generateInDevMode: true,
workboxOpts: {
    importsDirectory: 'static', // puts workbox in .next/static
    importWorkboxFrom: 'local',
    precacheManifest: false,
    runtimeCaching: [
        {
            urlPattern: /_next\/static$/,
            handler: 'cacheFirst',
            options: {
                cacheName: 'static-resources',
                cacheableResponse: {statuses: [0, 200]}
            }
        },
        {
            urlPattern: /webapi/,
            handler: 'networkFirst',
            options: {
                cacheableResponse: {
                    statuses: [0, 200],
                    headers: {'x-test': 'true'}
                }
            }
        },
        {
            urlPattern: /(localhost|YOUR\.DOMAIN)/i,
            handler: 'staleWhileRevalidate',
            options: {
                cacheableResponse: {statuses: [0, 200]},
                plugins: []
            }
        }
    ]
}

@SachsKaylee
Copy link
Contributor

Validation errors are hidden in development mode. If you run your build script you'll see the error:

  name: 'ValidationError',
  details:
   [ { message: '"precacheManifest" is not a supported parameter.',
       path: [Array],
       type: 'object.allowUnknown',
       context: [Object] } ]
// ....

@dandrei
Copy link
Author

dandrei commented Dec 20, 2018

You're right. I copied the config from the web. That particular parameter must have gotten deprecated and removed from Workbox at some point.

Now I'm running with a minimum configuration:

generateInDevMode: true,
workboxOpts: {
    importsDirectory: 'static', // puts workbox in .next/static
    importWorkboxFrom: 'local',
}

I get

UnhandledPromiseRejectionWarning: TypeError [ERR_INVALID_ARG_TYPE]: The "path" argument must be one of type string, Buffer, or URL. Received type undefined

The stacktrace points to this line

// Pick first and only as we've clean old ones.
const file = await readFile(files[0], 'utf-8');

in function getOriginalManifest(manifestFilePath) (next-manifest.js).

@hanford
Copy link
Owner

hanford commented Dec 20, 2018

@dandrei ahh, we should be using idx or something there or not invoke that function when we don't have files, I can probably get a fix for that specific problem in.. just on holiday right now 🎄

@hanford
Copy link
Owner

hanford commented Jan 3, 2019

@dandrei could you share a repository where this issue is easy to reproduce? It would help me debug this issue much faster, thanks!

@jackgray
Copy link

jackgray commented Apr 4, 2019

just wondering if this was fixed or if there is a version of next-offline that works? I keep getting a failed to load service-worker.js error when communicating to server and none seems to be generated.

@hanford
Copy link
Owner

hanford commented Apr 4, 2019

@jackgray I can't fix bugs if they can't be replicated. I need consistently reproducible repository to take a deeper look at this issue. I'd also be happy to merge/review a PR if you think you've fixed it.

I've never had this issue and I've used next-offline numerous times. There are many examples of next-offline working fine, you can see the examples folder or check out my personal website or a different side project trends

@hanford
Copy link
Owner

hanford commented Apr 29, 2019

Going to go ahead and close this issue. I can't really look in more without some sample code or a reproduction case.

I'd make sure you have a server or now.json set up to serve the server-worker GET request. Feel free to comment again again or open another issue if you have any other issues

@hanford hanford closed this as completed Apr 29, 2019
@hanford
Copy link
Owner

hanford commented Apr 29, 2019

This could be related to #127

@ScreamZ
Copy link

ScreamZ commented Jul 29, 2019

I'll answer because I think there is some misunderstanding from users, I'll make some pull request to the documentation soon to clarify some things that might not be easy to understand when you're new to service workers.

In order to use any service worker in development mode with nextJS you must rely on custom development server.

Just create a new file at root project folder called server.js and paste the following:

const { createServer } = require("http");
const { join } = require("path");
const { parse } = require("url");
const next = require("next");

const app = next({ dev: process.env.NODE_ENV !== "production" });
const handle = app.getRequestHandler();

app.prepare().then(() => {
  createServer((req, res) => {
    const parsedUrl = parse(req.url, true);
    const { pathname } = parsedUrl;

    // handle GET request to /service-worker.js
    if (pathname === "/service-worker.js") {
      const filePath = join(__dirname, ".next", pathname);

      app.serveStatic(req, res, filePath);
    } else {
      handle(req, res, parsedUrl);
    }
  }).listen(3000, () => {
    console.log(`> Ready on http://localhost:${3000}`);
  });
});

See the statement ?

  if (pathname === "/service-worker.js") {
      const filePath = join(__dirname, ".next", pathname);

      app.serveStatic(req, res, filePath);

That's because if you look into .next folder the service worker is in the root of this directory, as we know in nextJS, to serve static file like this you MUST use the static folder, otherwise the system will look for a page in pages folder.
The thing is that using the static folder will result with a scope issue because the service worker will only be activated for /static/* URLs.

The above server script solve the issue by allowing a root URL to serve a specific file which is the one generated using generateInDevMode: true option.

@hanford
Copy link
Owner

hanford commented Jul 29, 2019

PR's are welcome @ScreamZ !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants