Coder Social home page Coder Social logo

hanford / next-offline Goto Github PK

View Code? Open in Web Editor NEW
1.6K 16.0 113.0 2.41 MB

make your Next.js application work offline using service workers via Google's workbox

Home Page: https://github.com/hanford/next-offline

JavaScript 100.00%
nextjs service-worker offline cache website workbox pwa

next-offline's Introduction

next-offline

Use Workbox with Next.js and
easily enable offline functionality in your application!


Installation

$ npm install --save next-offline
$ yarn add next-offline

Usage

There are two important things to set up, first we need next-offline to wrap your next config.

If you haven't yet, create a next.config.js in your project.

// next.config.js
const withOffline = require('next-offline')

const nextConfig = {
  ...
}

module.exports = withOffline(nextConfig)

Next we need to make sure our application is properly serving the service worker, this setup depends on how you're hosting your application. There is documentation below. If you're not using Now 2.0, the Now 1.0 example should work in most circumstances.

Documentation

Serving service worker

Because service workers are so powerful, the API has some restrictions built in. For example, service workers must be served on the domain they're being used on - you can't use a CDN.

Now 1.0

You'll want to use the next.js custom server API. The easiest way to do that is creating a server.js that looks like this:

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}`)
    })
  })

You can read more about custom servers in the Next.js docs

If you're not hosting with Now, I'd probably follow the Now 1.0 approach because the custom server API can enable a lot of functionality, it just simply doesn't work well with Now 2.0 πŸ™‡β€β™‚οΈ

Now 2.0

Because Now 2.0 works so different than the previous version, so does serving the service worker. There are a few different ways to do this, but I'd recommend checking out this now2 example app. The changes to be aware of are in the now.json and next.config.js.

Registering service worker

Compile-time registration

By default next-offline will register a service worker with the script below, this is automatically added to your client side bundle once withOffline is invoked.

if ('serviceWorker' in navigator) {
  window.addEventListener('load', function () {
    navigator.serviceWorker.register('/service-worker.js', { scope: '/' }).then(function (registration) {
      console.log('SW registered: ', registration)
    }).catch(function (registrationError) {
      console.log('SW registration failed: ', registrationError)
    })
  })
}

Runtime registration

Alternative to compile-time, you can take control of registering/unregistering in your application code by using the next-offline/runtime module.

import { register, unregister } from 'next-offline/runtime'

class App extends React.Component {
  componentDidMount () {
    register()
  }
  componentWillUnmount () {
    unregister()
  }
  ..
}

You can choose to pass the service worker path and scope if needed.

import { register, unregister } from 'next-offline/runtime'

class App extends React.Component {
  componentDidMount () {
    /** 
      * Default service worker path is '/service-worker.js' 
      * Refer https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register for default scope rules
      *
    */
    register('/sub_folder/service-worker.js', {scope: '/sub_folder'}) 
  }
  componentWillUnmount () {
    unregister()
  }
  ..
}

If you're handling registration on your own, pass dontAutoRegisterSw to next-offline.

// next.config.js
const withOffline = require('next-offline')

module.exports = withOffline({ dontAutoRegisterSw: true })

Customizing service worker

Using workbox

If you're new to workbox, I'd recommend reading this quick guide -- anything inside of workboxOpts will be passed to workbox-webpack-plugin.

Define a workboxOpts object in your next.config.js and it will gets passed to workbox-webpack-plugin. Workbox is what next-offline uses under the hood to generate the service worker, you can learn more about it here.

// next.config.js
const withOffline = require('next-offline')

const nextConfig = {
  workboxOpts: {
    ...
  }
}

module.exports = withOffline(nextConfig)

next-offline options

On top of the workbox options, next-offline has some options built in flags to give you finer grain control over how your service worker gets generated.

Name Type Description Default
generateSw Boolean If false, next-offline will not generate a service worker and will instead try to modify the file found in workboxOpts.swSrc using WorkBox's [Inject Plugin](https://developers.google.com/web/tools/workbox/modules/workbox-webpack-plugin#injectmanifest_plugin) true
dontAutoRegisterSw Boolean If true, next-offline won't automatically push the registration script into the application code. This is required if you're using runtime registration or are handling registration on your own. false
devSwSrc String Path to be registered by next-offline during development. By default next-offline will register a noop during development false
generateInDevMode Boolean If true, the service worker will also be generated in development mode. Otherwise the service worker defined in devSwSrc will be used. false
registerSwPrefix String If your service worker isn't at the root level of your application, this can help you prefix the path. This is useful if you'd like your service worker on foobar.com/my/long/path/service-worker.js. This affects the [scope](https://developers.google.com/web/ilt/pwa/introduction-to-service-worker#registration_and_scope) of your service worker. false
scope String This is passed to the automatically registered service worker allowing increase or decrease what the service worker has control of. "/"

Cache strategies

By default next-offline has the following blanket runtime caching strategy. If you customize next-offline with workboxOpts, the default behaviour will not be passed into workbox-webpack-plugin. This article is great at breaking down various different cache recipes.

{
  runtimeCaching: [
    {
      urlPattern: /^https?.*/,
      handler: 'NetworkFirst',
      options: {
        cacheName: 'offlineCache',
        expiration: {
          maxEntries: 200
        }
      }
    }
  ]
}
// next.config.js
const withOffline = require('next-offline')

module.exports = withOffline({
  workboxOpts: {
    runtimeCaching: [
      {
        urlPattern: /.png$/,
        handler: 'CacheFirst'
      },
      {
        urlPattern: /api/,
        handler: 'NetworkFirst',
        options: {
          cacheableResponse: {
            statuses: [0, 200],
            headers: {
              'x-test': 'true'
            }
          }
        }
      }
    ]
  }
})

Service worker path

If your application doesn't live on the root of your domain, you can use registerSwPrefix. This is helpful if your application is on domain.com/my/custom/path because by default next-offline assumes your application is on domain.com and will try to register domain.com/service-worker.js. We can't support using assetPrefix because service workers must be served on the root domain. For a technical breakdown on that limitation, see the following link: Is it possible to serve service workers from CDN/remote origin?

By default next-offline will precache all the Next.js webpack emitted files and the user-defined static ones (inside /static) - essentially everything that is exported as well.

If you'd like to include some more or change the origin of your static files use the given workbox options:

workboxOpts: {
  modifyURLPrefix: {
    'app': assetPrefix,
  },
  runtimeCaching: {...}
}

Development mode

By default next-offline will add a no-op service worker in development. If you want to provide your own pass its filepath to devSwSrc option. This is particularly useful if you want to test web push notifications in development, for example.

// next.config.js
const withOffline = require('next-offline')

module.exports = withOffline({
  devSwSrc: '/path/to/my/dev/service-worker.js'
})

You can disable this behavior by setting the generateInDevMode option to true.

next export

In [email protected] we've rewritten the export functionality to work in more cases, more reliably, with less code thanks to some of the additions in Next 7.0.0!

You can read more about exporting at Next.js docs but next offline should Just Workℒ️.

next offline 5.0

If you're upgrading to the latest version of next-offline I recommend glancing at what's been added/changed inside of Workbox in 5.x releases along with the 4.0 release which included the breaking changes. Next Offline's API hasn't changed, but a core dependency has!


Questions? Feedback? Please let me know

Contributing

next-offline is a lerna monorepo which uses yarn workspaces. After cloning the repo, run the following

$ yarn bootstrap

This will ensure your development version of next-offline is symlinked in the examples & tests which should allow you to quickly make changes!

License (MIT)

WWWWWW||WWWWWW
 W W W||W W W
      ||
    ( OO )__________
     /  |           \
    /o o|    MIT     \
    \___/||_||__||_|| *
         || ||  || ||
        _||_|| _||_||
       (__|__|(__|__|

Copyright Β© 2017-present Jack Hanford, [email protected]

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the 'Software'), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

next-offline's People

Contributors

41y08h avatar 4cm4k1 avatar adam187 avatar adarshkonchady avatar airamrguez avatar alexanbj avatar arrel avatar de-perotti avatar dependabot[bot] avatar dudeman avatar edds avatar fberthelot avatar hanford avatar jipsterk avatar joaovieira avatar karlhorky avatar kingjan1999 avatar larbisahli avatar luandro avatar lucasavila00 avatar marcioj avatar orangexc avatar raajnadar avatar rauleite avatar scoobster17 avatar shawninder avatar simonflk avatar thejoebiz avatar xfumihiro avatar xmokax avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

next-offline's Issues

[issue] Improper url generated in precache manifest

Hi,

I am using Next-Offline plugin with default configuration to generate a SW in my next app. I am using it with next-compose-plugins. But some of the urls in the precache manifest is coming up in a wrong format.

[
  {
    "url": "/_next/static\\KNDFTKSOllSWsMpFn4rTQ\\pages\\articles\\article-tw-styles.js"
  },
  {
    "url": "/_next/static/chunks/commons.86fc779777898d71ec9d.js"
  },
  {
    "url": "/_next/static/runtime/main-41ce168f4e04b48f4931.js"
  },
  {
    "url": "/_next/static\\KNDFTKSOllSWsMpFn4rTQ\\pages\\_app.js"
  },
  {
    "url": "/_next/static\\KNDFTKSOllSWsMpFn4rTQ\\pages\\_error.js"
  },
  {
    "url": "/_next/static\\KNDFTKSOllSWsMpFn4rTQ\\pages\\articles\\article-detail.js"
  },
  {
    "url": "/_next/static\\KNDFTKSOllSWsMpFn4rTQ\\pages\\articles\\article-list.js"
  },
  {
    "url": "/_next/static/runtime/webpack-89179faa512dd01fbb62.js"
  },
  {
    "url": "/_next/static\\KNDFTKSOllSWsMpFn4rTQ\\pages\\homePage.js"
  },
  {
    "url": "/_next/static/css/styles.1922a2a1.chunk.css"
  },
  {
    "url": "/_next/static/chunks/styles.afe210c5d5c033637b26.js"
  },
  {
    "url": "/_next/static/images/Braun-Garantieverlaengerung-Landing-2a7a96eccf353053883657a0102e1411.jpg"
  },
  {
    "url": "/_next/static/images/loader-9e0373c2b4410c49439dfd822c5fd16e.gif"
  }
];

As you can see, the files inside the buildId folders are the only ones that are affected.
I feel like this is something related to the path module.

Any idea why its happening?

My config:

Platform: Windows 10
Next: 7.0.2
Next-Offline: 3.1.0

service-worker.js http 404

if ('serviceWorker' in navigator) {
window.addEventListener('load', function () {
navigator.serviceWorker.register('/service-worker.js').then(function (registration) {
console.log('SW registered: ', registration)
}).catch(function (registrationError) {
console.log('SW registration failed: ', registrationError)
})
})
}

This vs. workbox-webpack-plugin (question)

This is a question, not an issue. I am unclear as to why I would use this lib instead of workbox-webpack-plugin which this seems to also use. Is it an abstraction layer over it .

express custom server + next-routes example? getting unsupported mime type

i'm using next routes and express. next-routes creates a custom handler that up until installed next-offline i just used as an express middleware. When i attempt to do the following:

  server.use((request, response) => {
    const parsedUrl = parse(request.url, true);
    const { pathname } = parsedUrl;
    if (pathname === '/service-worker.js') {
      const filePath = join(__dirname, '.next', pathname);

      return app.serveStatic(request, response, filePath);
    }

    return handler(request, response, pathname);
  });

The error i receive in console is this;

SW registration failed:  DOMException: Failed to register a ServiceWorker: The script has an unsupported MIME type ('text/html').

I am using next 7 canary 11 right now, so this could just be an artifact of that. Thanks!

How I can use InjectManifest?


module.exports = {
  // Other webpack config...
  plugins: [
    // Other plugins...
    new InjectManifest({
      swSrc: './src/sw.js',
    })
  ]
};```

Homepage not in cached after initial visit

hi @hanford

Much like you, I have a similar site like jackhanford.com, but one thing that bothers me is when a new user enters the site, the homepage will not be in cache after just one visit to the site. You will need to do a full reload, or a secondary visit before the homepage will work when offline.

Do you have any suggestions on this issue?

Generating empty importScripts()

My next-offline options:

{
  dontAutoRegisterSw: true,
  generateSw: false,
  workboxOpts: {
    swSrc: "./server/sw.js",
    swDest: "service-worker.js",
  },
}


Original importScripts() generated by workbox-webpack-plugin:

importScripts("precache-manifest.80484f727fa927a948f274db14a17584.js", https://storage.googleapis.com/workbox-cdn/releases/3.2.0/workbox-sw.js");


Final importScripts() generated by next-offline on version 2.11.0:

importScripts("https://storage.googleapis.com/workbox-cdn/releases/3.2.0/workbox-sw.js");


Final importScripts() generated by next-offline on version 2.12.0 and above:

importScripts();


I believe that the problem started with 8399e41

Quota exceeded errors and purgeOnQuotaError

We're currently using next-offline for a very basic offline support with all default settings, but recently we have noticed a lot of "Quota Exceeded" errors in production.

I was taking a look at the workbox documentation and found this:

So, is there a way to set the value of purgeOnQuotaError on the expiration plugin? I couldn't find a way to pass this option or the expiration plugin itself.

How to version the ServiceWorker?

@hanford do you know how to version the generated service worker? Or, rather, how does this plugin change the service worker (SW) file so that a new version is requested by a user's browser?

It looks like the SW changes on each build from next, so does that mean it wouldn't change until a new deployment/build of next?

precache-manifest not copied on next export

next build

Created:
/${distDir}/service-worker.js
/${distDir}/precache-manifest.${hash}.js
next export

Created:
/out/service-worker.js

Missing:
/out/precache-manifest.${hash}.js

Resulting in

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

Support custom dir + distDir

From the discussion in #23:

Handle exporting of Next apps that are on a custom dir (e.g. /app instead of .) and/or with a custom distDir (e.g. /build instead of /.next) as it's currently assuming everything will be built under $projectRoot/.next.

Don't know how to get this information in the exportPathMap step (https://github.com/hanford/next-offline/blob/master/export.js#L23) as I think this is only (?) exposed in the webpack config options. If there's any ideas/guidance I can do the PR.

Styles rendering

Hey, I was wondering if its possible with styled-jsx have styles rendered in the first load like server-side rendering does. Instead of "blink" between app without style and rendering it after the first render.

Set debug to false

Hi There, thank you very much for your plugin!
I installed and it works very well, but I'd like to disable debug, how can I do that?

Error with Next-offline hosted with Firebase Functions

Am seeing following error when i try to use firebase functions with next-offline .

TypeError: (0 , _url.default) is not a function
    at functions.https.onRequest (/user_code/app/app.js:32:38)
    at cloudFunction (/user_code/node_modules/firebase-functions/lib/providers/https.js:57:9)
    at /var/tmp/worker/worker.js:689:7
    at /var/tmp/worker/worker.js:673:9

This is the starter am using

Firebase Nextjs Starter Used
Changes done to the Starter Project :

  1. Modified app.js as below
import * as functions from "firebase-functions"
import next from "next"
import parse from "url"
import join from "path"
const dev = process.env.NODE_ENV !== "production"
const app = next({ dev, conf: { distDir: "next" } })
const handle = app.getRequestHandler()
const nextApp = functions.https.onRequest((request, response) => {
  console.log("File: " + request.originalUrl)
  console.log("dev:", dev)
  // log the page.js file or resource being requested
  const parsedUrl = parse(request.url, true)
  const { pathname } = parsedUrl
  console.log("pathname:", pathname)
  if (pathname === '/service-worker.js') {
    const filePath = join(__dirname, '.next', pathname)
    return app.serveStatic(request, response, filePath)
  } 
  return app.prepare().then(() => handle(request, response))
})
export { nextApp }

2. This is my next.config.js file

const withOffline = require('next-offline')
module.exports = {
  distDir: "../../dist/functions/next",
  withOffline:withOffline()
}

Question :

  1. How do i know if the service worker is working fine. Currently am trying to look for the sw.js file in Application tab in chrome console.

  2. Do I need to connect the component to load the service worker file ?

My package.json file :

{
  "name": "firebase-functions-nextjs",
  "version": "2.0.0",
  "main": "index.js",
  "license": "MIT",
  "dependencies": {
    "@babel/runtime": "^7.1.2",
    "firebase": "^5.5.3",
    "firebase-admin": "^5.12.1",
    "firebase-functions": "^2.0.5",
    "next": "^7.0.2",
    "next-offline": "^3.0.2",
    "react": "^16.4.0",
    "react-dom": "^16.4.0",
    "styled-jsx": "^3.1.0"
  },
  "devDependencies": {
    "@babel/cli": "^7.1.2",
    "@babel/core": "^7.1.2",
    "@babel/preset-env": "^7.1.0",
    "@firebase/app-types": "^0.3.2",
    "cpx": "^1.5.0",
    "firebase-tools": "^3.18.6",
    "prettier": "^1.13.5",
    "rimraf": "^2.6.2"
  },
  "scripts": {
    "fblogin": "yarn firebase login",
    "dev": "next \"src/app\"",
    "preserve": "yarn build-public && yarn build-funcs && yarn build-app && yarn copy-deps && yarn install-deps",
    "serve": "NODE_ENV=production yarn firebase serve --only functions,hosting",
    "deploy-app": "yarn firebase deploy --only hosting,functions:app",
    "deploy-functions": "yarn firebase deploy --only functions:greetings",
    "deploy-all": "yarn firebase deploy",
    "clean": "rimraf \"dist/functions\" && rimraf \"dist/public\"",
    "build-public": "cpx \"src/public/**/*.*\" \"dist/public\" -C",
    "build-funcs": "babel \"src/functions\" --out-dir \"dist/functions\"",
    "build-app": "NODE_ENV=production next build \"src/app\"",
    "copy-deps": "cpx \"*{package.json,yarn.lock}\" \"dist/functions\"",
    "install-deps": "cd \"dist/functions\" && yarn"
  },
  "prettier": {
    "trailingComma": "es5"
  }
}

explore workbox support

Both #2 #1 are experiencing some bugs that appear to be related Next.js + sw-precache, I've decided to explore alternative approaches and it appears there are many.

I'm thinking about supporting both sw-precache and workbox ..

In the workbox branch I almost have workbox running 100%, I'll need to clean up this script but the tl;dr is that we need to run a script after next-build that will go and grab all of the built bundles/chunks/pages and write them to a service worker that we generate .. this is tricky because next is also fingerprinting assets, so we need to adhere to the custom path. (that was the hard part, and it's mostly done minus some cleanup)

At my work, I have an environment where I was able to get this implementation working 100% (opening the network work tab on first visit yeilds all assets next generates getting cached) .. I just need to generalize it a little bit before I cut a new release of next-offline

I have the the sw generation working in this repo .. the only gotcha is running node_modules/next-offline/precache.js after next build.

cc @OrangeXC @gerhardsletten

Configure Next Bundle Analyzer Plugin

Am trying to setup Next Bundle Analyzer Plugin

Still trying to get it working,
can you please help confirm if this is the right way to add it in next.config.js
Thanks

How do we actually add multiple configs .Say, I want to add next-css plugin
module.exports = withCSS()

const withOffline = require('next-offline')
//const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin;
const withBundleAnalyzer = require("@zeit/next-bundle-analyzer");
const { BundleAnalyzerPlugin } = require("webpack-bundle-analyzer");

module.exports = withOffline({
  distDir: "../../dist/functions/next",
  webpack:withBundleAnalyzer({
    analyzeServer: ["server", "both"].includes(process.env.BUNDLE_ANALYZE),
    analyzeBrowser: ["browser", "both"].includes(process.env.BUNDLE_ANALYZE),
    bundleAnalyzerConfig: {
      server: {
        analyzerMode: 'static',
        reportFilename: '../../bundles/server.html'
      },
      browser: {
        analyzerMode: 'static',
        reportFilename: '../bundles/client.html'
      }
    }
  })
})

next export

When I export the next projet via next export, files are not exported in the .out folder.

How can I have files in the .out folder ?

Support for Github Pages (gh-pages) prefix

@hanford I'm trying to use next export -o docs to create a static site at docs folder and then deploy it to gh-pages.

A Project Github Page as you know has the project name as a URL prefix:

https://<user-name>.github.io/<project-name-as-prefix-here>

My case:

https://danilobjr.github.io/timer

Problem: The first line of the auto-generated service-worker.js file has URLs pointed to /_next/...:

self.__precacheManifest = [{"url":"/_next/0b447979...

How can I achieve this?:

self.__precacheManifest = [{"url":"/timer/_next/0b447979...

Thanks in advance.

Spread Syntax Error

I recently installed the plugin and when I try to start my server I get the following error. Any ideas? My first thought was that I was missing something but I don't believe that's the case.

Thanks for taking a look!

next.config.js

const withCSS = require('@zeit/next-css')
const initReactFastclick = require('react-fastclick')
const withOffline = require('next-offline')

initReactFastclick()

module.exports = {
// Other webpack config...
plugins: [
new withCSS(),
new withOffline()
]
};

package.json

{
"main": "index.js",
"repository": "__private",
"scripts": {
"test": "echo "Error: no test specified" && exit 1",
"dev": "node server.js",
"prod": "next build && NODE_ENV=production node server.js",
"build": "next build",
"start": "NODE_ENV=production node server.js"
},
"keywords": [],
"author": "Kevin Miller",
"license": "ISC",
"dependencies": {
"@zeit/next-css": "^0.1.5",
"express": "^4.16.3",
"isomorphic-unfetch": "^2.0.0",
"lscache": "^1.1.0",
"next": "^5.1.0",
"next-offline": "^2.3.1",
"next-router-events": "^2.0.0",
"react": "^16.3.0",
"react-dom": "^16.3.0",
"react-fastclick": "^3.0.2",
"react-markdown": "^3.3.0",
"render-if": "^0.1.1",
"styled-components": "^3.2.5",
"workbox-webpack-plugin": "^3.0.1"
},
"devDependencies": {
"babel-preset-stage-0": "^6.24.1"
}
}

Error

/Users/kevin/projects/test/node_modules/next-offline/index.js:6
...nextConfig,
^^^
SyntaxError: Unexpected token ...
at Object.exports.runInThisContext (vm.js:78:16)
at Module._compile (module.js:543:28)
at Object.Module._extensions..js (module.js:580:10)
at Module.load (module.js:488:32)
at tryModuleLoad (module.js:447:12)
at Function.Module._load (module.js:439:3)
at Module.require (module.js:498:17)
at require (internal/module.js:20:19)
at Object. (/Users/kevin/projects/test/next.config.js:3:21)
at Module._compile (module.js:571:32)
npm ERR! code ELIFECYCLE
npm ERR! errno 1
npm ERR! [email protected] dev: node server.js
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the [email protected] dev script.
npm ERR! This is probably not a problem with npm. There is likely additional logging output above.

npm ERR! A complete log of this run can be found in:
npm ERR! /Users/kevin/.npm/_logs/2018-04-02T22_18_40_959Z-debug.log

Use workbox precache manifest output

While digging in I found out that workbox-webpack-plugin limits all of the "transform" options to the globPattern files only. I.e. don't run modifyUrlPrefix on webpack-generated assets, for example. See whole explanation here.

I then found out this will be available in workbox-webpack-plugin v4: GoogleChrome/workbox#1591

We can still do all of that work manually:

  1. Read contents of precache-manifest.*.js
  2. Mimic modifyUrlPrefix according to the existing exportPathMap
  3. Remove revision from hashed files (maybe all)
  4. Ignore unserved files (e.g. build-manifest.json)

I'd be ok to wait for v4, given the current version is working fine. Reading from the generated precache manifest is just a more accurate process.

404 servce-worker.js http 404

Request URL: http://localhost:3000/service-worker.js
Referrer Policy: no-referrer-when-downgrade
Provisional headers are shown
Referer: http://localhost:3000/service-worker.js
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_13_0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.77 Safari/537.36

404 pages

next-config.js

const withOffline = require('next-offline')

// module.exports = withOffline({ dontAutoRegisterSw: true })
module.exports = withOffline({
webpack(config, options) {
return config
}
})

?????

How can unregister service worker?

It seems the old service worker will be always there if we just remove the plugin for next.config.js.

Is there any instruction to unregister the existing service worker? Thanks.

Nested pages aren't precached

If you have nested routes/pages they aren't precached by the plugin. Only the top level pages are precached. Not sure if this is intentional or a bug.

Here is an example of a directory structure where only one of the two pages is precached.

./pages/is-precached.js
./pages/this/isnt-precached.js

Great Plugin

Hi,

I was using the sw-precache-webpack plugin to get offline support working. I had this setup alongside Onesignal for push notifications. The thing is I have to import my service worker with importScripts into the Onesignal workers.

Is there any way of disabling the registration of the service worker provided by this plugin, so I can just import it or manually start it myself?

Workbox configuration options that are not needed?

Hi! πŸ‘‹

Thank you for this great package. I'm seeing this output and just wondering if there's anything to be concerned about (or would become a concern in the future):

WARNING You're using the following Workbox configuration options: [globDirectory, globPatterns]. In Workbox v3 and later, this is usually not needed. Please see https://goo.gl/EQ4Rhm for more info.

Thanks!

Dev build fails if there is no .next dir

Coming from cyrilwanner/next-compose-plugins#11, the development build/server fails when there is no .next directory containing a build. This can happen when a project is set up/cloned initially or when the folder gets removed before a new dev build.

I created a minimal repository to reproduce this bug with only next-offline used: https://github.com/cyrilwanner/next-offline-bug

I think that next.js always calls the function defined at exportPathMap, not only for production builds, in which next-offline tries to get the BUILD_ID file. If this is not needed for dev builds, we can probably add a check to skip this function if it is a dev build as you already do in the webpack config function.

Total precache size is about 0 B for 0 resources.

Expected Behavior

The next-offline should precache all .next folder's ressources?

Current Behavior

Cache nothing.

Steps to Reproduce (for bugs)

  • Do install same README document
  • Run npm build

The result is:

Using "webpack" config function defined in next.config.js.
Total precache size is about 0 B for 0 resources.

Context

I would like to use next-offline with NextJS

My Environment

Tech Version
next 5.0.0
React 16.2
node 8.9.4
OS MacOSX
browser Chrome
etc

Remove hard-coded assumptions

If I wanted to output the generated service worker to any other place (e.g. .next/static or static - so they are automatically statically served) using workboxOpts.swDest then everything else breaks 😬

Turn off clean-webpack-plugin warnings

During Next.js build, I get console warnings like:

> clean-webpack-plugin: /usr/src/.next/precache-manifest.*.js has been removed.

Since this is normal desired behavior, can we disable these messages since they give the impression that there is a problem?

Allow to use InjectManifest plugin instead of GenerateSw

My use case requires to have custom service-worker logic.
I forked this repo and added the possibility to have a custom sw file via InjectManifest passing an generateSw false boolean option to next-offline like:

withOffline({
  ...config,
  dontAutoRegisterSw: true,
  generateSw: false,
  workboxOpts: {
    swSrc: resolve(paths.appComponents, 'service-worker.js')
  }
})

Runtime cache of initial route

Hi @hanford

I am trying out this plugin, and its great that is caches all js-files, but still the issue with runtime cache of initial route is present.

It's the old story about a user that visit your homepage, navigate to sub-page and then leaves. If he never navigate back to your homepage, he will later get the chome-dino if he (while offline) try to visit your homepage.

Do you have any thoughts about this, or is this a user-land problem? What I did in my approach was to add a custom-script to the sw-precache which I from frontend could call a method in the service-worker that added the pathname to manually cached

/service-worker.js 404 request failed, when deployed to production

I have read the documentation and the 3 other issues on here with a 404 issue and anything else I could find.

When I run $ next build && NODE_ENV=production node server.js everything gets served correctly on localhost:3000. No problems there.

However, as soon as I try to deploy my application to a production environment using now zeit I get an error:

A bad HTTP response code (404) was received when fetching the script.
Failed to load resource: net::ERR_INVALID_RESPONSE
main-8ae275bee0ba164baa7e.js:1 SW registration failed:
TypeError: Failed to register a ServiceWorker: A bad HTTP response code (404) was received when fetching the script.

^ One interesting note is that the error says "HTTP" response. but this is running on https. (might be related to the issue) but the request is https, so I think that's just a generic error message.

image

Full request URL: https://formula-stocks-oyjdhconcy.now.sh/service-worker.js

I followed the guide in the docs, and tried different variations I've seen from other issues.

I also tried to use createReadStream to server it directly in the response, but same problem.

Currently I'm trying the following solution from the README:

server.js

const { createServer } = require('https')
const { parse } = require('url')
const { join } = require('path')
const next = require('next')

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

app.prepare().then(() => {
  createServer((req, res) => {
    // Be sure to pass `true` as the second argument to `url.parse`.
    // This tells it to parse the query portion of the URL.
    const parsedUrl = parse(req.url, true)
    const { pathname, query } = parsedUrl

    if (pathname === '/service-worker.js') {
      const filePath = join(__dirname, '.next', pathname)
      app.serveStatic(req, res, filePath)
    } else if (pathname.indexOf('dashboard/articles/') > -1) {
      app.render(req, res, '/dashboard/articles/article', query)
    } else if (pathname.indexOf('articles/') > -1) {
      app.render(req, res, '/articles/article', query)
    } else {
      handle(req, res, parsedUrl)
    }
  }).listen(3000, err => {
    if (err) throw err
    console.log('> Ready on http://localhost:3000')
  })
})

next.config.js

const withPlugins = require('next-compose-plugins')
const withBundleAnalyzer = require('@zeit/next-bundle-analyzer')
const withOffline = require('next-offline')

module.exports = withPlugins([
  [
    withBundleAnalyzer,
    {
      analyzeServer: ['server', 'both'].includes(process.env.BUNDLE_ANALYZE),
      analyzeBrowser: ['browser', 'both'].includes(process.env.BUNDLE_ANALYZE),
      bundleAnalyzerConfig: {
        server: {
          analyzerMode: 'static',
          reportFilename: '../../bundles/server.html',
        },
        browser: {
          analyzerMode: 'static',
          reportFilename: '../bundles/client.html',
        },
      },
    },
  ],
  [withOffline],
])

the whole .next is ignored in both .gitignore and .nowignore

The .next/server-worker.js file is generated correctly on next build

I have no other files related to the service worker or next-offline.
next-offline is in my dependencies, and successfully installed in node_modules

next version: 7.0.2
next-offline: 3.2.1

Any ideas why this is happening when deployed in a prod environment?

Deployed application with the error: https://formula-stocks-snjnaoeivp.now.sh/ (this instance might no longer exist when you are reading this)

How to transpile autogenerated service worker

Hi,

My autogenerated service worker has a trailing comma when using the importScripts option from workbox, this is causing the service worker to fail to register in browsers that do not support the trailing comma on methods like Edge. Is there a way to transpile the autogenerated file before copying to ./next folder?

My config

 [
      withOffline,
      {
        workboxOpts: {
          globPatterns: ['static/**/*'],
          globDirectory: '.',
          runtimeCaching: [
            { urlPattern: /^https?.*/, handler: 'networkFirst' }
          ],
          importScripts: [
            'https://storage.googleapis.com/workbox-cdn/releases/3.2.0/workbox-precaching.prod.js'
          ]
        }
      }
    ]

Autogenerated trailing comma

importScripts("https://storage.googleapis.com/workbox-cdn/releases/3.2.0/workbox-sw.js");

importScripts(
  "https://storage.googleapis.com/workbox-cdn/releases/3.2.0/workbox-precaching.prod.js",
  
);

Thanks : )

Exclude _document.js

There is no _document.js in _next directory, but it is added to precache list, resulting 404 calls in SW.

better next export support

currently next-offline only works with next export when the user has an exportPathMap [email protected] now will generate the path map if the user doesn't declare one and next-offline should support that use case.

Cannot register service-worker

We have recently moved our application to Next.js and are now having difficulties loading the service worker.
We were able to register the service worker using a simple example. However, as soon we started to add more pages and loading data from the server. We are not sure how to configure correctly next-offline workbox options. The service worker gives us the error;

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

Does anyone know which configurations or files we should be looking to fix this? A working example with caching fetching data from the server would also be great. Thank you!

Please, provide a basic next.js + next-offline + express custom server basic example

I'm starting from scratch and actually I have

/static/favicon.ico
/static/pages/index.js
/static/pages/about.js
/server.js
/next.config.js

/server.js

const express = require('express')
const next = require('next')
const path = require('path')

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

app.prepare()
  .then(() => {
    const server = express()

    server.get("/service-worker.js", (req, res) => {
      // Don't cache service worker is a best practice (otherwise clients wont get emergency bug fix)
      res.set("Cache-Control", "no-store, no-cache, must-revalidate, proxy-revalidate");
      res.set("Content-Type", "application/javascript");
      if (dev) {
        console.log('dev - sw from static');
        app.serveStatic(req, res, path.resolve("./static/service-worker.js"));
      } else {
        console.log('next - sw from next');
        app.serveStatic(req, res, path.resolve("./.next/service-worker.js"));
      }
    });

    server.get('*', (req, res) => {
      return handle(req, res)
    })

    server.listen(3000, (err) => {
      if (err) throw err
      console.log('> Ready on http://localhost:3000')
    })
  })
  .catch((ex) => {
    console.error(ex.stack)
    process.exit(1)
  })

/next.config.js

const withOffline = require('next-offline')

module.exports = withOffline();

/pages/index.js

import Link from 'next/link'
import Head from 'next/head'

const Index = () => (
  <div>
    <Head>
      <title>My page title</title>
      <meta name="viewport" content="initial-scale=1.0, width=device-width" />
      <link rel="icon" href="/static/favicon.ico"></link>
    </Head>

    <Link href="/about">
      <a>About Page</a>
    </Link>
    <p>Hello Next.js</p>
  </div>
)

export default Index

/pages/about.js

export default () => (
  <div>
    <p>This is the about page</p>
  </div>
)

scripts in package.json

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "dev": "node server.js",
    "build": "next build",
    "export": "next export",
    "start": "cross-env NODE_ENV=production node server.js"
  },

After npm run build, I execute npm start.

Is this the right way to combine next, espress and next-offline?

What make me suspecting that something is wrong is that in production (npm start) , if I go online, visist index and about, then go offline, all is working until I reload the page when am I offline: in this case the /static/favicon.ico is not served. It gives a 404.

In the readme I see

By default next-offline will precache all the Next.js webpack emitted files and the user-defined static ones (inside /static) - essentially everything that is exported as well.

So I was expecting the /static/favicon.ico must be automatically included in app cache. Also, as you can see, to (uselessly try to) force the cachine of favicon.ico, I added manually the head meta link to point to /static/favicon.ico.

What am I doing wrong? What's the right way to write the server.js? Must manually setup a route to distinguish dev and production mode for service-worker.js?

Thanks in advance

Ie11 arrow function issue

register-sw.js uses arrow functions which is not supported in ie11. I see there is an option to disable automatic registration to avoid this from being fired, but is there a way to customize this without injecting my own?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    πŸ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. πŸ“ŠπŸ“ˆπŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❀️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.