'Bundle JS and CSS into single file with Vite

I'm having a devil of a time figuring out how to build a single .js file from Vite in my Svelte project that includes all of the built javascript and CSS from my Svelte projects. By default, Vite bundles the app into one html file (this is ok), two .js files (why??), and one .css file (just want this bundled into the one js file).

I ran this very basic command to get a starter project:
npx degit sveltejs/template myproject

I tried adding a couple of plugins, but nothing I added achieved the results I wanted. Primarily, the plugins I found seem to want to create a single HTML file with everything in it. It seems like PostCSS might be able to help, but I don't understand what configuration I can set via Vite to get it to do what I want.

What is the magic set of plugins and config that will output a single HTML file with a single js file that renders my Svelte app and its CSS onto the page?



Solution 1:[1]

I created a boilerplate Vite project for this problem:
https://github.com/mvsde/svelte-micro-frontend

Maybe the configuration helps with your case:

import { defineConfig } from 'vite'
import { svelte } from '@sveltejs/vite-plugin-svelte'

export default defineConfig({
  plugins: [
    svelte({
      emitCss: false
    })
  ],

  build: {
    assetsDir: '',
    sourcemap: true,
    lib: {
      entry: 'src/main.js',
      formats: ['iife'],
      name: 'SvelteMicroFrontend',
      fileName: 'svelte-micro-frontend'
    }
  }
})

Solution 2:[2]

I had the same issue and was able to fix by editing vite.config.ts as follows tested on [email protected]

export default {
  build: {
    rollupOptions: {
      output: {
        manualChunks: undefined,
      },
    },
  },
};

Solution 3:[3]

That doesn't come out of the box for vite but you can write a quick plugin which will be doing exactly that

const bundle_filename = ''
const css_filename = 'style.css'

defineConfig({
  build: {
    lib: {
      entry: 'src/mycomponent.js',
      name: 'mycomponent.js',
      fileName: () => 'mycomponent.js',
      formats: ['iife'],
    },
    cssCodeSplit: false,
    rollupOptions: {
      plugins: [
        {
          apply: 'build',
          enforce: 'post',
          name: 'pack-css',
          generateBundle(opts, bundle) {
            const {
              [css_filename]: { source: rawCss },
              [bundle_filename]: component,
            } = bundle

            const IIFEcss = `
            (function() {
              try {
                  var elementStyle = document.createElement('style');
                  elementStyle.innerText = ${JSON.stringify(rawCss)}
                  document.head.appendChild(elementStyle)
              } catch(error) {
                console.error(error, 'unable to concat style inside the bundled file')
              }
            })()`

            component.code += IIFEcss

            // remove from final bundle
            delete bundle[css_filename]
          },
        },
      ],
    },
  },
})

Solution 4:[4]

Two steps,

Final result,

import cssInjectedByJsPlugin from "vite-plugin-css-injected-by-js";

export default defineConfig({
  plugins: [cssInjectedByJsPlugin()],
  build: {
    rollupOptions: {
      output: {
        manualChunks: undefined,
      },
    },
  },
});

Solution 5:[5]

If you are working with Svelte, you can use emitCss:

export default defineConfig({
    plugins: [svelte({
        emitCss: false,
    })],
})

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Fynn Becker
Solution 2 manse
Solution 3
Solution 4 aryzing
Solution 5 Arseniy Sidorov