I'm back in Laravel development after being out of practice since 2019ish. I'm more accustomed to Mix than to Vite but I like the @vite helpers in Blade. For this app I have to provide a Firebase service worker in the root public directory, accessible at https://example.com/firebase-messaging-sw.js. This is what my vite.config.js looks like:
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
export default defineConfig({
plugins: [
laravel({
valetTls: 'whatever.test',
input: [
'resources/css/app.css',
'resources/js/app.js',
'resources/js/firebase-messaging-sw.js'
],
refresh: true,
})
]
});
The problem is that firebase-messaging-sw.js uses import statements to grab Firebase functions from node_modules, which also end up in the compiled public-facing file as minified gibberish. Since a service worker isn't referenced as a module, "import" statements fail. ALL I want is for that file to be compiled into one single JavaScript file with no imports in the final product. This is trivially easy with Mix:
const mix = require('laravel-mix');
mix.js('./build/firebase-messaging-sw.js', './public/firebase-messaging-sw.js');
But I'm already in too deep to switch to Mix at this point. What can I do to my configuration to make Vite output a single clean file, preferably without a hashed filename? I see this, but it assumes a much deeper knowledge of Rollup than I have, and I'm honestly not sure where the lines between Laravel/Vite/Rollup are drawn in this case. This seems like a very simple question but I can't find a recent answer.
Per this answer, I tried changing my vite.config.js to this:
export default defineConfig({
build: {
rollupOptions: {
output: {
manualChunks: {}
},
}
},
plugins: [
laravel({
valetTls: 'whatever.test',
input: [
'resources/css/app.css',
'resources/js/app.js',
'resources/js/firebase-messaging-sw.js'
],
refresh: true,
})
],
});
But this had no effect on Vite's output.
We can turn off chunking by dynamic imports with 'output.inlineDynamicImports: true`. The problem we have several inputs that doesn't support this options...
I didn't find any better solution than building the inputs separately:
pass input file as an argument to vite-cli after --
(Vite doesn't support custom arguments)
dynamically change your Vite config to process only 1 input file at a time with inlineDynamicImports
set emptyOutDir: false
so a build wouldn't delete files built with another build.
The OP went with several config files which is a valid option too.
How this can be done:
How to build multiple bundles using Vite similar to Multi Compiler mode(multi config) in Webpack
import { defineConfig } from 'vite';
const input = process.argv[4]?.split('=')?.[1];
if (input) {
console.log('SINGLE INPUT PROVIDED: ' + input);
}
export default defineConfig(() => {
return {
build: {
emptyOutDir: false,
rollupOptions: {
input: input || ['main.js', 'test.js'],
output: {
[input ? 'inlineDynamicImports' : 'dummy']: true,
entryFileNames: input || ['main.js', 'test.js']
}
},
},
};
});
My output:
printf "test.js main.js" | xargs -d ' ' -P0 -I% npx vite build -- --input=%
SINGLE INPUT PROVIDED: main.js
SINGLE INPUT PROVIDED: test.js
vite v4.3.9 building for production...
vite v4.3.9 building for production...
✓ 5 modules transformed.
✓ 3 modules transformed.
dist/test.js 0.95 kB │ gzip: 0.59 kB
dist/assets/javascript-8dac5379.svg 1.00 kB │ gzip: 0.60 kB
dist/assets/vite-4a748afd.svg 1.50 kB │ gzip: 0.77 kB
dist/assets/main-48a8825f.css 1.24 kB │ gzip: 0.65 kB
dist/main.js 0.75 kB │ gzip: 0.43 kB
✓ built in 67ms
✓ built in 68ms