How to use multiple Vite & Tailwind CSS configs in Laravel?

How to use multiple Vite & Tailwind CSS configs in Laravel?

In this article, I will share how you can use multiple Tailwind config, Vite config in your Laravel project.

Web Development

April 30, 2023 11:40 PM

Recently I found myself in a situation where I had hundreds of Vue components and pages for the admin interface & several Laravel Blade pages for the website all inside a single project. Both the admin interface and the website use the Tailwind CSS framework. I wanted my clients to be able to customize the website only.

To make the website customizable, I had to provide the assets that include the website as well as the admin interface. To avoid sharing admin interface-related assets, I decided to have separate asset bundling for the website and admin interface.

The other reason was to separate the build directory of both the admin interface as well as the website.

You could have different reasons for separating asset bundling, but this was the first time I was doing it and thought of sharing it with all of you.

I am using Laravel 10, Vite.js 4.x, Vue.js 3.x & Tailwind CSS 3.x in this project.

Both the admin as well as website assets have different endpoints so I decided to have separate vite.config.js files.

Here is my vite.config.js file.

// vite.config.js

import { defineConfig } from 'vite'
import laravel from 'laravel-vite-plugin'
import vue from '@vitejs/plugin-vue'

export default defineConfig(() => {
    return {
        plugins: [
            laravel({
                input: [
                    'resources/js/app.js',
                    'resources/js/site.js',
                ],
                refresh: true
            }),
            vue({
                template: {
                    transformAssetUrls: {
                        base: null,
                        includeAbsolute: false,
                    },
                },
            }),
        ],
    }
})

Here is my tailwind.config.js file:

// tailwind.config.js

module.exports = {
  darkMode: 'class',
  content: [
    './resources/**/*.blade.php',
    './resources/**/*.js',
    './resources/**/*.vue',
  ],
  theme: {
  },
  plugins: [
    require('@tailwindcss/forms'),
    require('@tailwindcss/typography'),
    require('@tailwindcss/aspect-ratio'),
  ],
}

And here is my postcss.config.js file:

// postcss.config.js

module.exports = {
    plugins: {
      tailwindcss: {},
      autoprefixer: {},
    },
}

Here is my package.json file:

// package.json

{
    "private": true,
    "scripts": {
        "dev": "vite",
        "prod": "vite build"
    }
    // other dependencies
}

I use to run npm run dev or npm run prod to build the assets.

To separate tailwind.config.js file, the first option I had was to define in the app.scss & site.scss file using @config directive as below:

// Solution which I didn't prefer

@config "./tailwind.site.config.js";

@tailwind base;
@tailwind components;
@tailwind utilities;

As I didn't want to move the tailwind.config.js file from the root directory because it has some other imports that would create an issue.

So I explored other options. First thing, I created two separate tailwind config files as below:

// tailwind.app.config.js

module.exports = {
  darkMode: 'class',
  content: [
    './resources/**/*.blade.php',
    './resources/**/*.js',
    './resources/**/*.vue',
  ],
  theme: {
  },
  plugins: [
    require('@tailwindcss/forms'),
    require('@tailwindcss/typography'),
    require('@tailwindcss/aspect-ratio'),
  ],
}
// tailwind.site.config.js

module.exports = {
  darkMode: 'class',
  content: [
    './resources/**/*.blade.php',
  ],
  theme: {
  },
  plugins: [
    require('@tailwindcss/forms'),
    require('@tailwindcss/typography'),
    require('@tailwindcss/aspect-ratio'),
  ],
}

Next, I created two separate vite config files and define tailwind config path in it.

// vite.app.config.js

import { defineConfig } from 'vite'
import laravel from 'laravel-vite-plugin'
import vue from '@vitejs/plugin-vue'

export default defineConfig(() => {
    return {
        plugins: [
            laravel({
                input: [
                    'resources/js/app.js',
                ],
                refresh: true
            }),
            vue({
                template: {
                    transformAssetUrls: {
                        base: null,
                        includeAbsolute: false,
                    },
                },
            }),
        ],
        css: {
            postcss: {
                plugins: [
                    require("tailwindcss")({
                        config: "./tailwind.app.config.js",
                    }),
                    require("autoprefixer"),
                ],
            },
        },
    }
})

I removed the resources/js/site.js from the entry point in the above file. The assets are built in the public/build directory.

Next, the vite.site.config.js file looks like the below:

// vite.site.config.js

import { defineConfig } from 'vite'
import laravel from 'laravel-vite-plugin'

export default defineConfig(() => {
    return {
        plugins: [
            laravel({
                buildDirectory: "site/build",
                input: [
                    'resources/js/site',
                ],
                refresh: true
            }),
        ],
        css: {
            postcss: {
                plugins: [
                    require("tailwindcss")({
                        config: "./tailwind.site.config.js",
                    }),
                    require("autoprefixer"),
                ],
            },
        },
    }
})

Since the website doesn't contain any Vue.js related code, therefore, I removed it and also changed the build directory to public/site/build.

Next, I looked for options where I can provide this config file path when building assets. To do this, I have to explicitly provide the vite config file path during npm commands like npm run dev --config vite.app.config.js.

To avoid passing the vite config file every time, I made some changes in the package.json file as below:

// package.json

{
    "private": true,
    "scripts": {
        "dev-app": "vite --config vite.app.config.js",
        "dev-site": "vite --config vite.site.config.js",
        "dev": "dev-app && dev-site",
        "prod-app": "vite build --config vite.app.config.js",
        "prod-site": "vite build --config vite.site.config.js",
        "prod": "prod-app && prod-site"
    }
    // other dependencies
} 

This way I could run npm run dev-app or npm run dev-site individually during development. I can also run npm run dev to build both the admin interface and website assets at once.

These steps helped me to build separate assets for my script. Now, I can distribute compiled admin assets and fully customizable website blade files to clients.

Newsletter Subscription

Subscribe & get latest updates from ScriptMint

Related Blogs