From b7928068f6eef5c0c0fda2e5d6c6c389e3607346 Mon Sep 17 00:00:00 2001 From: David Moodie Date: Sat, 17 Mar 2018 03:18:07 +0000 Subject: [PATCH 01/13] Add workbox service worker functionality --- packages/react-scripts/config/paths.js | 3 ++ .../config/webpack.config.prod.js | 36 ++----------- packages/react-scripts/config/workbox.js | 50 +++++++++++++++++++ packages/react-scripts/package.json | 4 +- 4 files changed, 60 insertions(+), 33 deletions(-) create mode 100644 packages/react-scripts/config/workbox.js diff --git a/packages/react-scripts/config/paths.js b/packages/react-scripts/config/paths.js index 8cd5cf439d7..09fad236950 100644 --- a/packages/react-scripts/config/paths.js +++ b/packages/react-scripts/config/paths.js @@ -61,6 +61,7 @@ module.exports = { appNodeModules: resolveApp('node_modules'), publicUrl: getPublicUrl(resolveApp('package.json')), servedPath: getServedPath(resolveApp('package.json')), + craConfig: resolveApp('cra.config.js'), }; let checkForMonorepo = true; @@ -82,6 +83,7 @@ module.exports = { appNodeModules: resolveApp('node_modules'), publicUrl: getPublicUrl(resolveApp('package.json')), servedPath: getServedPath(resolveApp('package.json')), + craConfig: resolveApp('cra.config.js'), // These properties only exist before ejecting: ownPath: resolveOwn('.'), ownNodeModules: resolveOwn('node_modules'), // This is empty on npm 3 @@ -107,6 +109,7 @@ if (useTemplate) { appNodeModules: resolveOwn('node_modules'), publicUrl: getPublicUrl(resolveOwn('package.json')), servedPath: getServedPath(resolveOwn('package.json')), + craConfig: resolveOwn('template/cra.config.js'), // These properties only exist before ejecting: ownPath: resolveOwn('.'), ownNodeModules: resolveOwn('node_modules'), diff --git a/packages/react-scripts/config/webpack.config.prod.js b/packages/react-scripts/config/webpack.config.prod.js index d631fc32a3b..6127536bb44 100644 --- a/packages/react-scripts/config/webpack.config.prod.js +++ b/packages/react-scripts/config/webpack.config.prod.js @@ -16,7 +16,7 @@ const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); const ManifestPlugin = require('webpack-manifest-plugin'); const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); -const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin'); +const workboxPlugin = require('./workbox'); const eslintFormatter = require('react-dev-utils/eslintFormatter'); const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); const paths = require('./paths'); @@ -413,36 +413,7 @@ module.exports = { // having to parse `index.html`. new ManifestPlugin({ fileName: 'asset-manifest.json', - publicPath: publicPath - }), - // Generate a service worker script that will precache, and keep up to date, - // the HTML & assets that are part of the Webpack build. - new SWPrecacheWebpackPlugin({ - // By default, a cache-busting query parameter is appended to requests - // used to populate the caches, to ensure the responses are fresh. - // If a URL is already hashed by Webpack, then there is no concern - // about it being stale, and the cache-busting can be skipped. - dontCacheBustUrlsMatching: /\.\w{8}\./, - filename: 'service-worker.js', - logger(message) { - if (message.indexOf('Total precache size is') === 0) { - // This message occurs for every build and is a bit too noisy. - return; - } - if (message.indexOf('Skipping static resource') === 0) { - // This message obscures real errors so we ignore it. - // https://github.com/facebook/create-react-app/issues/2612 - return; - } - console.log(message); - }, - minify: true, - // Don't precache sourcemaps (they're large) and build asset manifest: - staticFileGlobsIgnorePatterns: [/\.map$/, /asset-manifest\.json$/], - // `navigateFallback` and `navigateFallbackWhitelist` are disabled by default; see - // https://github.com/facebook/create-react-app/blob/master/packages/react-scripts/template/README.md#service-worker-considerations - // navigateFallback: publicUrl + '/index.html', - // navigateFallbackWhitelist: [/^(?!\/__).*/], + publicPath: publicPath, }), // Moment.js is an extremely popular library that bundles large locale files // by default due to how Webpack interprets its code. This is a practical @@ -450,6 +421,9 @@ module.exports = { // https://github.com/jmblog/how-to-optimize-momentjs-with-webpack // You can remove this if you don't use Moment.js: new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), + // Generate a service worker script that will precache, and keep up to date, + // the HTML & assets that are part of the Webpack build. + workboxPlugin, ], // Some libraries import Node modules but don't use them in the browser. // Tell Webpack to provide empty mocks for them so importing them works. diff --git a/packages/react-scripts/config/workbox.js b/packages/react-scripts/config/workbox.js new file mode 100644 index 00000000000..35dcaecc786 --- /dev/null +++ b/packages/react-scripts/config/workbox.js @@ -0,0 +1,50 @@ +// @remove-on-eject-begin +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ +// @remove-on-eject-end +'use strict'; + +const path = require('path'); +const paths = require('./paths'); +const fs = require('fs'); +const { GenerateSW, InjectManifest } = require('workbox-webpack-plugin'); + +const defaultGenerateConfig = { + exclude: [/\.map$/, /^(?:asset-)manifest.*\.js(?:on)?$/], + navigateFallback: '/index.html', + navigateFallbackWhitelist: [/^(?!\/__).*/], // fix for Firebase +}; + +const defaultInjectConfig = { + exclude: defaultGenerateConfig.exclude, + swSrc: path.join(paths.appSrc, 'sw.js'), +}; + +// Default method is generate +let method = 'generate'; +let workboxConfig; + +const craConfigPath = paths.craConfig; +console.log('craConfigPath', craConfigPath); +if (fs.existsSync(craConfigPath)) { + console.log('file exists'); + const craConfig = require(craConfigPath); + console.log('file is', craConfig); + if ('workbox' in craConfig) { + // 'method' should be either 'generate' or 'inject' + method = craConfig.workbox.method || method; + workboxConfig = + method === 'generate' ? defaultGenerateConfig : defaultInjectConfig; + workboxConfig = craConfig.workbox.config || workboxConfig; + } +} + +const plugin = + method === 'generate' + ? new GenerateSW(workboxConfig) + : new InjectManifest(workboxConfig); +module.exports = plugin; diff --git a/packages/react-scripts/package.json b/packages/react-scripts/package.json index 69bc74f2862..04e9ba9ee31 100644 --- a/packages/react-scripts/package.json +++ b/packages/react-scripts/package.json @@ -58,14 +58,14 @@ "react-dev-utils": "^5.0.0", "style-loader": "0.19.1", "svgr": "1.8.1", - "sw-precache-webpack-plugin": "0.11.4", "thread-loader": "1.1.2", "uglifyjs-webpack-plugin": "1.1.6", "url-loader": "0.6.2", "webpack": "3.10.0", "webpack-dev-server": "2.11.0", "webpack-manifest-plugin": "1.3.2", - "whatwg-fetch": "2.0.3" + "whatwg-fetch": "2.0.3", + "workbox-webpack-plugin": "^3.0.0" }, "devDependencies": { "react": "^16.0.0", From 405907943246f17cd21b0df0d210574383e7176a Mon Sep 17 00:00:00 2001 From: David Moodie Date: Sat, 17 Mar 2018 03:40:07 +0000 Subject: [PATCH 02/13] Remove debug --- packages/react-scripts/config/workbox.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/react-scripts/config/workbox.js b/packages/react-scripts/config/workbox.js index 35dcaecc786..35b0594dd61 100644 --- a/packages/react-scripts/config/workbox.js +++ b/packages/react-scripts/config/workbox.js @@ -29,11 +29,8 @@ let method = 'generate'; let workboxConfig; const craConfigPath = paths.craConfig; -console.log('craConfigPath', craConfigPath); if (fs.existsSync(craConfigPath)) { - console.log('file exists'); const craConfig = require(craConfigPath); - console.log('file is', craConfig); if ('workbox' in craConfig) { // 'method' should be either 'generate' or 'inject' method = craConfig.workbox.method || method; From db756382ff0ddcf43fc39f87630df36e1f48f8f6 Mon Sep 17 00:00:00 2001 From: David Moodie Date: Sat, 17 Mar 2018 12:38:18 +0000 Subject: [PATCH 03/13] Set workboxConfig for when there isn't a cra config file --- packages/react-scripts/config/workbox.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-scripts/config/workbox.js b/packages/react-scripts/config/workbox.js index 35b0594dd61..322b5d774df 100644 --- a/packages/react-scripts/config/workbox.js +++ b/packages/react-scripts/config/workbox.js @@ -26,7 +26,7 @@ const defaultInjectConfig = { // Default method is generate let method = 'generate'; -let workboxConfig; +let workboxConfig = defaultGenerateConfig; const craConfigPath = paths.craConfig; if (fs.existsSync(craConfigPath)) { From 7f1725700de75eed0b1bf30a30ce9416d61f75d0 Mon Sep 17 00:00:00 2001 From: David Moodie Date: Tue, 20 Mar 2018 15:46:03 +0000 Subject: [PATCH 04/13] Remove workbox configuration options as c-r-a isn't planning on supporting optional configuration --- packages/react-scripts/config/workbox.js | 33 +++--------------------- 1 file changed, 3 insertions(+), 30 deletions(-) diff --git a/packages/react-scripts/config/workbox.js b/packages/react-scripts/config/workbox.js index 322b5d774df..eecf83315e0 100644 --- a/packages/react-scripts/config/workbox.js +++ b/packages/react-scripts/config/workbox.js @@ -8,40 +8,13 @@ // @remove-on-eject-end 'use strict'; -const path = require('path'); -const paths = require('./paths'); -const fs = require('fs'); -const { GenerateSW, InjectManifest } = require('workbox-webpack-plugin'); +const { GenerateSW } = require('workbox-webpack-plugin'); -const defaultGenerateConfig = { +const workboxConfig = { exclude: [/\.map$/, /^(?:asset-)manifest.*\.js(?:on)?$/], navigateFallback: '/index.html', navigateFallbackWhitelist: [/^(?!\/__).*/], // fix for Firebase }; -const defaultInjectConfig = { - exclude: defaultGenerateConfig.exclude, - swSrc: path.join(paths.appSrc, 'sw.js'), -}; - -// Default method is generate -let method = 'generate'; -let workboxConfig = defaultGenerateConfig; - -const craConfigPath = paths.craConfig; -if (fs.existsSync(craConfigPath)) { - const craConfig = require(craConfigPath); - if ('workbox' in craConfig) { - // 'method' should be either 'generate' or 'inject' - method = craConfig.workbox.method || method; - workboxConfig = - method === 'generate' ? defaultGenerateConfig : defaultInjectConfig; - workboxConfig = craConfig.workbox.config || workboxConfig; - } -} - -const plugin = - method === 'generate' - ? new GenerateSW(workboxConfig) - : new InjectManifest(workboxConfig); +const plugin = new GenerateSW(workboxConfig); module.exports = plugin; From b25b6e047a6ed4d51d6379b91740869ac8b40304 Mon Sep 17 00:00:00 2001 From: David Moodie Date: Tue, 20 Mar 2018 15:47:40 +0000 Subject: [PATCH 05/13] Remove c-r-a config path from paths --- packages/react-scripts/config/paths.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/react-scripts/config/paths.js b/packages/react-scripts/config/paths.js index 09fad236950..8cd5cf439d7 100644 --- a/packages/react-scripts/config/paths.js +++ b/packages/react-scripts/config/paths.js @@ -61,7 +61,6 @@ module.exports = { appNodeModules: resolveApp('node_modules'), publicUrl: getPublicUrl(resolveApp('package.json')), servedPath: getServedPath(resolveApp('package.json')), - craConfig: resolveApp('cra.config.js'), }; let checkForMonorepo = true; @@ -83,7 +82,6 @@ module.exports = { appNodeModules: resolveApp('node_modules'), publicUrl: getPublicUrl(resolveApp('package.json')), servedPath: getServedPath(resolveApp('package.json')), - craConfig: resolveApp('cra.config.js'), // These properties only exist before ejecting: ownPath: resolveOwn('.'), ownNodeModules: resolveOwn('node_modules'), // This is empty on npm 3 @@ -109,7 +107,6 @@ if (useTemplate) { appNodeModules: resolveOwn('node_modules'), publicUrl: getPublicUrl(resolveOwn('package.json')), servedPath: getServedPath(resolveOwn('package.json')), - craConfig: resolveOwn('template/cra.config.js'), // These properties only exist before ejecting: ownPath: resolveOwn('.'), ownNodeModules: resolveOwn('node_modules'), From ee3c1ae9db29a982ccc224df8bc97b85e5de70df Mon Sep 17 00:00:00 2001 From: David Moodie Date: Sat, 17 Mar 2018 03:18:07 +0000 Subject: [PATCH 06/13] Add workbox service worker functionality --- packages/react-scripts/config/paths.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/react-scripts/config/paths.js b/packages/react-scripts/config/paths.js index 8cd5cf439d7..09fad236950 100644 --- a/packages/react-scripts/config/paths.js +++ b/packages/react-scripts/config/paths.js @@ -61,6 +61,7 @@ module.exports = { appNodeModules: resolveApp('node_modules'), publicUrl: getPublicUrl(resolveApp('package.json')), servedPath: getServedPath(resolveApp('package.json')), + craConfig: resolveApp('cra.config.js'), }; let checkForMonorepo = true; @@ -82,6 +83,7 @@ module.exports = { appNodeModules: resolveApp('node_modules'), publicUrl: getPublicUrl(resolveApp('package.json')), servedPath: getServedPath(resolveApp('package.json')), + craConfig: resolveApp('cra.config.js'), // These properties only exist before ejecting: ownPath: resolveOwn('.'), ownNodeModules: resolveOwn('node_modules'), // This is empty on npm 3 @@ -107,6 +109,7 @@ if (useTemplate) { appNodeModules: resolveOwn('node_modules'), publicUrl: getPublicUrl(resolveOwn('package.json')), servedPath: getServedPath(resolveOwn('package.json')), + craConfig: resolveOwn('template/cra.config.js'), // These properties only exist before ejecting: ownPath: resolveOwn('.'), ownNodeModules: resolveOwn('node_modules'), From 9a2024e714906322f29383c5b45c2e0794608e3b Mon Sep 17 00:00:00 2001 From: David Moodie Date: Tue, 20 Mar 2018 15:47:40 +0000 Subject: [PATCH 07/13] Remove c-r-a config path from paths --- packages/react-scripts/config/paths.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/packages/react-scripts/config/paths.js b/packages/react-scripts/config/paths.js index 09fad236950..8cd5cf439d7 100644 --- a/packages/react-scripts/config/paths.js +++ b/packages/react-scripts/config/paths.js @@ -61,7 +61,6 @@ module.exports = { appNodeModules: resolveApp('node_modules'), publicUrl: getPublicUrl(resolveApp('package.json')), servedPath: getServedPath(resolveApp('package.json')), - craConfig: resolveApp('cra.config.js'), }; let checkForMonorepo = true; @@ -83,7 +82,6 @@ module.exports = { appNodeModules: resolveApp('node_modules'), publicUrl: getPublicUrl(resolveApp('package.json')), servedPath: getServedPath(resolveApp('package.json')), - craConfig: resolveApp('cra.config.js'), // These properties only exist before ejecting: ownPath: resolveOwn('.'), ownNodeModules: resolveOwn('node_modules'), // This is empty on npm 3 @@ -109,7 +107,6 @@ if (useTemplate) { appNodeModules: resolveOwn('node_modules'), publicUrl: getPublicUrl(resolveOwn('package.json')), servedPath: getServedPath(resolveOwn('package.json')), - craConfig: resolveOwn('template/cra.config.js'), // These properties only exist before ejecting: ownPath: resolveOwn('.'), ownNodeModules: resolveOwn('node_modules'), From 1a6f48d9bb562cc0e5287bb5177dfb93ab064894 Mon Sep 17 00:00:00 2001 From: David Moodie Date: Tue, 20 Mar 2018 17:01:11 +0000 Subject: [PATCH 08/13] Inline the webpack workbox config --- .../config/webpack.config.prod.js | 8 ++++++-- packages/react-scripts/config/workbox.js | 20 ------------------- 2 files changed, 6 insertions(+), 22 deletions(-) delete mode 100644 packages/react-scripts/config/workbox.js diff --git a/packages/react-scripts/config/webpack.config.prod.js b/packages/react-scripts/config/webpack.config.prod.js index 6127536bb44..3bb0e973c5f 100644 --- a/packages/react-scripts/config/webpack.config.prod.js +++ b/packages/react-scripts/config/webpack.config.prod.js @@ -16,7 +16,7 @@ const UglifyJsPlugin = require('uglifyjs-webpack-plugin'); const ExtractTextPlugin = require('extract-text-webpack-plugin'); const ManifestPlugin = require('webpack-manifest-plugin'); const InterpolateHtmlPlugin = require('react-dev-utils/InterpolateHtmlPlugin'); -const workboxPlugin = require('./workbox'); +const WorkboxWebpackPlugin = require('workbox-webpack-plugin'); const eslintFormatter = require('react-dev-utils/eslintFormatter'); const ModuleScopePlugin = require('react-dev-utils/ModuleScopePlugin'); const paths = require('./paths'); @@ -423,7 +423,11 @@ module.exports = { new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), // Generate a service worker script that will precache, and keep up to date, // the HTML & assets that are part of the Webpack build. - workboxPlugin, + new WorkboxWebpackPlugin.GenerateSW({ + exclude: [/\.map$/, /^(?:asset-)manifest.*\.js(?:on)?$/], + navigateFallback: '/index.html', + navigateFallbackWhitelist: [/^(?!\/__).*/], // fix for Firebase + }), ], // Some libraries import Node modules but don't use them in the browser. // Tell Webpack to provide empty mocks for them so importing them works. diff --git a/packages/react-scripts/config/workbox.js b/packages/react-scripts/config/workbox.js deleted file mode 100644 index eecf83315e0..00000000000 --- a/packages/react-scripts/config/workbox.js +++ /dev/null @@ -1,20 +0,0 @@ -// @remove-on-eject-begin -/** - * Copyright (c) 2015-present, Facebook, Inc. - * - * This source code is licensed under the MIT license found in the - * LICENSE file in the root directory of this source tree. - */ -// @remove-on-eject-end -'use strict'; - -const { GenerateSW } = require('workbox-webpack-plugin'); - -const workboxConfig = { - exclude: [/\.map$/, /^(?:asset-)manifest.*\.js(?:on)?$/], - navigateFallback: '/index.html', - navigateFallbackWhitelist: [/^(?!\/__).*/], // fix for Firebase -}; - -const plugin = new GenerateSW(workboxConfig); -module.exports = plugin; From 9a8785902ca5154f110ad9320abb02d7e61452ae Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Thu, 27 Sep 2018 10:50:50 -0400 Subject: [PATCH 09/13] Use settings reccommended by @jeffposnick https://github.com/facebook/create-react-app/pull/4169/#issuecomment-422963072 --- packages/react-scripts/config/webpack.config.prod.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/react-scripts/config/webpack.config.prod.js b/packages/react-scripts/config/webpack.config.prod.js index 3824ec4c16f..e856c3085f7 100644 --- a/packages/react-scripts/config/webpack.config.prod.js +++ b/packages/react-scripts/config/webpack.config.prod.js @@ -490,9 +490,14 @@ module.exports = { // Generate a service worker script that will precache, and keep up to date, // the HTML & assets that are part of the Webpack build. new WorkboxWebpackPlugin.GenerateSW({ - exclude: [/\.map$/, /^(?:asset-)manifest.*\.js(?:on)?$/], + clientsClaim: true, + exclude: [/\.map$/, /asset-manifest\.json$/], + importWorkboxFrom: 'local', navigateFallback: '/index.html', - navigateFallbackWhitelist: [/^(?!\/__).*/], // fix for Firebase + navigateFallbackBlacklist: [ + new RegExp('^/_'), + new RegExp('/[^/]+.[^/]+$'), + ], }), ], // Some libraries import Node modules but don't use them in the browser. From 3dcec0e6993a837f771d002149b46a2bd6a0f249 Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Thu, 27 Sep 2018 10:53:44 -0400 Subject: [PATCH 10/13] Fallback to public url index.html, not root --- packages/react-scripts/config/webpack.config.prod.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/react-scripts/config/webpack.config.prod.js b/packages/react-scripts/config/webpack.config.prod.js index e856c3085f7..98d87df2451 100644 --- a/packages/react-scripts/config/webpack.config.prod.js +++ b/packages/react-scripts/config/webpack.config.prod.js @@ -493,7 +493,7 @@ module.exports = { clientsClaim: true, exclude: [/\.map$/, /asset-manifest\.json$/], importWorkboxFrom: 'local', - navigateFallback: '/index.html', + navigateFallback: publicUrl + '/index.html', navigateFallbackBlacklist: [ new RegExp('^/_'), new RegExp('/[^/]+.[^/]+$'), From 88f603a2209f81cd6c622e7afbc66dd13771428c Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Thu, 27 Sep 2018 10:56:54 -0400 Subject: [PATCH 11/13] Add one comment --- packages/react-scripts/config/webpack.config.prod.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/react-scripts/config/webpack.config.prod.js b/packages/react-scripts/config/webpack.config.prod.js index 98d87df2451..6e8c8f28f75 100644 --- a/packages/react-scripts/config/webpack.config.prod.js +++ b/packages/react-scripts/config/webpack.config.prod.js @@ -495,6 +495,7 @@ module.exports = { importWorkboxFrom: 'local', navigateFallback: publicUrl + '/index.html', navigateFallbackBlacklist: [ + // Exclude URLs starting with /_, as they're likely an API call new RegExp('^/_'), new RegExp('/[^/]+.[^/]+$'), ], From 285e6634abecba96359522880aa74d4f9e8c14ac Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Thu, 27 Sep 2018 11:26:37 -0400 Subject: [PATCH 12/13] Update comment --- packages/react-scripts/config/webpack.config.prod.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/packages/react-scripts/config/webpack.config.prod.js b/packages/react-scripts/config/webpack.config.prod.js index 6e8c8f28f75..444abe6b9ec 100644 --- a/packages/react-scripts/config/webpack.config.prod.js +++ b/packages/react-scripts/config/webpack.config.prod.js @@ -497,6 +497,8 @@ module.exports = { navigateFallbackBlacklist: [ // Exclude URLs starting with /_, as they're likely an API call new RegExp('^/_'), + // Exclude URLs not ending with a /, as they're likely a resource from + // the public/ directory new RegExp('/[^/]+.[^/]+$'), ], }), From 7f6e7efc02f0e0bfb062ed762bef3594987bf34d Mon Sep 17 00:00:00 2001 From: Joe Haddad Date: Thu, 27 Sep 2018 11:38:46 -0400 Subject: [PATCH 13/13] Correct regex --- packages/react-scripts/config/webpack.config.prod.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/react-scripts/config/webpack.config.prod.js b/packages/react-scripts/config/webpack.config.prod.js index 444abe6b9ec..55692cbf38a 100644 --- a/packages/react-scripts/config/webpack.config.prod.js +++ b/packages/react-scripts/config/webpack.config.prod.js @@ -497,9 +497,9 @@ module.exports = { navigateFallbackBlacklist: [ // Exclude URLs starting with /_, as they're likely an API call new RegExp('^/_'), - // Exclude URLs not ending with a /, as they're likely a resource from - // the public/ directory - new RegExp('/[^/]+.[^/]+$'), + // Exclude URLs containing a dot, as they're likely a resource in + // public/ and not a SPA route + new RegExp('/[^/]+[.][^/]+$'), ], }), ],