Giter Club home page Giter Club logo

sw-precache-webpack-plugin's Introduction

SW Precache Webpack Plugin

NPM version NPM downloads CircleCI

SWPrecacheWebpackPlugin is a webpack plugin for using service workers to cache your external project dependencies. It will generate a service worker file using sw-precache and add it to your build directory.

🚨 No longer being updated

I will try to keep this up-to-date with new webpack releases so feel free to keep using this if you like but I will not be adding any new features. I would recommend using workbox-webpack-plugins#GenerateSW which is actively being supported.

Install

npm install --save-dev sw-precache-webpack-plugin

Basic Usage

A simple configuration example that will work well in most production environments. Based on the configuration used in create-react-app.

var path = require('path');
var SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');

const PUBLIC_PATH = 'https://www.my-project-name.com/';  // webpack needs the trailing slash for output.publicPath

module.exports = {

  entry: {
    main: path.resolve(__dirname, 'src/index'),
  },

  output: {
    path: path.resolve(__dirname, 'src/bundles/'),
    filename: '[name]-[hash].js',
    publicPath: PUBLIC_PATH,
  },

  plugins: [
    new SWPrecacheWebpackPlugin(
      {
        cacheId: 'my-project-name',
        dontCacheBustUrlsMatching: /\.\w{8}\./,
        filename: 'service-worker.js',
        minify: true,
        navigateFallback: PUBLIC_PATH + 'index.html',
        staticFileGlobsIgnorePatterns: [/\.map$/, /asset-manifest\.json$/],
      }
    ),
  ],
}

This will generate a new service worker at src/bundles/service-worker.js. Then you would just register it in your application:

(function() {
  if('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/service-worker.js');
  }
})();

Another example of registering a service worker is provided by GoogleChrome/sw-precache

Configuration

You can pass a hash of configuration options to SWPrecacheWebpackPlugin:

plugin options:

  • filename: [String] - Service worker filename, default is service-worker.js
  • filepath: [String] - Service worker path and name, default is to use webpack.output.path + options.filename. This will override filename. Warning: Make the service worker available in the same directory it will be needed. This is because the scope of the service worker is defined by the directory the worker exists.
  • staticFileGlobsIgnorePatterns: [RegExp] - Define an optional array of regex patterns to filter out of staticFileGlobs (see below)
  • mergeStaticsConfig: [boolean] - Merge provided staticFileGlobs and stripPrefixMulti with webpack's config, rather than having those take precedence, default is false.
  • minify: [boolean] - Set to true to minify and uglify the generated service-worker, default is false.

sw-precache options: Pass any option from sw-precache into your configuration. Some of these will be automatically be populated if you do not specify the value and a couple others will be modified to be more compatible with webpack. Options that are populated / modified:

  • cacheId: [String] - Not required but you should include this, it will give your service worker cache a unique name. Defaults to "sw-precache-webpack-plugin".
  • importScripts: [Array<String|Object>]
    • When importScripts array item is a String:
      • Converts to object format { filename: '<publicPath>/my-script.js'}
    • When importScripts array item is an Object:
      • Looks for chunkName property.
      • Looks for filename property.
      • If a chunkName is specified, it will override the accompanied value for filename.
  • replacePrefix: [String] - Should only be used in conjunction with stripPrefix
  • runtimeCaching: [Array<Object>] - Configures runtime caching for dynamic content such as HTTP requests. Refer to sw-precache to see all available options.
  • staticFileGlobs: [Array<String>] - Omit this to allow the plugin to cache all your bundles' emitted assets. If mergeStaticsConfig=true: this value will be merged with your bundles' emitted assets, otherwise this value is just passed to sw-precache and emitted assets won't be included.
  • stripPrefix: [String] - Same as stripPrefixMulti[stripPrefix] = ''
  • stripPrefixMulti: [Object<String,String>] - Omit this to use your webpack config's output.path + '/': output.publicPath. If mergeStaticsConfig=true, this value will be merged with your webpack's output.path: publicPath for stripping prefixes. Otherwise this property will be passed directly to sw-precache and webpack's output path won't be replaced.

Note that all configuration options are optional. SWPrecacheWebpackPlugin will by default use all your assets emitted by webpack's compiler for the staticFileGlobs parameter and your webpack config's {[output.path + '/']: output.publicPath} as the stripPrefixMulti parameter. This behavior is probably what you want, all your webpack assets will be cached by your generated service worker. Just don't pass any arguments when you initialize this plugin, and let this plugin handle generating your sw-precache configuration.

Examples

See the examples documentation or the implementation in create-react-app.

Simplest Example

No arguments are required by default, SWPrecacheWebpackPlugin will use information provided by webpack to generate a service worker into your build directory that caches all your webpack assets.

module.exports = {
  ...
  plugins: [
    new SWPrecacheWebpackPlugin(),
  ],
  ...
}

Advanced Example

Here's a more elaborate example with mergeStaticsConfig: true and staticFileGlobsIgnorePatterns. mergeStaticsConfig: true allows you to add some additional static file globs to the emitted ServiceWorker file alongside webpack's emitted assets. staticFileGlobsIgnorePatterns can be used to avoid including sourcemap file references in the generated ServiceWorker.

plugins: [
  new SWPrecacheWebpackPlugin({
    cacheId: 'my-project-name',
    filename: 'my-project-service-worker.js',
    staticFileGlobs: [
      'src/static/img/**.*',
      'src/static/styles.css',
    ],
    stripPrefix: 'src/static/', // stripPrefixMulti is also supported
    mergeStaticsConfig: true, // if you don't set this to true, you won't see any webpack-emitted assets in your serviceworker config
    staticFileGlobsIgnorePatterns: [/\.map$/], // use this to ignore sourcemap files
  }),
]

Generating Multiple Service Workers

If you have multiple bundles outputted by webpack, you can create a service worker for each. This can be useful if you have a multi-page application with bundles specific to each page and you don't need to download every bundle (among other reasons).

/**
 * @module {Object} webpack.config
 */
const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');

/** @constant {Object} Application entry points and bundle names */
const APPS = {
  home: path.resolve(__dirname, 'src/home'),
  posts: path.resolve(__dirname, 'src/posts'),
  users: path.resolve(__dirname, 'src/users'),
}

/** @constant {string} build directory name */
const OUTPUT_DIR = 'dist';

/**
 * @alias webpack.config
 * @type {Object}
 */
module.exports = {

  entry: APPS,

  output: {
    path: path.resolve(__dirname, OUTPUT_DIR),
    filename: '[name].[hash].js',
  },

  plugins: [
    // iterate over each `entry[app]` key.
    ...Object.keys(APPS)
      .map(app => new SWPrecacheWebpackPlugin({
        cacheId: `${app}`,
        filename: `${app}-service-worker.js`,
        stripPrefix: OUTPUT_DIR,
        // We specify paths to the compiled destinations of resources for each "app's"
        // bundled resources. This is one way to separate bundled assets for each
        // application.
        staticFileGlobs: [
          `${OUTPUT_DIR}/js/manifest.*.js`,
          `${OUTPUT_DIR}/js/${app}.*.js`,
          `${OUTPUT_DIR}/css/${app}.*.css`,
          `${OUTPUT_DIR}/${app}.html`,
        ],
      })),
  ],
}

importScripts usage example

Accepts an array of <String|Object>'s. String entries are legacy supported. Use filename instead.

If importScripts item is object, there are 2 possible properties to set on this object:

  • filename: Use this if you are referencing a path that "you just know" exists. You probably don't want to use this for named chunks.
  • chunkName: Supports named entry chunks & dynamically imported named chunks.
entry: {
  main: __dirname + '/src/index.js',
  sw: __dirname + '/src/service-worker-entry.js'
},
output: {
  publicPath: '/my/public/path',
  chunkfileName: '[name].[<hash|chunkhash>].js'
},
plugins: [
  new SWPrecacheWebpackPlugin({
    filename: 'my-project-service-worker.js',
    importScripts: [
      // * legacy supported
      // [chunkhash] is not supported for this usage
      // This is transformed to new object syntax:
      // { filename: '/my/public/path/some-known-script-path.js' }
      'some-known-script-path.js',

      // This use case is identical to above, except
      // for excluding the .[hash] part:
      { filename: 'some-known-script-path.[hash].js' },

      // When [chunkhash] is specified in filename:
      // - filename must match the format specified in output.chunkfileName
      // - If chunkName is invalid; an error will be reported
      { chunkName: 'sw' },

      // Works for named entry chunks & dynamically imported named chunks:
      // For ex, if in your code is:
      // import(/* webpackChunkName: "my-named-chunk" */ './my-async-script.js');
      { chunkName: 'my-named-chunk' },

      // All importScripts entries resolve to a string, therefore
      // the final output of the above input is:
      // [
      //   '/my/public/path/some-known-script-path.js',
      //   '/my/public/path/some-known-script-path.<compilation hash>.js',
      //   '/my/public/path/some-known-script-path.<chunkhash>.js',
      //   '/my/public/path/<id>.my-named-chunk.<chunkhash>.js'
      // ]
    ]
  }),
]

Webpack Dev Server Support

Currently SWPrecacheWebpackPlugin will not work with webpack-dev-server. If you wish to test the service worker locally, you can use simple a node server see example project or python SimpleHTTPServer from your build directory. I would suggest pointing your node server to a different port than your usual local development port and keeping the precache service worker out of your local configuration (example).

Or add setup section to devServer config, e.g.:

module.exports = {
    devServer: {
        setup: function (app) {
            app.get('/service-worker.js', function (req, res) {
                res.set({ 'Content-Type': 'application/javascript; charset=utf-8' });
                res.send(fs.readFileSync('build/service-worker.js'));
            });
        }
    }
}

There will likely never be webpack-dev-server support. sw-precache needs physical files in order to generate the service worker. webpack-dev-server files are in-memory. It is only possible to provide sw-precache with globs to find these files. It will follow the glob pattern and generate a list of file names to cache.

Contributing

Install node dependencies:

  $ npm install

Or:

  $ yarn

Add unit tests for your new feature in ./test/plugin.spec.js

Testing

Tests are located in ./test

Run tests:

  $ npm t

sw-precache-webpack-plugin's People

Contributors

andriijas avatar capouch avatar christianhg avatar cpxpratik avatar dkrnl avatar ghengeveld avatar goldhand avatar hosar avatar hulkish avatar jorgeortega avatar lencioni avatar lyf1999 avatar max-b avatar maxweldsouza avatar miccycn avatar michaseel avatar mrmaxmeier avatar neeharv avatar pavelloz avatar rkostrzewski avatar salzhrani avatar secretmapper avatar simonkberg avatar thetechie avatar uditalias 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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sw-precache-webpack-plugin's Issues

Upgrade sw-precache dependency

Would we be able to update to the latest sw-precache version? Currently it looks like this lib depends on v4.1.0 released last sept, but it's now up to v4.3.0, with the latest release including some useful bug fixes.

Can't get service worker when offline

I'm generating the service worker using webpack 2. It's marked as registered and running in DevTools, works brilliantly on throttled connections, but fails to even get when fully offline. Just get a generic An unknown error occurred when fetching the script. failure.

I'm also working on localhost (not sure if that's relevant)

Not sure what other kind of information would be relevant here, but if I'm missing anything of importance let me know

Service worker not loading when offline

So, when attempting to load my site, after setting network to 'offline' in devTools, I am presented with (see attached image):

An unknown error occurred when fetching the script.
service-worker.js Failed to load resource: net::ERR_INTERNET_DISCONNECTED

My code is as follows:

webpack.js

var path = require('path');
var webpack = require('webpack');
var SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');

module.exports = {
  devtool: 'source-map',
  context: __dirname,
  entry: {
    main: path.resolve(__dirname, './client/app'),
  },
  output: {
    path: path.join(__dirname, '/public'),
    filename: '[name]-[hash].js',
    publicPath: '/public/'
  },
  plugins: [
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.DefinePlugin({
      'process.env': {
        'NODE_ENV': "'production'"
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        warnings: false
      }
    }),
    new SWPrecacheWebpackPlugin(
      {
        cacheId: 'flamingoCity',
        filename: 'service-worker.js',
        stripPrefix: path.join(__dirname, 'public').replace(/\\/g,"/"),
        maximumFileSizeToCacheInBytes: 6194304,
        minify: true,
        runtimeCaching: [{
          handler: 'cacheFirst',
          urlPattern: /[.]mp3$/,
        }],
      }
    ),
  ],
  module: {
    loaders: [
    // js
    {
      test: /\.js$/,
      loaders: ['babel'],
      include: path.join(__dirname, 'client')
    },
    // CSS
    { 
      test: /\.styl$/, 
      include: path.join(__dirname, 'client'),
      loader: 'style-loader!css-loader!stylus-loader'
    }
    ]
  }
};

index.html

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Flamingo City</title>
    <link rel="shortcut icon" type="image/png" href="http://wes.io/ehRe/my-favourite-icon.png"/>
  </head>
  <body>
    <div id="root"></div>
    <script type="text/javascript" src="/main-bcd2549cd3ae2963222b.js"></script>
    <script>
      /*
        Register Service Worker
      */

      if('serviceWorker' in navigator) {
        window.addEventListener('load', function() {
          console.log('CLIENT: service worker registration in progress.');
          navigator.serviceWorker.register('/service-worker.js').then(function(reg) {
          console.log("CLIENT: service worker registration succeeded. Scope is " + reg.scope)
          reg.onupdatefound = function() {
            var installingWorker = reg.installing;

            installingWorker.onstatechange = function() {
              switch (installingWorker.state) {
                case 'installed':
                  if (navigator.serviceWorker.controller) {
                    console.log('CLIENT: New or updated content is available.');
                  } else {
                    console.log('CLIENT: Content is now available offline!');
                  }
                  break;

                case 'redundant':
                  console.error('CLIENT: The installing service worker became redundant.');
                  break;
              }
            };
          };
          }).catch(function(e) {
            console.error('CLIENT: Error during service worker registration:', e);
          });
        });
      }
    </script>
  </body>
</html>

What is the issue here?

service-worker-error

Misspelled constant in examples/webpack.config.js

It's wrong the same way in both places, so it doesn't have any effect on operations, but this is the kind of thing that might bite somebody later.

IGONRE -> IGNORE

const SERVICE_WORKER_IGONRE_PATTERNS = [/dist\/.*\.html/]; const SW_PRECACHE_CONFIG = { cacheId: SERVICE_WORKER_CACHEID, filename: SERVICE_WORKER_FILENAME, staticFileGlobsIgnorePatterns: SERVICE_WORKER_IGONRE_PATTERNS,

Set up SWPrecache to cache index and return 200 when offline

I am trying to make the webapp usable offline, how do I do this with this plugin?

I have this config:

new SWPrecacheWebpackPlugin(
  {
    cacheId: 'my-project',
    filename: 'my-project-sw.js',
    filepath: publicDir + '/my-project-sw.js',
    staticFileGlobs: [
      assetsDir + '/**/*.{json,webmanifest}',
      assetsDir + '/**/*.css',
      assetsDir + '/**/*.{ttf,woff,woff2,eof}',
      assetsDir + '/**/*.js',
      assetsDir + '/**/*.map',
      publicDir + '/index.html',
      assetsDir + '/**/*.{png,jpg,jpeg,ico,gif,svg}'
    ],
    verbose: true,
    navigateFallback: '/index.html',
    runtimeCaching: [{
      urlPattern: /\/api\//,
      handler: 'networkFirst'
    },{
      urlPattern: /\/assets\//,
      handler: 'cacheFirst'
    }]
  }
)

stripPrefix not stripped, but added

Hi there,

I'm using this plugin to cache some static files. I try doing this by adding the code below. The issue is in the array of staticFileGlobs.

    new SWPrecacheWebpackPlugin({
      cacheId: 'prod1',
      filepath: `${PATHS.build}/sw.js`,
      maximumFileSizeToCacheInBytes: 4194304,
      staticFileGlobs: [`${PATHS.assets}/*.{png,jpg,gif,svg}`, `${PATHS.publicDir}/fonts/*.{ttf,woff}`],
      stripPrefix: '/Users/username/Developer/React/website.com/public/'
    }),

The images with PATHS.assets are correctly inserted in my service worker. This is my main webpack output path. But the fonts in PATHS.publicDir are inserted into the service worker with the absolute path of my computer. I did try to strip this text by adding it to the stripPrefix, but it seems that this doesn't work as expected.

Any heads up?

Hash is not preserved on importScripts

If I set importScripts:['sw-[hash].js'], the [hash] is not preserved so when executing webpack in watch mode it always return the first hash that was set and not the new one.

Cannot get offline access to other pages in a SPA

Hi,
I'm using this plugin and trying to get offline access to my single page app built with react.js. But I can only get the home page to show when I'm offline, and not the other routes. i.e. my home page, https://mysoundwise.com, can be rendered offline, but an url such as https://mysoundwise.com/courses/112 returns chrome's dinosaur and "there's no internet connection" message. I set the navigateFallback option to index.html. But it does not help.

The webpack.config.js file:

var path = require('path');
var SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');

module.exports = {
  context: __dirname,
  entry: [
    'babel-polyfill',
    './client/index.js'
  ],
  output: {
    path: path.resolve(__dirname, 'client/'),
    publicPath: '/',
    filename: 'bundle.js'
  },
  module: {
    loaders: [{
      exclude: /node_modules/,
      loader: 'babel',
      query: {
        presets: ['react', 'es2015', 'stage-1']
      }
    },
    {
      test: /\.(jpg|png)$/,
      loader: 'url-loader?mimetype=image/png'
    }]
  },
  resolve: {
    extensions: ['', '.js', '.jsx']
  },
  devServer: {
    historyApiFallback: true,
    contentBase: './client'
  },
  plugins: [
    new SWPrecacheWebpackPlugin(
      {
        cacheId: 'Soundwise',
        filename: 'service-worker.js',
        maximumFileSizeToCacheInBytes: 10485760, //10mb
        minify: false,
        stripPrefix: 'client/',
        navigateFallback: 'client/index.html',
        staticFileGlobs: [
          'client/index.html',
          'client/css/**.css',
          'client/bundle.js'
        ]
   ],
      }
    ),
  ]
};

Does anybody have an idea of what's wrong? Thanks!

How to importScripts that are generated by webpack?

Hi!, I need some help. How do I import an script that is generated by webpack?
I mean in the import section how do I pass the hash that is generated by webpack, so when the service worker file is created, it can import the correct script.
(this is not an issue, I just need some help. Please tell me If I need to open a question on stackoverflow and what tag should I use. Thanks in advance)

new swPrecacheWebpackPlugin(
      {
        cacheId: 'myCoffeeB',
        filename: 'swPrecache.js',
        staticFileGlobsIgnorePatterns: SERVICE_WORKER_IGONRE_PATTERNS,
        maximumFileSizeToCacheInBytes: 4194304,
        importScripts:['sw-[hash].js'],
   }

Fetch event listener not working

i have the following webpack config

new SWPrecacheWebpackPlugin({
        //cacheId: '[app_name]',
        filename: 'connect-service-worker.js',
        staticFileGlobs: ['./views/build/*'],
        dontCacheBustUrlsMatching: [/./]
      }),
html  
  head
    title= title
    meta(name='viewport', content='width=device-width, initial-scale=1.0') 
  body
    #app
    script(src="build/" + vendor)
    script(src="build/" + bundle)
    script.
      if(navigator.serviceWorker) {
        navigator.serviceWorker.register('./build/connect-service-worker.js')
          .then(function(registration) {
            console.log('Service worker successfully installed with scope',registration.scope)
          })
          .catch(function(err) {
            // registration failed :(
            console.log('ServiceWorker registration failed: ', err);
          });
      } 

i am caching the entire build folder. My service worker is also created in the build folder itself. The above code installs the service worker correctly, and i can see my assets cached, but the next time i refresh the browser a fresh request is made, even on putting a breakpoint in the fetch listener, i dont see the flow going into that block. Anything i'm doing wrong. Any helo would be great.

importScripts add default url automatically

When adding the publicPath to the importScripts section it will generate something like:
importScripts('http://localhost:3000/otherscript.js'). But importScripts adds an url by default, so when trying to import I'm getting something like:
importScripts('http://localhost:3000/http://localhost:3000/otherscript.js') causing an error.
In webpack.config I set:
new swPrecacheWebpackPlugin({
importScripts:['someScript-[hash].js']
})

Is this expected? because now I'm getting an error because import scripts can not find
http://localhost:3000/http://localhost:3000/otherscript.js

Should I set the script in a different way in webpack?

[Bug] Option 'filename' doesn't name sw correctly

Here's the config:

new SWPrecacheWebpackPlugin({
      cacheId: 'example-cache',
      filename: 'example-sw-precache.js',
      maximumFileSizeToCacheInBytes: 4194304
}),

However after build i see that it is being compiled to service-worker.js in my output dir.

Items are added to Cache Storage but don't have response OK ?

Just noticed that items added via this plugin get added to Cache Storage correctly, but seem to have an empty response instead of the response (OK).

captureswcache

new SWPrecacheWebpackPlugin({
    cacheId: pkg.name,
    filename: 'sw.js',
    minify: true,
    maximumFileSizeToCacheInBytes: 4194304,
}),

Everything seems to be working and a page hit it responds with 200 from Service Worker, but on other sites with Service Workers I see 200 (OK) from Service Worker.

cached but not loaded through service worker cache

First of all, awesome plugin. Looks like so much flexibility, the right way!

I have been trying to get my server side rendered react app to be supported offline.I am using this boilerplate

https://github.com/erikras/react-redux-universal-hot-example

My service worker is registered, running and I can see the cached resources in Cache Storage. Basically all of my assets created through webpack are cached. Cool.

Here's a snapshot of that:

res

Two problems I am facing:

  1. None of the resources, not even the cached ones I see in Cache Storage are getting loaded from service worker but either disk cache or memory cache as I see in my network tab in chrom console

Literally none of them. Attached snapshot:

res2

  1. My website is not working offline even though resources are cached.

nooffline

Why is that? What do I exactly need to do to make it work offline?

Note: The HTML generated at the server is through a react component that looks like this:

(coming straight from the boilerplate so you could use this boilerplate to reproduce the issue)

(I am using production version here on my local system)

This component gets server side rendered through renderToString function of react.


import React, {Component, PropTypes} from 'react';
import ReactDOM from 'react-dom/server';
import serialize from 'serialize-javascript';
import Helmet from 'react-helmet';

/**
 * Wrapper component containing HTML metadata and boilerplate tags.
 * Used in server-side code only to wrap the string output of the
 * rendered route component.
 *
 * The only thing this component doesn't (and can't) include is the
 * HTML doctype declaration, which is added to the rendered output
 * by the server.js file.
 */
export default class Html extends Component {
  static propTypes = {
    assets: PropTypes.object,
    component: PropTypes.node,
    store: PropTypes.object
  };

  render() {
    const {assets, component, store} = this.props;
    const content = component ? ReactDOM.renderToString(component) : '';
    const head = Helmet.rewind();

    return (
      <html lang="en-us">
        <head>
          {head.base.toComponent()}
          {head.title.toComponent()}
          {head.meta.toComponent()}
          {head.link.toComponent()}
          {head.script.toComponent()}

          <link rel="shortcut icon" href="/favicon.ico" />
          <meta name="viewport" content="width=device-width, initial-scale=1" />
          {/* styles (will be present only in production with webpack extract text plugin) */}
          {Object.keys(assets.styles).map((style, key) =>
            <link href={assets.styles[style]} key={key} media="screen, projection"
                  rel="stylesheet" type="text/css" charSet="UTF-8"/>
          )}

          {/* (will be present only in development mode) */}
          {/* outputs a <style/> tag with all bootstrap styles + App.scss + it could be CurrentPage.scss. */}
          {/* can smoothen the initial style flash (flicker) on page load in development mode. */}
          {/* ideally one could also include here the style for the current page (Home.scss, About.scss, etc) */}
          { Object.keys(assets.styles).length === 0 ? <style dangerouslySetInnerHTML={{__html: require('../theme/bootstrap.config.js') + require('../containers/App/App.scss')._style}}/> : null }
        </head>
        <body>
          <div id="content" dangerouslySetInnerHTML={{__html: content}}/>
          <script dangerouslySetInnerHTML={{__html: `window.__data=${serialize(store.getState())};`}} charSet="UTF-8"/>
          <script src={assets.javascript.main} charSet="UTF-8"/>
        </body>
      </html>
    );
  }
}


Could I please get some help on this?

error in plugin or enviorment

Hi,

I'm getting following error while trying to integrate swpreacache plugin.

ERROR in .//sw-precache-webpack-plugin/lib/index.js
Module not found: Error: Can't resolve 'fs' in '/home/rohitn/dbs/node_modules/sw-precache-webpack-plugin/lib'
@ ./
/sw-precache-webpack-plugin/lib/index.js 27:10-23
@ ./nuxt.config.js
@ ./plugins/axios.js
@ .//babel-loader/lib?{"presets":["vue-app"],"cacheDirectory":false}!.//vue-loader/lib/selector.js?type=script&index=0!./pages/index.vue
@ ./pages/index.vue
@ ./.nuxt/router.js
@ ./.nuxt/index.js
@ ./.nuxt/client.js

Any idea what such error mean?

How to use with multiple service workers

BEFORE YOU SUBMIT please read the following:

  • I'm submitting a bug report
  • I'm submitting a feature request
  • I'm submitting a support request

webpack version:
2.2.1

sw-precache-webpack-plugin version:
0.9.1

I have an additional service worker at the moment, that handles push notifications. How can I combine the generated one which handles the fetches and my current one?

Service Worker termination by a timeout timer was canceled because DevTools is attached.

OS: Windows 10 Pro
webpack: 1.14.0
sw-precache-webpack-plugin: 0.9.1
sw-precache: 5.0.0

So, I launch my site and don't actively do anything for a few moments, and then the above specified error message is generated in devTools (See attached image). If some process is carried out, the the error does not arise.

My React code is as follows:

webpack.config.prod.js

var path = require('path');
var webpack = require('webpack');
var SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin');

module.exports = {
  devtool: 'source-map',
  context: __dirname,
  entry: {
    main: path.resolve(__dirname, './client/app'),
  },
  output: {
    path: path.join(__dirname, '/public'),
    filename: 'bundle.js',
    publicPath: '/public/'
  },
  plugins: [
    new webpack.optimize.OccurenceOrderPlugin(),
    new webpack.DefinePlugin({
      'process.env': {
        'NODE_ENV': "'production'"
      }
    }),
    new webpack.optimize.UglifyJsPlugin({
      compressor: {
        warnings: false
      }
    }),
    new SWPrecacheWebpackPlugin(
      {
        cacheId: 'flamingoCity',
        filename: 'my-service-worker.js',
        stripPrefix: path.join(__dirname, 'public').replace(/\\/g,"/"),
        maximumFileSizeToCacheInBytes: 6194304,
        minify: true,
        runtimeCaching: [{
          handler: 'cacheFirst',
          urlPattern: /[.]mp3$/,
        }],
      }
    ),
  ],
  module: {
    loaders: [
    // js
    {
      test: /\.js$/,
      loaders: ['babel'],
      include: path.join(__dirname, 'client')
    },
    // CSS
    { 
      test: /\.styl$/, 
      include: path.join(__dirname, 'client'),
      loader: 'style-loader!css-loader!stylus-loader'
    }
    ]
  }
};

app.js

/*
  Import Dependencies
*/
import React from 'react';
import { render } from 'react-dom';
import { Provider } from 'react-redux';
import { Router, Route, IndexRoute } from 'react-router'
import 'babel-polyfill';

/*
  Import Components
*/
import App from './components/App';
import Single from './components/Single';
import PhotoGrid from './components/PhotoGrid';

/* Import CSS */
import css from  './styles/style.styl';

/* Import our data store */
import store, { history } from './store';

/*
  Error Logging
*/

import Raven from 'raven-js';
import { sentry_url } from './data/config';
if(window) {
  Raven.config(sentry_url).install();
}

/*
  Register Service Worker
*/

if('serviceWorker' in navigator  && process.env.NODE_ENV === 'production') {
  navigator.serviceWorker.register('./my-service-worker.js').then(function(reg) {
  // updatefound is fired if my-service-worker.js changes.
  reg.onupdatefound = function() {
    // The updatefound event implies that reg.installing is set; see
    // https://slightlyoff.github.io/ServiceWorker/spec/service_worker/index.html#service-worker-container-updatefound-event
    var installingWorker = reg.installing;

    installingWorker.onstatechange = function() {
      switch (installingWorker.state) {
        case 'installed':
          if (navigator.serviceWorker.controller) {
            // At this point, the old content will have been purged and the fresh content will
            // have been added to the cache.
            // It's the perfect time to display a "New content is available; please refresh."
            // message in the page's interface.
            console.log('New or updated content is available.');
          } else {
            // At this point, everything has been precached.
            // It's the perfect time to display a "Content is cached for offline use." message.
            console.log('Content is now available offline!');
          }
          break;

        case 'redundant':
          console.error('The installing service worker became redundant.');
          break;
      }
    };
  };
  }).catch(function(e) {
    console.error('Error during service worker registration:', e);
  });
}

/*
  Rendering
  This is where we hook up the Store with our actual component and the router
*/
render(
  <Provider store={store}>
    { /* Tell the Router to use our enhanced history */ }
    <Router history={history}>
      <Route path="/" component={App}>
        <IndexRoute component={PhotoGrid} />
        <Route path="/view/:postId" component={Single}></Route>
      </Route>
    </Router>
  </Provider>,
  document.getElementById('root')
);

What is the issue here?

error-msg

Make sw-precache-configuration object passable as an argument

Currently filepath is compiler.options.output.path
and cacheId is only configurable in the options argument.
and to pass an sw-precache config you have to specify { options: config }

Just make options a single object (no options.options) and allow a sw-precache configuration to be passed in along with custom options as a single object.

Output assets even when filtered from precache.

Hi,

First thanks for the amazing plugin :)

I have an issue with it, when it comes to not using local caching of assets.

I build my static assets with webpack, and then use staticFileGlobs: [] to prevent them to be cached locally.
I do that because once outputted, all my assets will be uploaded on amazon S3 and served via cloudfront. I then use runtimeCaching to cache them in the service worker.

The problem is, that setting staticFileGlobs: [] seems to block webpack from outputting my assets in my dist directory. Can we still output the assets while not caching them using the plugin ?

Thanks !

Issues using a default offline fallback

Hello, I've been moving from having my own sw-worker to use this plugin cause of the benefits it provides. One thing I can't find how to do is to set a standar offline response (a response that appears then there's no internet connection.

With my previous worker I had an offline.html page precached which will be returned if the was no connection.

Is there a way to implement this with this plugin?

Thanks a lot!

Want to skip urls patterns to server only

My config is as bellow:
SWPrecache({ filename: 'service-worker.js', cacheId: 'v5', staticFileGlobsIgnorePatterns: [/\.map$/], dontCacheBustUrlsMatching: /./, navigateFallback: 'index.html', runtimeCaching: [{ handler: 'networkOnly', urlPattern: /\/app\//, }], })
I have setup of preact, preact-router with default route and webpack.

My requirement is got all urls which has '/app/' in the path go to server but it fallback to index.html and router shows the default rout.

I tried by adding runtimeCaching as well but still result is same.

If I manually modify the get function and check for url path and redirect the code to network it works fine.

Ex:

`self.addEventListener('fetch', function(event) {
if (event.request.method === 'GET') {
// Should we call event.respondWith() inside this fetch event handler?
// This needs to be determined synchronously, which will give other fetch
// handlers a chance to handle the request if need be.
var shouldRespond;

// First, remove all the ignored parameter and see if we have that URL
// in our cache. If so, great! shouldRespond will be true.
var url = stripIgnoredUrlParameters(event.request.url, ignoreUrlParametersMatching);
shouldRespond = urlsToCacheKeys.has(url);

if(/\/app\//.test(url))
  return fetch(event.request);`

Let me know is there any other way to do it in config.

how do i create a separate app shell so i can effectively use sw-precache ? (question)

Apologies , I'm a total newbie in terms of webpack and service workers. I am unsure how to generate a sepertae build file that is my app shell that i can precache. Currently, my webpack config looks like the following which just generates a single index_bundle.js file:

import webpack from 'webpack'
import path from 'path'
import HtmlWebpackPlugin from 'html-webpack-plugin'
import autoprefixer from 'autoprefixer'

const LAUNCH_COMMAND = process.env.npm_lifecycle_event

const isProduction = LAUNCH_COMMAND === 'production'
process.env.BABEL_ENV = LAUNCH_COMMAND

const PATHS = {
  root: path.join(__dirname),
  app: path.join(__dirname, 'app'),
  build: path.join(__dirname, 'dist')
}

const HTMLWebpackPluginConfig = new HtmlWebpackPlugin({
  template: PATHS.app + '/index.html',
  filename: 'index.html',
  inject: 'body'
})

const productionPlugin = new webpack.DefinePlugin({
  'process.env': {
    NODE_ENV: JSON.stringify('production')
  }
})

const productionPlugin2 = new webpack.optimize.UglifyJsPlugin({
  compressor: {
    warnings: false
  }
})

const base = {
  entry: [
    'babel-polyfill',
    PATHS.app
  ],
  output: {
    path: PATHS.build,
    filename: 'index_bundle.js'
  },
  module: {
    loaders: [
      {test: /\.js$/, exclude: /node_modules/, loader: 'babel-loader'},
      {test: /\.css$/, loader: 'style!css?sourceMap&modules&localIdentName=[name]__[local]___[hash:base64:5]&importLoader=1!postcss'}
    ]
  },
  postcss: [ autoprefixer({ browsers: ['last 2 versions'] }) ],
  resolve: {
    root: path.resolve('./app')
  }
}

const developmentConfig = {
  devtool: 'cheap-module-inline-source-map',
  devServer: {
    contentBase: PATHS.build,
    historyApiFallback: true,
    hot: true,
    inline: true,
    progress: true
  },
  plugins: [HTMLWebpackPluginConfig, new webpack.HotModuleReplacementPlugin()]
}

const productionConfig = {
  devtool: 'cheap-module-source-map',
  plugins: [HTMLWebpackPluginConfig, productionPlugin, productionPlugin2]
}

export default Object.assign({}, base, isProduction === true ? productionConfig : developmentConfig)

Plugin is async while registered on a synchronous hook

I stumbled upon an error where the service worker file didn't get written. After looking into the code I noticed the plugin is registering itself on the done compiler hook, which is synchronously executed, while the plugin implementation is asynchronous.

This can be reproduced by exiting immediately after the run callback on the compiler instance.

var webpack = require('webpack')
var webpackConfig = require('./webpack.config')

compiler.run((err, stats) => {
  if (err) throw err

  const result = stats.toString({ chunks: false, colors: true })

  if (stats.hasErrors()) {
    console.error(result)
    process.exit(1) // exit process with an 'error' status code
  } else if (stats.hasWarnings()) {
    console.warn(result)
  } else {
    console.log(result)
  }

  // Everything should be fine, exit the node process with a 'success' status code
  process.exit(0)
  // ...but our service worker was never actually written
})

A PR fixing this will be submitted shortly.

compress generated file

The generated service worker js file can be upwards of 24KB in size. Having the option to minimize or pass it through uglify would be great.

Unless I'm missing something, and it's possible to send the result of this plugin through to the UglifyJS plugin?

Breaks webpack stats (the --json flag)

When running webpack --json we get something like:

{
  "build-stats-etc": "here..."
}
Caching static resource "bla-bla-bla.js" (64.77 kB)
...
Total precache size is about etc MB for xxx resources.

which is invalid JSON. The sw-precache log output is appended to the JSON output.
Could this be due to the plugin logging to stdout, while when running webpack with the --json flag, it's supposed to log to stderr? (or suppress logging?)

webpack 2.2.0-rc.2 compatibility

I've upgraded to webpack 2.2.0-rc.2 and there seems to be no trouble for me at least.

I don't know if you have some sort of validation process to check for full compatibility, and in this case, if you'd like some help to get it done? Otherwise, juste update peerDependencies to accept webpack@^2.2.0-beta ?

[help wanted] service-worker file is not server from top level

Hey,

my problem is probably cause of my lack of knowledge of the topic, but I'm struggling with it since yesterday and thought I might ask for a help eventually ;)

I use pretty standard configs, however I cannot force webpack to serve generated service worker at top level of my app during development. In normal case I would just add new entry to the webpack configuration, but here I have no entry point for a service-worker file as it is generated from the scratch by a plugin. Is there any option to allow that now?

my webpack.config.js (important parts)

const SWPrechaceConfig = require('./sw-precache-config')
const config = {
    context: __dirname,
    entry: {
        app: ['./src/app/index'],
    },
    output: {
        path: path.resolve(__dirname, './dist'),
        filename: '[name].js',
    },
    resolve: {
        extensions: ['', '.es6', '.js', '.json'],
    },
    module: {
        preLoaders: [
            {test: /\.jsx?$/, loader: 'eslint', exclude: /node_modules/},
        ],
        loaders: [
            {test: /\.jsx?$/, loaders: ['react-hot', 'babel'], exclude: /node_modules/},
            {test: /\.html$/, loader: 'raw'},
            {test: /\.css$/, loader: 'css'},
            {test: /\.styl$/, loader: 'style!css!postcss!stylus'},
            {test: /\.json$/, loader: 'json'},
            {test: /\.svg$/, loader: 'babel!svg-react'},
        ],
    },
    plugins: [new SWPrecacheWebpackPlugin(SWPrechaceConfig)],
}

and my SWPrechaceConfig:

module.exports = {
    cacheId: "local_app",
    maximumFileSizeToCacheInBytes: 4194304,
    runtimeCaching: [{
        handler: "cacheFirst",
        urlPattern: /[.]mp3$/,
    }],
    staticFileGlobs: [
        "dist/app.js"
    ],
    stripPrefix: "dist/",
    verbose: true,
}

POST not work?

I use webpack to build.

    new SWPrecacheWebpackPlugin({
      cacheId: 'v3',
      filename: 'sw.js',
      maximumFileSizeToCacheInBytes: 4194304,
      minify: true,
      staticFileGlobs: [
        'dist/**.html',
        'dist/static/**.*',
        'dist/static/fonts/**.*',
        'dist/static/css/**.css',
        'dist/static/img/**.*',
        'dist/static/js/**.js'
      ],
      staticFileGlobsIgnorePatterns: [/\.map$/],
      stripPrefix: 'dist',
      mergeStaticsConfig: true,
      runtimeCaching: [{
        handler: 'networkFirst',
        urlPattern: /^(https:\/\/)[^\s]+\/detail\/\w*-\w*-\w*-\w*-\w*/,
        method: 'post',
      }],
    })

The urlPattern that match has CORS.

I saw the generated sw.js. It looks fine in the finall:

toolbox.router.post(/^(https:\/\/)[^\s]+\/detail\/\w*-\w*-\w*-\w*-\w*/,toolbox.networkFirst,{});

but It looks like the fetch only works with GET method:

self.addEventListener('fetch', function(event) {
  if (event.request.method === 'GET') {
      ......

Did I missing something?

Non root-relative URLs

My app is currently hosted in a subfolder of the domain and spent some time debugging why all the urls being fetched by sw-precache were root-relative (ie. /app.js) instead of relative (ie. app.js). I don't believe there is an issue but I'm posting this in case it helps anyone else. Feel free to close.

The root of the issue is that sw-precache-webpack-plugin will use the webpack output path as the stripPrefix param to sw-precache. My webpack config looked something like this

{
  output: {
    filename: 'app.js',
    path: path.resolve(__dirname, 'dist', env)
  },
  plugins: [
    new SWPrecacheWebpackPlugin({
      cacheId: require('./package.json').name
    })
  ]
}

The fix is to set stripPrefix to replace the output path and the leading '/' manually

{
  output: {
    filename: 'app.js',
    path: path.resolve(__dirname, 'dist', env)
  },
  plugins: [
    new SWPrecacheWebpackPlugin({
      cacheId: require('./package.json').name,
      stripPrefix: path.resolve(__dirname, 'dist', env) + '/',
      replacePrefix: ''
    })
  ]
}

Provide option to auto generate register bundle script

When a user opts in, emit a bundle with a registration script.

API:

  ...
  output: {
    path: path.resolve(__dirname, 'dist/'),
    filename: '[name]-[hash].js',
    publicPath: 'http://localhost:3000/',
  },
  plugins: [
    new SWPrecacheWebpackPlugin(
      {
        cacheId: 'my-project-name',
        filename: 'my-service-worker.js'
        register: true,
      }
    ),
  ],
  ...

emits: dist/register-sw-[hash].js

(function() {
  if('serviceWorker' in navigator) {
    navigator.serviceWorker.register('http://localhost:3000/my-service-worker.js');
  }
})();

This has the added benefit of being picked up by webpack template plugins that inject all bundles into an html template (html-webpack-plugin #62)

Please support [chunkhash] for importScripts

Currently only [hash] supported for importScripts. This means, that if you're trying to reference a file that was generated via [chunkhash] - there is no way to use it with importScripts

cache.add() returning Error: DOMException Quota exceeded.

In line 137 of the generated service.worker.js file, the return values from the cache.add calls are returning the error listed in the title: DOMException Quota Exceeded. I did a good amount of research on the error earlier today, but the only thing I could find was that it was somehow linked to localStorage. Any ideas?

Example Cannot GET /

When run the npm run serve, at the 3000 port I see the message "Cannot GET /" in the browser

service worker file generated with index.html code inside

with this code:

new SWPrecacheWebpackPlugin(
  {
    cacheId: 'my-project',
    filename: 'my-project-sw.js',
    filepath: publicDir + '/my-project-sw.js',
    staticFileGlobsIgnorePatterns: [/.*\.html/],
    verbose: true,
    runtimeCaching: [{
      urlPattern: /\/assets\//,
      handler: 'cacheFirst'
    }]
  }
)

In the webpack config, and this in my express server:

app.use((request, response) => {
  if(request.url === '/my-project-sw.js') response.sendFile(path.join( publicDir, 'my-project-sw.js'));
  response.sendFile(path.join( publicDir, 'index.html'));
});

I get the generated file containing the sw-precache code, the sw-toolbox code and the source code of my index.html file..

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.