npm list --depth=0)node -v): v8.11.3npm -v): 6.1.0This issue was also mentioned in Workbox repository:
https://github.com/GoogleChrome/workbox/issues/1534
Up until v1.7.2, Laravel-Mix was outputting the js/app.js and css/app.css with a forward slash like:
/js/app.js
/css/app.css
When upgraded to v2.1.11, I noticed a double slash in the path:
//js/app.js
//css/app.css
This ends up resulting these two files to be loaded from http://js/app.js and http://css/app.css which results a 404 error.
However, this works fine for anyone running out-of-the box installation of Laravel. But when the application starts growing and you want to integrate a service worker plugin (i.e. Workbox), then the real monster comes to play (see the Steps To Reproduce section below).
This is only because Laravel-Mix isn't honoring the public path in the first place. Regardless of v1.7.2 or v2.1.11, it shouldn't set the path to "/" after compiling the scripts and sass files. It should rather set the paths relative, such as: "js/app.js" and "css/app.css" instead of "/js/app.js" and "/css/app.css".
I noticed the fonts and images aren't using this leading "/" while outputting them in the public directory. Only the js and css files are including it.
To understand what's being generated from the Workbox plugin, take a look at my precache manifest file generated by the workbox plugin (refer to the Steps To Reproduce section below) while using Laravel Mix v1.7.2:
self.__precacheManifest = [
{
"revision": "c1deb96084cecef66f0e1f41e7fe1c96",
"url": "apple-touch-icon.png"
},
{
"revision": "44f2b77fa6a419081a6271801e5fda28",
"url": "img/svg/magnifier.svg"
},
{
"revision": "01232e8fd32ab1e8997e",
"url": "/js/vendor.js"
},
{
"revision": "b72a3712fdabc4d2cc6b138e00ae1e96",
"url": "img/logo-dark.png"
},
{
"revision": "598b07f2fce824854ebe0bba82b2b397",
"url": "img/logo-light-small.png"
},
{
"revision": "e8c13486745f6a1c3fd3cc7788eaace2",
"url": "img/logo-light.png"
},
{
"revision": "0d22b57cc0113eaf5fff48fe2339e738",
"url": "fonts/icomoon.eot"
},
{
"revision": "ac7e3b54ed37c5dc26bfdbd2ff9a2e83",
"url": "fonts/icomoon.ttf"
},
{
"revision": "a09c96d925ad889a9fe2169fa977300d",
"url": "fonts/icomoon.woff"
},
{
"revision": "06dbce2d2e8fc4cafa42319937955521",
"url": "fonts/icomoon.svg"
},
{
"revision": "3590030f106aae5b66d36fcbd03b2bf0",
"url": "favicon-16x16.png"
},
{
"revision": "c2d8bfb9b66a4bb17a1e71757b5ee13a",
"url": "favicon-32x32.png"
},
{
"revision": "7ca2abdc7b1ec65f45104eea49e92b63",
"url": "favicon.ico"
},
{
"revision": "38d143e25f32fb48f698",
"url": "/js/manifest.js"
},
{
"revision": "7a9765e1523cee9eed8f",
"url": "/js/app.js"
},
{
"revision": "7a9765e1523cee9eed8f",
"url": "/css/vendor.css"
},
{
"revision": "7a9765e1523cee9eed8f",
"url": "/css/app.css"
}
];
This worked for me until the forward slashes doubled in Laravel Mix v2.1.11 only for js and css files:
[
...
{
"revision": "7a9765e1523cee9eed8f",
"url": "//js/app.js"
},
{
"revision": "7a9765e1523cee9eed8f",
"url": "//css/vendor.css"
},
{
"revision": "7a9765e1523cee9eed8f",
"url": "//css/app.css"
}
...
]
If Laravel Mix returns the JS and CSS file paths without any leading slash, that will solve this issue. I hope @JeffreyWay will look into this.
Install the workbox-webpack-plugin and then update the webpack.mix.js file to use it for generating the service worker file:
const WorkboxPlugin = require('workbox-webpack-plugin')
...
mix.js(...)
.sass(...)
.webpackConfig({
...
plugins: [
...
// Generate service worker
new WorkboxPlugin.GenerateSW({
swDest: 'service-worker.js',
clientsClaim: true,
skipWaiting: true
})
]
})
I'm having the same problem in laravel mix 2.1.
This is problematic if you want to insert script tags into a html using html webpack plugin.
Css files don't seem to have that same problem.
I tried laravel mix 2.0 and the issue is not present in that version.
Can someone help?
my webpack.mix.js code:
const mix = require('laravel-mix');
const HtmlWebpackPlugin = require('html-webpack-plugin');
mix.setPublicPath('dist');
mix.webpackConfig({
plugins: [
new HtmlWebpackPlugin({
template: 'public/index.html',
filename: 'index.html',
}),
],
});
mix.sass('./src/test.scss', '.css/main.css'); // generates '/css.main.css' in stylesheet link in index.html
mix.js('./src/main.js', 'js/main.js') // generates '//js/main.js' in script tags in index.html. why?
.extract([
'vue',
'vue-router',
'vuex',
]);
if (mix.inProduction()) {
mix.version();
} else {
mix.sourceMaps();
}
output in terminal: (the js file uri's should not start with a '/')
images/logo.png?250511dbe7e64107809d0e6d980ff135 5.19 kB [emitted]
/js/main.js 104 kB 0 [emitted] /js/main
/js/vendor.js 1.08 MB 1 [emitted] [big] /js/vendor
/js/manifest.js 3.84 kB 2 [emitted] /js/manifest
css/main.css 78 bytes 0, 0 [emitted] /js/main, /js/main
index.html
EDIT:
my remark on terminal output is not correct. version 2.0 als show /js/main.js and that works (it does not use double slashes in plugins as in v2.1)
Having the same issue with laravel mix 2.1.14.
I am trying to inject my script via the html-webpack-plugin, but i end up with //js/main.js as src, while the path to my css file looks just fine.
I did try to manipulate the webpack config just to see whats going on and found out that the entry file (which should be js/main.js) already has a leading slash, which shouldn't be there. If I manually change that value on runtime I get the right result.
@JeffreyWay It would be nice to know if the leading slash is intentional. At the moment it just causes problems, at least for me..
I am using a basic mix setup with a self written plugin called 'mix-html-builder' as an additional dependency.
webpack.mix.js
let mix = require('laravel-mix');
require('mix-html-builder');
mix.setPublicPath('out')
.js('src/js/main.js', 'js')
.sass('src/scss/main.scss', 'css')
.buildHtml('src/index.html', 'index.html', 'src/partials');
In out/index.html the injected script tag looks like this:
<script type="text/javascript" src="//js/main.js"></script>
And as I said, the path of my css file looks fine.
I'm having the exact same problem as @philicevic .
Did you guys find a work-around or how did you solve the problem?
As a hacky workaround, I've added the following to my webpack.mix.js
const replace = require( 'replace-in-file' );
const path = require( 'path' );
const publicDir = 'public/html';
...
mix.js( 'resources/js/app.js', 'js' )
...
.then( () => replace.sync( {
// FIXME: Workaround for laravel-mix placeing '//*.js' at the begining of JS filesystem
files: path.normalize( `${publicDir}/precache-manifest.js` ),
from: /\/\//gu,
to: '/',
} ) )
Not too proud of the solution but it works. Hopefully now that @JeffreyWay has finished his site updates, he'll have a bit of time to take a look.
is there any way to apply versions from mix-manifest.json to the files referred from html?
Any update about this issue ?
@tyler36 your workaround doesn't work for me because precache-manifest file name contain a unique hash precache-manifest.79ad89616b48f59453b7ebaa4d7ca623.js
@donmbelembe mine doesn't have a hash.
I'm not that familiar with replace-in-file but it might accept a globs for the filename, then you could do something like
...
files: path.normalize( `${publicDir}/precache-manifest.*.js` ),
...
@JeffreyWay ping
Having same problem. Furthermore, if I include chunk in the file name it also adds it to app.js and vendor.js files and then I can't use those files in index blade on Laravel.
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions.
Hi for anyone still having this issue. I could fix the problem by manually overwriting the publicPath setting like this:
mix.webpackConfig({
output: {
publicPath: "",
},
});
Be sure to apply the right publicPath for your setup!
(tested with workbox 5.0.0-alpha.1)
Same problem here but setting up the publicPath to nothing caused some errors on my chunk files.
Digging into the core of Laravel mix, I found out that there is an unnecessary leading slash in the entry array.
"entry": {
"/main": [
"/Users/lorisleiva/projects/acme/src/main.js"
]
},
This is fixed by chaining another replace call to the createName method of the Entry class in order to remove any leading slash when generating a new entry.
// src/builder/Entry.js
createName(output) {
let name = output
.pathFromPublic(Config.publicPath)
.replace(/\.js$/, "")
.replace(/\\/g, "/")
.replace(/^\//, ""); // <- Adding this line makes it work.
this.base = path.parse(name).dir;
return name;
}
This now outputs:
"entry": {
"main": [
"/Users/lorisleiva/projects/acme/src/main.js"
]
},
I'm happy to make a PR for this but I have no ideas if this is going to break something for non-standalone application.
Edit: In the meantime, you can add this override function to your mix file.
mix.override(config => {
config.entry = Object.keys(config.entry).reduce((acc, key) => {
acc[key.replace(/^\//, "")] = config.entry[key];
return acc;
}, {});
});
@lorisleiva Thanks so much for sharing. I would certainly support a PR or fork. I have the same issue where setting publicPath empty screws up my chunk files. Pretty frustrating.
When I applied your suggestion it solved the problem slash in front of my js file "/js/app.js" but I still have a slash in front of my css file "//css/app.css". Just curious if you had a similar issue with css, and if so can you share how you got around it? Thanks.
Argh sorry to hear that. No I鈥檓 afraid on that particular project I鈥檝e got all my CSS defined within single file components in Vue.js. The code I pasted above should remove the trailing slashes of all the keys in the entry configuration. I鈥檓 not sure where else a trailing slash would be added for CSS. Maybe if you do a mix.dump() you could find it. I hope this helps.
@lorisleiva for me the override function won't work. I use mix 3.0. I'm stuck because I cannot update because of the empty css file bug...
Thanks @lorisleiva your solution is working in my case. Because of this problem I had to add /js by hand to every dynamic import and to the configuration of the vendor and manifest files, now I can just add it to the names in webpackConfig without having the double slashes in the file name:
.webpackConfig({
output: {
filename: 'js/[name].js',
chunkFilename: 'js/[name].js?id=[chunkhash]',
path: path.resolve(__dirname, 'public'),
},
})
As an addition to the discussion, I've seen that the slash appeared also under Chunk Names in the logs, and it disappeared after the fix.
As a solution, I've added webpack.mix.js transform function in my project:
Altho I'd like to see a solution from Symfony/Asset side, I've updated on the Mix side to strip prefix from items.
const collect = require('collect.js');
/**
* Update manifest to remove leading slash of key => value pairs
* @author Elan Ruusam盲e <[email protected]>
* @see https://github.com/symfony/symfony/issues/36234
*/
mix.extend('updateManifestPathsRelative', (config) => {
config.plugins.push(new class {
apply(compiler) {
compiler.plugin('done', () => {
const manifest = {};
collect(Mix.manifest.get()).each((value, key) => {
key = this.normalizePath(key);
value = this.normalizePath(value);
manifest[key] = value;
});
Mix.manifest.manifest = manifest;
Mix.manifest.refresh();
});
}
/**
* @param {string} filePath
*/
normalizePath(filePath) {
if (filePath.startsWith('/')) {
filePath = filePath.substring(1);
}
return filePath;
}
})
});
mix.updateManifestPathsRelative();
refs:
Most helpful comment
Same problem here but setting up the
publicPathto nothing caused some errors on my chunk files.Digging into the core of Laravel mix, I found out that there is an unnecessary leading slash in the
entryarray.This is fixed by chaining another
replacecall to thecreateNamemethod of theEntryclass in order to remove any leading slash when generating a new entry.This now outputs:
I'm happy to make a PR for this but I have no ideas if this is going to break something for non-standalone application.
Edit: In the meantime, you can add this override function to your mix file.