Enable local build of TailwindCSS/DaisyUI CSS

Created on 20 February 2025, 16 days ago

Problem/Motivation

Many site owners would like to be in control of the code they deliver. In this respect, some configuration steps are required to add NPM packages, create configuration file, and define the location of the destination CSS.

Steps to reproduce

npm install -D tailwindcss "@tailwindcss/forms" "@tailwindcss/typography" daisyui@beta autoprefixer postcss "@tailwindcss/postcss" postcss-import postcss-nested cssnano

Create two script definitions in the `package.json` file

"scripts": {
    "dev": "NODE_ENV=development postcss ./style/style.pcss.css -o ./dist/style.css -w -m",
    "build": "NODE_ENV=production postcss ./style/style.pcss.css -o ./dist/style.css"
  },

Create a postcss.config.js file

module.exports = (ctx) => ({
  map: ctx.options.map,
  plugins: {
    "postcss-import": {},
    "postcss-nested": {},
    "@tailwindcss/postcss": {},
    autoprefixer: {},
    ...(process.env.NODE_ENV === "production"
      ? { cssnano: { preset: "default" } }
      : {}),
  },
});

- Create a folder /style, if it does not already exist

- Create the style.pcss.css file in the above folder with the following contents

@import "tailwindcss";

@plugin "@tailwindcss/typography";
@plugin "@tailwindcss/forms";
@plugin "daisyui";

- Update ui_suite_daisyui.info.yml
Remove reference to the following libraries

- ui_suite_daisyui/daisyui_cdn
- ui_suite_daisyui/daisyui_themes_cdn
- ui_suite_daisyui/custom_css

Add reference to the following library

- ui_suite_daisyui/daisyui

Update ui_suite_daisyui.libraries.yml
Add definition of the daisyui library

daisyui:
  css:
    theme:
      dist/style.css: { minified: true }

- Create a folder /dist, if it does not already exist

- npm run build - to build a compressed CSS file
- npm run dev - to build a non-compressed CSS file and watch for changes, and rebuild after change

Proposed resolution

Update configuration to cater for own built version CSS for eventual publication to production environments.

Remaining tasks

- Validate concept
- Ensure that the reference to DaisyUI 5 beta in the configuration, is updated as and when DaisyUI 5 is released

User interface changes

None

API changes

- Remove dependency on externally delivered CSS files
- Host code to automatically (re)generate CSS files

- Running npm update will download and make available most recent versions of TailwindCSS and DaisyUI and other libraries
- Running npm run build will rebuild CSS with the most recently installed versions of TailwindCSS and DaisyUI

Data model changes

none

Feature request
Status

Active

Version

5.0

Component

Code

Created by

🇱🇺Luxembourg paddy_deburca

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Merge Requests

Comments & Activities

  • Issue created by @paddy_deburca
  • 🇫🇷France G4MBINI Bègles

    Hello @paddy_deburca ,

    One of the main goal of this theme is to promote display building and no-code mapping between data and design elements. So the main persona here is Site Builder.

    It's important that this type of users who install the theme have directly a good visual experience and already built-in configs. That being said, I will keep the CDN libraries by default (and why not ship a DaisyUI CSS library already built that we can switch with theme settings).

    Other users like developers, are for most them already confortable with build processes (SASS, Tailwind, ...) so I guess they know how to do that, right ?

    IMHO, build process tools shouldn't be shipped inside the theme, but well documented instead, in the README or in the incoming htdocs.

    Do you want to take care of that ?

  • 🇫🇷France G4MBINI Bègles
  • 🇫🇷France G4MBINI Bègles
  • 🇱🇺Luxembourg paddy_deburca

    My proposal is to move this documentation to a starterkit theme. This would allow
    - existing theme to work as-is and un modified
    - create sub-theme from starterkit with documentation and examples on how to configure with own versions of CSS

    There are multiple ways to build the local CSS, and of these I propose to only document two
    - using TailwindCSS CLI to compile the CSS
    - using PostCSS to compile the CSS with some processors

    The file `package.json` is be required with a minimum configuration for TailwinsCSS, daisyUI, and TailwindCSS/CLI.

    Two extra files _could_ also be included
    - `package-postcss-example.json` - containing an example, working, configuration, with PostCSS, TailwindCSS, daisyUI
    - `postcss-example.js` - containing PostCSS configuration

    In both cases, we can include the script definitions to hide the complexity of `npm`/`npx` calls
    - `npm run build` to build and store CSS in `output.css`
    - `npm run dev` to build, and re-build on file updates, and store CSS in `output.css`

    The `README.md` file documents these configuration items, but having a sample file(s) to start with would make process easier.

    If this approach is OK, I will create the sample files, and create a merge request with the entire starterkit folder.

  • First commit to issue fork.
  • Merge request !139Resolve #3508143 "Starterkit followup" → (Closed) created by vasike
  • Merge request !140Resolve #3508143 "Starterkit followup" → (Open) created by vasike
  • 🇷🇴Romania vasike Ramnicu Valcea

    new MR available
    https://git.drupalcode.org/project/ui_suite_daisyui/-/merge_requests/140

    Which updates the previous one:
    - Use the daisyUI logo/icon
    - Delete the extra files that "needed renaming" - not actually needed
    - Fix the Regions and libraries
    - Remove not needed files ... empty or inherited from the base theme.
    - Emptied generated CSS file.
    - Update README file - simplify the process + remove older Drupal info.

    I could generate an working theme just with

    php core/scripts/drupal generate-theme my_daisyui_theme --starterkit ui_suite_daisyui_starterkit --path themes/custom
    npm install
    npm run build or npm run dev

    commands

  • 🇷🇴Romania vasike Ramnicu Valcea
  • 🇩🇪Germany Christian.wiedemann

    Hi all,

    I checked some frameworks like nuxt and next and other themes. But from my point of view there is no best practice. So here are my 5 cents about the folder structure and compile steps.

    • 1. CSS Folder/File structure in the Drupal way. Means 1 result file for each component. Same folder structure.
    • 2. CSS Linting "stylelint/Prettier". We ignore JS stuff.
    • 3. Base Blocks

    1. CSS compile in the Drupal core way.

    So I think we should do it like Drupal Core. Maybe other themes will follow. They use pcss.css as source files and generate the resulting file in the same folder without pcss.css extension. So I would change the src/css folder structure to:

    css/global.pcss.css
    css/global.css > generated. in gitignore etc.
    css/themes.pcss.css
    # Not sure if we need. But I am
    css/base.pcss.css
    css/utitilites.pcss.css
    
    # Components look like:
    components/component/component.pcss.css
    components/component/component.css > generated. in gitignore etc.
    

    So we don't have a dist folder. (Not 100% sure about this. But I think some CSS is in a dist folder and some not is not so clean)

    To generate the CSS I would do something similar core is doing. Following Script is part of core. Maybe we can use it or we copy and adapt it. I think it is easy to adapt to tailwind CLI. It uses a glob to add each CSS to a separate process so there is no need to adopt an config file if a CSS file is added.

    What do you think?

    
    /**
     * @file
     *
     * Provides the build:css command to compile *.pcss.css files to CSS.
     *
     * Run build:css with --file to only parse a specific file. Using the --check
     * flag build:css can be run to check if files are compiled correctly.
     * @example <caption>Only process misc/drupal.pcss.css and misc/drupal.init.pcss.css</caption>
     * yarn run build:css --file misc/drupal.pcss.css --file misc/drupal.init.pcss.css
     * @example <caption>Check if all files have been compiled correctly</caption>
     * yarn run build:css --check
     *
     * @internal This file is part of the core CSS build process and is only
     * designed to be used in that context.
     */
    
    'use strict';
    
    const { globSync } = require('glob');
    const argv = require('minimist')(process.argv.slice(2));
    const changeOrAdded = require('./changeOrAdded');
    const check = require('./check');
    const log = require('./log');
    
    // Match only on .pcss.css files.
    const fileMatch = './**/*.pcss.css';
    // Ignore everything in node_modules
    const globOptions = {
      ignore: './node_modules/**'
    };
    const processFiles = (filePaths) => {
      // Process all the found files.
      let callback = changeOrAdded;
      if (argv.check) {
        callback = check;
      }
      filePaths.forEach(callback);
    };
    
    if (argv.file) {
      processFiles([].concat(argv.file));
    }
    else {
      processFiles(globSync(fileMatch, globOptions).sort());
    }
    process.exitCode = 0;
    

    Style/lint

    We should add some tailwind specific style and linting configs.

    Blocks

    Not realy have a hard opionion about it.

    I think a vite startkit would be also nice. But this is a seperate issue.

  • 🇱🇺Luxembourg paddy_deburca

    I am inclined to agree with using the Drupal way - store custom CSS in *.pcss.css files and compile to an *.css file in the same folder. This changes the output folder, and possibly negates the need for a dist/ folder altogether.

    The code sample provided could be very interesting - at the moment I miss the context in which this code is executed. Is this build process publicly available? Is it possible to see the environment in which it is run, so that I can see if we can cherry pick utilities from the process?

  • 🇱🇺Luxembourg paddy_deburca

    Regarding Stylelint - we *could* include stylelint into the build process.

    By defining lints in a config file

    module.exports = {
      rules: {
        "at-rule-no-unknown": true,
        "block-no-empty": true,
        "color-no-invalid-hex": true,
        "comment-no-empty": true,
        "declaration-block-no-duplicate-properties": [
          true,
          {
            ignore: ["consecutive-duplicates-with-different-values"]
          }
        ],
        "declaration-block-no-shorthand-property-overrides": true,
        "font-family-no-duplicate-names": true,
        "font-family-no-missing-generic-family-keyword": true,
        "function-calc-no-unspaced-operator": true,
        "function-linear-gradient-no-nonstandard-direction": true,
        "keyframe-declaration-no-important": true,
        "media-feature-name-no-unknown": true,
        "no-descending-specificity": true,
        "no-duplicate-at-import-rules": true,
        "no-duplicate-selectors": true,
        "no-empty-source": true,
        "no-extra-semicolons": true,
        "no-invalid-double-slash-comments": true,
        "property-no-unknown": true,
        "selector-pseudo-class-no-unknown": true,
        "selector-pseudo-element-no-unknown": true,
        "selector-type-no-unknown": true,
        "string-no-newline": true,
        "unit-no-unknown": true
      }
    };
    

    we can invoke the stylelint plugin during the build process.

    An invalid CSS such as

    .dummy {
      color: var(--color-black);
      font-size: 12jon;
    }

    would provide an error such as

    ERROR in 
    src/css/components/dummy.css
     3:14 ✖ Unexpected unknown unit “jon” unit-no-unknown

    example source: https://jontorrado.medium.com/working-with-webpack-4-es6-postcss-with-pr...

    So: Yes! we can!! - but, should we?

  • 🇱🇺Luxembourg paddy_deburca

    And finally, my last comment before my next one.

    Using the following configuration syntax in vite we may be able to automatically target all subfolder of the components/ folder.

    import { globSync } from 'glob';
    import path from 'node:path';
    import { fileURLToPath } from 'node:url';
    
    export default {
    	input: Object.fromEntries(
    		globSync('components/**/*.pcss.css').map(file => [
    			'components/'.concat(path.split("/")[1]),
    			fileURLToPath(new URL(file.slice(0, file.length - ".pcss.css".length).concat(".css"), import.meta.url))
    		])
    	),
    	output: {
    		dir: 'components'
    	}
    };

    This would try to process all .pcss.css files found in a components folder into one components CSS file. This concept may or may not work.

    Further reading: https://rollupjs.org/configuration-options/#input and https://vite.dev/config/build-options#build-rollupoptions

  • 🇩🇪Germany Christian.wiedemann

    Hi @paddy_deburca,

    CSS

    The code sample provided could be very interesting - at the moment I miss the context in which this code is executed. Is this build process publicly available? Is it possible to see the environment in which it is run, so that I can see if we can cherry pick utilities from the process?

    The script is part of drupal core. (Or do I missunderstand your question.). You can find it in web/core/scripts/css. It should run during the local or CI build process. So we maybe can reuse the script from web/core/scripts/css or place a script in our scripts/css folder and execute it via package.json.

    Liniting

    I think we should at least provide it. Other frameworks deliver mostly more preconfigured tools. So a good starting point helps.
    I would vote for stylelint and prettier config.

    Vite

    I also vote for a separate starter kit with VITE support. When we finished we create it in a separate branch?

Production build 0.71.5 2024