ShadeWork's avatar

Vite: How to exclude static assets from copying/processing?

I'm in the progress of rolling our Laravel as our new application framework in a single domain, multi-application environment. Our main website is WordPress, but various applications live in nested directories of the website root (/). Our applications live in various directories off the root, and I've accomplished this nicely with Laravel by placing the applications above web root and symlinking the public directories to their appropriate directories e.g. /application.

We also have a shared static asset repository at /includes. This is where the problems come in. There are many theme based scss files etc here which get included in application style sheets, via a resolve.alias I set up`, which get built down and minified, all good.

The problem comes with any of those style sheets references a static asset, like an svg icon. Vite can't see the icon, so it doesn't show up when using npm run dev. npm run build outputs an error saying it can't find the file, so leaves the URL intact (which is what we want) so the built css works fine. If I add options to make it so that npm run dev can see the svg files, that works great, but then npm run build copies them all over to the local public/build/assets directory.

We need it to not do this. We're coming from an older gulp/webpack setup and just use it to build and minify our JS and CSS, not touch static assets. Any guidance to make vite work for us?

0 likes
9 replies
LaryAI's avatar
Level 58

To address the issue of excluding static assets from being copied or processed by Vite during the build process, you can configure Vite to handle assets differently. Here's a solution that should help you achieve the desired behavior:

  1. Configure Vite to Ignore Certain Assets:

    You can use Vite's build.rollupOptions to customize how assets are handled. Specifically, you can use the external option to prevent certain files from being processed by Vite. This is useful for assets that are already hosted elsewhere and should not be copied into the build directory.

  2. Use Aliases for Static Assets:

    If you have a shared static asset repository, you can set up an alias in your Vite configuration to point directly to these assets. This way, Vite will resolve the paths correctly without trying to process or copy them.

Here's an example of how you might configure your vite.config.js:

import { defineConfig } from 'vite';

export default defineConfig({
  resolve: {
    alias: {
      // Alias for your shared static assets
      '@assets': '/path/to/your/includes'
    }
  },
  build: {
    rollupOptions: {
      // Specify external assets that should not be processed
      external: [
        // Add patterns or specific files you want to exclude
        '/path/to/your/includes/**/*.svg',
        '/path/to/your/includes/**/*.png',
        // Add more as needed
      ]
    }
  }
});
  1. Ensure CSS References are Correct:

    When referencing assets in your SCSS or CSS files, make sure the paths are correct and align with the aliases you've set up. This ensures that during development (npm run dev), the assets are correctly resolved without being copied during the build process.

  2. Testing:

    After setting up your configuration, test both npm run dev and npm run build to ensure that the assets are correctly referenced during development and that they are not copied into the public/build/assets directory during the build.

By following these steps, you should be able to configure Vite to exclude certain static assets from being copied or processed, while still allowing them to be correctly referenced in your application.

ShadeWork's avatar

So I've spent some time trying to get what the bot suggested working. This is similar to what I tried myself and am still having no luck.

I've set up the resolve.alias and server.fs.allow paths so that the external resources work in npm run dev.

Unfortunately I'm still stuck on the build.rollupOptions.external configuration. No matter what I set it still always seems to import the svg icons from my external directory.

ShadeWork's avatar

If it helps in explaining what I'm doing, here is the file structure I'm using:

~/www
	/apps
		/laravel_app
	/public_html
		/includes
			/css
				/sass
			/icons
				/svg
					icon.svg

with many different icons in the ~/www/public_html/includes/icons/svg/ directory which are referenced in scss files inside ~/www/public_html/includes/css/sass/ directory. These are global theme files and get included in the application's sass, merged and minified down in the application. The problem being the SVG files all get copied over as well.

I've tried using the following based on the bot response, but it doesn't seem to work:

build: {
    rollupOptions: {
        external: [
            '../../public_html/includes/icons/svg/*.svg',
        ]
    }
}
RemiM's avatar

@ShadeWork First, you can add a specific icons alias to your resolve entry:

'@icons': '/includes/icons/svg',

Then, modify your rollupOptions.external to prevent Vite from copying SVGs to public/build folder:

rollupOptions: {
            external: (id) => id.includes('/includes/icons/svg/')
        }

Now, in your SCSS files, use absolute URLs to avoid processing them:

background-image: url("@icons/icon.svg");

This should be converted in the final CSS to:

background-image: url('/includes/icons/svg/icon.svg');
1 like
ShadeWork's avatar

@RemiM thanks for the reply. This is effectively how I have it set up, except I wasn't using the arrow function in external. Changing it to mirror this and... it still seems to copy all of the SVG files over.

Is there perhaps a chance that this isn't working because the references are in scss/css files? Reading the rollup documentation for external makes it sound like it's JS focused. This is our first time dealing with Vite/Rollup coming from an older Gulp/Webpack setup.

ShadeWork's avatar

Ok I seem to have confirmed that the external option is only applying to JS files. In an effort to debug what was going on, I changed the above rollupOptions to:

build: {
   rollupOptions: {
        external: (id) => {
            console.log(id)
            return id.includes('/includes/icons/svg/')
        }
    }
},

And there's no mention of any of the scss/SVG files even being processed by rollup, only js. So configuration for scss/css includes must be somewhere else?

RemiM's avatar

@ShadeWork I forgot that the external was applied only for JS/TS files.

I could not really find an easy way using Vite, so one option here is to use a symlink. I've created a new Laravel project with Inertia and Vue, and for the test, the includes folder is at the same level as the Laravel project.The general layout of the directories is as follows after the symlink creation:

ln -s /Users/{username}/dev/includes/icons/svg /Users/{username}/dev/starter-vue/public/svg

The folder structure looks like this:

includes
    └── icons
        └── svg
            ├── vite.svg
            └── ...
starter-vue
    ├── app
    ├── bootstrap
    ├── config
    ├── database
    ├── ...
    └── public
        └── svg (symlink)
			├── vite.svg
			└── ...

No changes are required in your vite.config.js. With this setup, you can now reference SVG files from the public/svg folder like this:

<img src="/svg/vite.svg" alt="Vite Logo" class="w-16 h-16" />

There is no reference to SVG files in your build folder.

1 like
ShadeWork's avatar

@RemiM Thanks again for replying. Unfortunately this method doesn't address the situation we're running into in that in very specific cases the SVG files are being used as background images via the CSS like so:

background-image: url('/includes/icons/svg/icon.svg');
background-size: cover;

At the very least, I now understand why exclude wasn't working and can work on doing some additional digging when I get time in hopefully a better direction and will update here if I find a solution.

RemiM's avatar

@ShadeWork Well, it should come from your public folder where you setup the symlink, not the shared includes. Taking a look at my previous example on the img tag and applying to your context:

background-image: url('/svg/icon.svg');

Please or to participate in this conversation.