Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combining tailwind css with sass using webpack

I'm struggling a bit getting Tailwind CSS to work with SASS and Webpack. It seems like the postcss configuration for tailwind doesn't really do anything in terms of processing @tailwind preflight, @tailwind components and @tailwind utilities

My set up is as follows:

layout.scss

@import "~tailwindcss/preflight.css";
@import "~tailwindcss/components.css";

.my-class {
    @apply text-blue;    
    @apply border-red;
}

@import "~tailwindcss/utilities.css";

entry.js

import '../css/src/layout.scss';

postcss.config.js

const tailwindcss = require('tailwindcss');
const purgecss = require('@fullhuman/postcss-purgecss');
const cssnano = require('cssnano');
const autoprefixer = require('autoprefixer');

module.exports = {
    plugins: [
        tailwindcss('./tailwind.js'),
        cssnano({
            preset: 'default',
        }),
        purgecss({
            content: ['./views/**/*.cshtml']
        }),
        autoprefixer
    ]
 }

webpack.config.js

// NPM plugins
const autoprefixer = require('autoprefixer');
const WebpackNotifierPlugin = require('webpack-notifier');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');

module.exports = {
    entry: {
        main: './scripts/entry.js'
    },
    output: {
        filename: '[name].bundle.js',
        publicPath: './'
    },
    watch: false,
    externals: {
        jquery: 'jQuery'
    },
    mode: 'development',
    plugins: [
        // Notify when build succeeds
        new WebpackNotifierPlugin({ alwaysNotify: true }),

        // Extract any CSS from any javascript file to process it as LESS/SASS using a loader
        new MiniCssExtractPlugin({
            fileame: "[name].bundle.css"
        }),

        // Minify CSS assets
        new OptimizeCSSAssetsPlugin({}),

        // Use BrowserSync plugin for file changes. I.e. if a CSS/SASS/LESS file changes, the changes will be injected directly in the browser with no page load
        new BrowserSyncPlugin({
            proxy: 'mysite.local',
            open: 'external',
            host: 'mysite.local',
            port: 3000,
            files: ['./dist/main.css', './views', './tailwind.js']
        },
            {
                // disable reload from the webpack plugin since browser-sync will handle CSS injections and JS reloads
                reload: false
            })
    ],
    module: {
        rules: [
            {
                // Transpile ES6 scripts for browser support
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env']
                    }
                }
            },            
            {
                test: /\.(png|jpg|gif|svg|eot|ttf|woff)$/,
                use: [
                    {
                        loader: 'file-loader'
                    }
                ]
            },       
            {
                // Extract any SCSS content and minimize
                test: /\.scss$/,
                use: [                    
                    MiniCssExtractPlugin.loader,
                    { loader: 'css-loader' },
                    {
                        loader: 'postcss-loader',
                        options: {
                            plugins: () => [autoprefixer()]
                        }
                    },
                    {
                        loader: 'sass-loader',
                        options: {                            
                            plugins: () => [autoprefixer()]
                        }
                    } 
                ]
            },
            {
                // Extract any CSS content and minimize
                test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    { loader: 'css-loader', options: { importLoaders: 1 } },
                    { loader: 'postcss-loader' }
                ]
            }            
        ]
    }
};

When I run Webpack, everything runs just fine, but the content of /dist/main.css is:

@tailwind preflight;@tailwind components;@tailwind utilities;.my-class{@apply text-blue;@apply border-red}

I suspect it's related to the (order of) loaders, but I can't seem to figure out why it's not getting processed correctly.

Does anyone know what I'm doing wrong here? :-)

Thanks in advance.

like image 232
Bo Mortensen Avatar asked Apr 10 '19 07:04

Bo Mortensen


People also ask

Can you combine sass and Tailwind?

Since Tailwind is a PostCSS plugin, there's nothing stopping you from using it with Sass, Less, Stylus, or other preprocessors, just like you can with other PostCSS plugins like Autoprefixer.

Is Tailwind better than sass?

Although Tailwind CSS saves us time and makes it easier to makes changes to our markup file, it is difficult to read. This is especially noticeable when there are so many different classes used in the markup file. However, SASS has a feature called bundlers. This helps to split your SASS into files.


1 Answers

Wow, so after fiddling around with the loaders even more, I made it work :-) For future reference:

I added options: { importLoaders: 1 } to the css-loader for SCSS files and removed: plugins: () => [autoprefixer()] from the postcss-loader in my webpack.config.js file.

Full, updated webpack.config.js file:

// NPM plugins
const autoprefixer = require('autoprefixer');
const WebpackNotifierPlugin = require('webpack-notifier');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin");
const BrowserSyncPlugin = require('browser-sync-webpack-plugin');

module.exports = {
    entry: {
        main: './scripts/entry.js'
    },
    output: {
        filename: '[name].bundle.js',
        publicPath: './'
    },
    watch: false,
    externals: {
        jquery: 'jQuery'
    },
    mode: 'development',
    plugins: [
        // Notify when build succeeds
        new WebpackNotifierPlugin({ alwaysNotify: true }),

        // Extract any CSS from any javascript file to process it as LESS/SASS using a loader
        new MiniCssExtractPlugin({
            fileame: "[name].bundle.css"
        }),

        // Minify CSS assets
        new OptimizeCSSAssetsPlugin({}),

        // Use BrowserSync plugin for file changes. I.e. if a CSS/SASS/LESS file changes, the changes will be injected directly in the browser with no page load
        new BrowserSyncPlugin({
            proxy: 'mysite.local',
            open: 'external',
            host: 'mysite.local',
            port: 3000,
            files: ['./dist/main.css', './views', './tailwind.js']
        },
            {
                // disable reload from the webpack plugin since browser-sync will handle CSS injections and JS reloads
                reload: false
            })
    ],
    module: {
        rules: [
            {
                // Transpile ES6 scripts for browser support
                test: /\.js$/,
                exclude: /node_modules/,
                use: {
                    loader: 'babel-loader',
                    options: {
                        presets: ['@babel/preset-env']
                    }
                }
            },            
            {
                test: /\.(png|jpg|gif|svg|eot|ttf|woff)$/,
                use: [
                    {
                        loader: 'file-loader'
                    }
                ]
            },       
            {
                // Extract any SCSS content and minimize
                test: /\.scss$/,
                use: [                       
                    MiniCssExtractPlugin.loader,
                    { loader: 'css-loader', options: { importLoaders: 1 } },                    
                    {
                        loader: 'postcss-loader'                        
                    },                    
                    {
                        loader: 'sass-loader',
                        options: {                            
                            plugins: () => [autoprefixer()]
                        }
                    }                    
                ]
            },
            {
                // Extract any CSS content and minimize
                test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    { loader: 'css-loader', options: { importLoaders: 1 } },
                    { loader: 'postcss-loader' }
                ]
            }            
        ]
    }
};
like image 96
Bo Mortensen Avatar answered Nov 06 '22 22:11

Bo Mortensen