UNPKG

react-universally

Version:

A starter kit for universal react applications.

143 lines (136 loc) 6.04 kB
import { sync as globSync } from 'glob'; import appRootDir from 'app-root-dir'; import path from 'path'; import HtmlWebpackPlugin from 'html-webpack-plugin'; import OfflinePlugin from 'offline-plugin'; import config from '../../../config'; import ClientConfig from '../../../config/components/ClientConfig'; export default function withServiceWorker(webpackConfig, bundleConfig) { if (!config('serviceWorker.enabled')) { return webpackConfig; } // Offline Page generation. // // We use the HtmlWebpackPlugin to produce an "offline" html page that // can be used by our service worker (see the OfflinePlugin below) in // order support offline rendering of our application. // We will only create the service worker required page if enabled in // config and if we are building the production version of client. webpackConfig.plugins.push( new HtmlWebpackPlugin({ filename: config('serviceWorker.offlinePageFileName'), template: `babel-loader!${path.resolve(__dirname, './offlinePageTemplate.js')}`, production: true, minify: { removeComments: true, collapseWhitespace: true, removeRedundantAttributes: true, useShortDoctype: true, removeNilAttributes: true, removeStyleLinkTypeAttributes: true, keepClosingSlash: true, minifyJS: true, minifyCSS: true, minifyURLs: true, }, inject: true, // We pass our config and client config script compoent as it will // be needed by the offline template. custom: { config, ClientConfig, }, }), ); // We use the offline-plugin to generate the service worker. It also // provides a runtime installation script which gets executed within // the client. // @see https://github.com/NekR/offline-plugin // // This plugin generates a service worker script which as configured below // will precache all our generated client bundle assets as well as our // static "public" folder assets. // // It has also been configured to make use of a HtmlWebpackPlugin // generated "offline" page so that users can still used the application // offline. // // Any time our static files or generated bundle files change the user's // cache will be updated. // // We will only include the service worker if enabled in config. webpackConfig.plugins.push( new OfflinePlugin({ // Setting this value lets the plugin know where our generated client // assets will be served from. // e.g. /client/ publicPath: bundleConfig.webPath, // When using the publicPath we need to disable the "relativePaths" // feature of this plugin. relativePaths: false, // Our offline support will be done via a service worker. // Read more on them here: // http://bit.ly/2f8q7Td ServiceWorker: { // The name of the service worker script that will get generated. output: config('serviceWorker.fileName'), // Enable events so that we can register updates. events: true, // By default the service worker will be ouput and served from the // publicPath setting above in the root config of the OfflinePlugin. // This means that it would be served from /client/sw.js // We do not want this! Service workers have to be served from the // root of our application in order for them to work correctly. // Therefore we override the publicPath here. The sw.js will still // live in at the /build/client/sw.js output location therefore in // our server configuration we need to make sure that any requests // to /sw.js will serve the /build/client/sw.js file. publicPath: `/${config('serviceWorker.fileName')}`, // When the user is offline then this html page will be used at // the base that loads all our cached client scripts. This page // is generated by the HtmlWebpackPlugin above, which takes care // of injecting all of our client scripts into the body. // Please see the HtmlWebpackPlugin configuration above for more // information on this page. navigateFallbackURL: `${bundleConfig.webPath}${config('serviceWorker.offlinePageFileName')}`, }, // According to the Mozilla docs, AppCache is considered deprecated. // @see https://mzl.la/1pOZ5wF // It does however have much wider support compared to the newer // Service Worker specification, so you could consider enabling it // if you needed. AppCache: false, // Which external files should be included with the service worker? externals: // Add the polyfill io script as an external if it is enabled. ( config('polyfillIO.enabled') ? [`https://cdn.polyfill.io/v2/polyfill.min.js?features=${config('polyfillIO.features').join(',')}`] : [] ) // Add any included public folder assets. .concat( config('serviceWorker.includePublicAssets').reduce((acc, cur) => { const publicAssetPathGlob = path.resolve( appRootDir.get(), config('publicAssetsPath'), cur, ); const publicFileWebPaths = acc.concat( // First get all the matching public folder files. globSync(publicAssetPathGlob, { nodir: true }) // Then map them to relative paths against the public folder. // We need to do this as we need the "web" paths for each one. .map(publicFile => path.relative( path.resolve(appRootDir.get(), config('publicAssetsPath')), publicFile, )) // Add the leading "/" indicating the file is being hosted // off the root of the application. .map(relativePath => `/${relativePath}`), ); return publicFileWebPaths; }, []), ), }), ); return webpackConfig; }