22

In particular, I'm using Blazor (server hosted) with ASP.NET Core Preview 8. I tried adding it using LibMan, but that seems to be more about downloading files from a CDN. I'd like to introduce Tailwind to my build process.

Is this a case where I should use something like Webpack? If so, how do I make Webpack part of my build process?

Jeremy Caney
  • 6,191
  • 35
  • 44
  • 70
Mitkins
  • 3,475
  • 3
  • 36
  • 72

2 Answers2

45

After reviewing the information in this SO post. Here's a quick rundown of what I ended up implementing. It's not perfect and it needs some work. But it's a good starting point (without making things too complicated).

Created npm Package

I ran npm init in the root of the solution - this created a package.json file. Based on advice I read, this shouldn't be created underneath a project/sub-folder.

Installed/Configured Webpack

Based on the webpack installation guide, I did the following:

npm install webpack webpack-cli --save-dev

In preparation for my Tailwind setup, I also installed the following (see the webpack.config.js file below for more details):

npm install css-loader postcss-loader mini-css-extract-plugin --save-dev
npm install tailwindcss postcss-import

And here's my webpack.config.js file. Note that it's mainly geared towards processing css with Tailwind:

const path = require('path');
const MiniCssExtractPlugin = require("mini-css-extract-plugin");

const bundleFileName = 'holly';
const dirName = 'Holly/wwwroot/dist';

module.exports = (env, argv) => {
    return {
        mode: argv.mode === "production" ? "production" : "development",
        entry: ['./Holly/wwwroot/js/app.js', './Holly/wwwroot/css/styles.css'],
        output: {
            filename: bundleFileName + '.js',
            path: path.resolve(__dirname, dirName)
        },
        module: {
            rules: [{
                test: /\.css$/,
                use: [
                    MiniCssExtractPlugin.loader,
                    'css-loader',
                    'postcss-loader'
                ]
            }]
        },
        plugins: [
            new MiniCssExtractPlugin({
                filename: bundleFileName + '.css'
            })
        ]
    };
};

In the case of css, this will take a single entry point styles.css (which is underneath a sub-folder/project called "Holly") and process it with PostCSS/Tailwind CSS. CSS is broken into separate files, but handled by postcss-import (more on that below). All CSS is compiled into a single file called holly.css.

Managing Multiple CSS Files

I also have a postcss.config.js file in the root of my solution:

module.exports = {
  plugins: [
    require('postcss-import'),
    require('tailwindcss'),
    require('autoprefixer'),
  ]
}

This configures PostCSS for Tailwind, but also includes postcss-import. In the Webpack config styles.css is the entry point for processing:

@import "tailwindcss/base";
@import "./holly-base.css";

@import "tailwindcss/components";
@import "./holly-components.css";

@import "tailwindcss/utilities";

As per the Tailwind documentation postcss-import module pre-processes the @import statements before applying Tailwind CSS.

Making it Work

Once everything was configured, I added the following scripts to the npm package:

  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1",
    "build": "webpack --progress --profile",
    "watch": "webpack --progress --profile --watch",
    "production": "webpack --progress --profile --mode production"
  },

To apply Tailwind to the styles.css file, I ran the following command:

npm run build

It would be nice if I could get Visual Studio to run the above command anytime a file is altered (with a guarantee that it will wait for said compilation when debugging the app) and have Visual Studio show me the errors. But that's another kettle of fish/much more difficult. So I settled on the following workflow.

When I'm debugging on my machine, I run this command in an open terminal:

npm run watch

Whenever a .css file changes, a new holly.css file is generated. Which works fine while the app is running - I just have to refresh the page after I've made a change.

The production server runs inside a Docker container. So I ended up calling npm run production in the Dockerfile:

# Latest .NET Core from https://hub.docker.com/_/microsoft-dotnet-core-sdk/ (not the nightly one)
FROM mcr.microsoft.com/dotnet/core/sdk:3.0.100-preview9-disco AS build-env

# Setup npm!
RUN apt-get -y update && apt-get install npm -y && apt-get clean

WORKDIR /app
COPY . ./

# To run Tailwind via Webpack/Postcss
RUN npm install
RUN npm run production

RUN dotnet restore "./Holly/Holly.csproj"
RUN dotnet publish "./Holly/Holly.csproj" -c Release -o out

As you can see, the build process isn't as simple as hitting the "Start" button in Visual Studio. But the workflow is simple enough for others members of the team to learn. If the above workflow becomes problematic, I'll look at what my options are at that point.

The next thing I'll probably focus on is removing unused Tailwind CSS

If there's anything that doesn't make sense or could be done better, please let me know!

Mitkins
  • 3,475
  • 3
  • 36
  • 72
  • 1
    How this has no upvotes is beyond me. This is probably the simplest answer I've found in about an hour of research. – agrath Sep 21 '19 at 01:42
  • 1
    In full VS, following https://code.visualstudio.com/api/working-with-extensions/bundling-extension you can add the webpack and webpack-dev scripts to the package.json then in vs package manager console you can type npm run webpack-dev to start watching the css files for automatic rebuild on save – agrath Sep 21 '19 at 01:46
  • I realised later that you actually did the same above in your walkthrough just with a different name. The only difference is I ran the watch from the PMC rather than from a standalone command window. Though that blocks the PMC from being used to install nuget packages so you have to stop the watch to do that. – agrath Sep 23 '19 at 04:17
  • @Mitkins Do you have something on Github i can look at. I kinda got lost and don't understand the project structure – GidiBloke Mar 02 '20 at 14:12
13

I recently asked myself the same question. I decided that I didn't like a package.json or the node_modules directory in the project. For these reasons I created a NuGet package with a new build action.

With this build action you can simply give your stylesheet the build action "TailwindCSS" and during the build process the stylesheet will be converted via PostCSS.

For more details you can take a look on its GitHub repo.

BamButz
  • 141
  • 1
  • 4
  • I like this. But what are the prerequisites? I assume node & npm, plus some installed packages? – Alex from Jitbit Jul 17 '20 at 15:51
  • Yes, you are right. It depends on node & npm, the needed packages (tailwindcss, postcss, ..) will be installed by the MSBuild target. – BamButz Jul 19 '20 at 08:43