Library Affected:
[email protected]
Issue:
precache manifest generated by webpack is:
self.__precacheManifest = [
{
"revision": "9321d432420f913d773e",
"url": "//js/app.js"
},
{
"revision": "9321d432420f913d773e",
"url": "//css/app.css"
}
];
Which causes service worker to fetch from http://js/app.js and http://css/app.css. Changing to:
self.__precacheManifest = [
{
"revision": "9321d432420f913d773e",
"url": "/js/app.js"
},
{
"revision": "9321d432420f913d773e",
"url": "/css/app.css"
}
];
Fixes the issues. Am I missing something? Webpack config:
mix.webpackConfig({
plugins:[
new GenerateSW({
cacheId: 'pwa',
templatedUrls: {
"/": "resources/views/spa.blade.php",
"/test": "resources/views/spa.blade.php"
},
clientsClaim: true,
skipWaiting: true,
runtimeCaching: [
{
urlPattern: /^https:\/\/fonts\.googleapis\.com\//,
handler: 'cacheFirst',
options: {
cacheName: 'google-fonts-cache',
expiration: {
maxEntries: 5,
maxAgeSeconds: 600,
},
},
},
],
importScripts: ['./js/importScripts.js']
})
]
});
Also, a new precache-manifest[hash].js file is produced on every compile. Shouldn't it be overwriting the previous one?
I have exactly the same problem. See
https://stackoverflow.com/questions/50760754/workboxs-precache-manifest-file-contains-invalid-url-strings-in-laravel-mix-set
A workaround is to add the option output.publicPath as an empty string to your webpack.mix.js file like this:
mix.webpackConfig({
plugins: <your plugins>,
output: {
publicPath: ''
}
});
However, as soon as you need to specify an actual path here, this workaround fails. So I think this is a bug.
Here is a basic, sample Laravel project to reproduce this issue:
https://github.com/matthiku/laravelAndWorkbox
However, as soon as you need to specify an actual path here, this workaround fails. So I think this is a bug.
I'm not sure about that characterization鈥攚hat you're describing is the expected behavior of output.publicPath.
When there isn't anything that needs to be prepended to the wepback-specific URLs to translate them into public URLs, the value should be ''. That's webpack's default, and I'm not entirely sure why Laravel sets it to a different default.
If you were to set output.publicPath to something else other than '', it would presumably be because you need to use a prefix for all of our URLs corresponding to the public root of your web app. If that were the case, you would want that prefix to be appended to all of the URLs in your precache manifest as well, and that's the behavior you'd end up with.
I am, unfortunately, not familiar with the Laravel community, but I'd suggest reaching out to some of the folks who maintain the project and double-check that defaulting everyone to a publicPath of '/' rather than '' was intentional.
Jeff, thanks for looking into this!
My apologies for saying that this might be a bug. My comment was probably not conclusive. I wish I understood more about Webpack and Workbox in order to better demonstrate this with a simple example.
As I understand it, Laravel Mix (which is totally independent from Laravel!) is just some "syntactical sugar" (or an API) around Webpack. It probably is possible to replicate this without Laravel Mix, but I understand too little about it and perhaps it is indeed an issue with Mix.
But I found another project which exhibits this behaviour when Workbox creates the pre-cache manifest file: https://github.com/cretueusebiu/laravel-vue-spa
Just clone it, add Workbox and a sw.js file and configure it like this:
const {InjectManifest} = require('workbox-webpack-plugin')
mix.webpackConfig({
plugins: [
// new BundleAnalyzerPlugin()
new InjectManifest({
swSrc: './resources/assets/js/sw.js'
}),
],
resolve: {
extensions: ['.js', '.json', '.vue'],
alias: {
'~': path.join(__dirname, './resources/assets/js')
}
},
output: {
chunkFilename: 'js/[name].[chunkhash].js',
publicPath: mix.config.hmr ? '//localhost:8080' : '/'
}
})
Run npm install and npm run production and this will be the resulting pre-cache manifest file:
self.__precacheManifest = [
(...)
{
"url": "/js/12.e6403f2d7c7fc85ff389.js"
},
{
"url": "/js/11.8936dd18126a2ee42aba.js"
},
{
"revision": "ec55c28b2755419a7891",
"url": "//js/app.js"
},
{
"revision": "ec55c28b2755419a7891",
"url": "//css/app.css"
}
];
Note the different URL paths! How can that be?
Based on my understanding of how webpack interprets publicPath, we're using it correctly within the workbox-webpack-plugin.
From the webpack docs:
The value of the option is prefixed to every URL created by the runtime or loaders. Because of this the value of this option ends with
/in most cases.
Laravel Mix shouldn't be setting publicPath to '/' if it's also creating assets whose URLs start with '/'. Since explicitly setting publicPath to '' is enough to resolve the issue for you, and since that's the default that webpack assumes anyway, I think this is something that needs to be addressed by the maintainers of those projects rather than in Workbox.
I know that if we were to stop honoring publicPath it would end up breaking a number of integrations that rely on it.
Settings publicPath to '' works fine as long as I don't have a path after the domain on the first page load.
However if I go to mysite.com/goals/add then it tries to load mysite.com/goals/js/5.7c22a7b9e634b3d4fc89.js
Setting the publicPath to '/' fixes this, but then we're back to Workbox trying to load //js/app.js
To resolve this problem we can use the modifyURLPrefix option to fix the double slash.
.generateSW({
modifyURLPrefix: {
'//': '/',
},
})
In laravel mix, for setup a domin like mysite.com/goals/, I used:
modifyURLPrefix: {
'//': process.env.APP_URL + "/",
},
And it worked.
Most helpful comment
Settings
publicPathto''works fine as long as I don't have a path after the domain on the first page load.However if I go to
mysite.com/goals/addthen it tries to loadmysite.com/goals/js/5.7c22a7b9e634b3d4fc89.jsSetting the
publicPathto'/'fixes this, but then we're back to Workbox trying to load//js/app.jsTo resolve this problem we can use the modifyURLPrefix option to fix the double slash.