Lean Flowbite, Tailwindcss, and Webpack Integration in .NET Core Project in 5 steps
Goal: have a complete but lean local compilation of all css and js needed to run on tailwindcss and flowbite, including custom css classes and js customization by extension.
Assume you have a .net core project roughly in the shape of:
YourSolution |- YourProject |- wwwroot |- Areas |- ... |- Views |...
In wwwroot, delete Bootstrap libraries. End up with this:
YourSolution |- YourProject |- wwwroot |- css |- output.css |- js |- bundle.js
YourSolution |- YourProject |- wwwroot |- Areas |- ... |- Views |- src //this one is new! |-input.css //css source |-index.js //js source
YourSolution |- YourProject |- wwwroot |- Areas |- … |- Views - package.json - purgecss.config.js - tailwind.config.js - postcss.config.js - webpack.config.js - gulpfile.js
All dependencies needed. Also requires node.js installation.
{ "name": "yourProject", "version": "1.0.0", "description": "YourProject", "scripts": { "css:build": "npx tailwindcss -i ./src/input.css -o ./wwwroot/css/output.css --verbose", "clean:css": "rimraf ./wwwroot/css/output.css" }, "dependencies": { "@tailwindcss/forms": "^0.5.3", "@tailwindcss/typography": "^0.5.9", "amqplib": "^0.10.3", "create-npm": "^1.3.2", "flowbite": "^1.6.4", "flowbite-datepicker": "^1.2.2", "jquery": "^3.6.4", "next-auth": "^4.20.1", "rimraf": "^3.0.2", "vinyl-sourcemaps-apply": "^0.2.1" }, "devDependencies": { "autoprefixer": "^9.8.8", "eslint": "^8.4.0", "gulp": "^4.0.2", "gulp-purgecss": "^5.0.0", "postcss": "^8.4.21", "postcss-url": "^10.1.3", "purgecss": "^5.0.0", "tailwind": "^4.0.0", "tailwindcss": "^3.2.7", "webpack": "^5.76.1", "webpack-cli": "^5.0.1" }, "main": "tailwind.config.js", "repository": { "type": "git", "url": "git+https://github.com/you/YourProject.git" }, "keywords": [], "author": "", "license": "ISC", "bugs": { "url": "https://github.com/you/YourProject/issues" }, "homepage": "https://github.com/you/YourProject#readme" }
Defines an array that includes all css and js files to be read for css class identification and purging. Not included in the array means not considered. The other config classes inherit this content array.
module.exports = [ ".//*.cshtml", "./src//.{html,js}", "./src/index.js", "./src/input.css", "./Views/**/.cshtml", "./Areas/Admin/**/*.cshtml" ];
Configuring TailwindCSS, extending themes. Settings may vary depending on your tailwindcss, flowbite modules, and other preferences, e.g. fonts.
const colors = require('tailwindcss/colors') const contentArray = require('./purgecss.config'); module.exports = { darkMode: 'class', plugins: [ // ... require('@tailwindcss/forms'), require('@tailwindcss/typography'), require('flowbite/plugin') ], content: contentArray, theme: { extend: { colors: { primary: { "50": "#eff6ff", "100": "#dbeafe", "200": "#bfdbfe", "300": "#93c5fd", "400": "#60a5fa", "500": "#3b82f6", "600": "#2563eb", "700": "#1d4ed8", "800": "#1e40af", "900": "#1e3a8a" } } }, fontFamily: { 'body': [ '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'Helvetica Neue', 'Arial', 'Noto Sans', 'sans-serif', 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji' ], 'sans': [ '-apple-system', 'BlinkMacSystemFont', 'Segoe UI', 'Roboto', 'Helvetica Neue', 'Arial', 'Noto Sans', 'sans-serif', 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji' ], 'serif': [ 'Noto Serif', 'ui-serif', 'Georgia' ] } }, variants: { extend: { brightness: ['dark'], }, }, }
PostCSS, Tailwind, plugin config.
const tailwindConfig = require('./tailwind.config'); module.exports = { plugins: { tailwindcss: {}, autoprefixer: {}, typography: {} }, mode: 'jit', content: tailwindConfig.content };
Bundles all javascript of /src/index.js to one bundle.js file.
const path = require('path'); module.exports = { mode: 'development', entry: './src/index.js', output: { filename: 'bundle.js', path: path.resolve(__dirname, 'wwwroot/js') } };
Purges unnecessary css
const { src, dest } = require('gulp'); const purgecss = require('gulp-purgecss'); const contentArray = require('./purgecss.config'); function purge() { return src('wwwroot/css/output.css') .pipe( purgecss({ content: contentArray, safelist: ['safelist-class-1', 'safelist-class-2'], }) ) .pipe(dest('wwwroot/css')); } exports.purge = purge;
Make sure to import base, components, utilities you need. This all ends up in output.css
@tailwind base; @tailwind components; @tailwind utilities; //example custom class .my-custom-shadow { box-shadow: rgba(50, 50, 93, 0.25) 0px 13px 27px -5px, rgba(0, 0, 0, 0.3) 0px 8px 16px -8px; }
Same principle. Place for flowbite, tailwindcss customization and additional js.
import Flowbite from 'flowbite'; import Datepicker from 'flowbite-datepicker/Datepicker'; //example
In your project file
|- YourProject
after
</PropertyGroup>
add:
<ItemGroup> <UpToDateCheckBuilt Include="./src/input.css" Set="Css" /> <UpToDateCheckBuilt Include="postcss.config.js" Set="Css" /> </ItemGroup> <ItemGroup> <Content Include="gulpfile.js" /> <Content Include="src\index.js" /> <Content Include="src\input.css" /> </ItemGroup> <Target Name="Tailwind" BeforeTargets="Build"> <Exec Command="npm run css:build" /> </Target> <Target Name="PostBuild" AfterTargets="PostBuildEvent"> <Exec Command="webpack" /> </Target> <Target Name="PurgeCSS" AfterTargets="Publish"> <Exec Command="gulp purge" /> </Target> <ItemGroup> <None Include="wwwroot\css\output.css" /> </ItemGroup>
Adjust the Before/After Targets as needed. Note: remove/exclude the target-entries before publishing, as they may cause problems.