How to add tailwindcss to KotlinJS

I am unable to add the tailwindcss library to my KotlinJS project. I tried multiple things.

I have multiple dependencies defined in my build.gradle.kts

implementation(npm("postcss", "latest"))
implementation(npm("postcss-loader", "latest"))
implementation(npm("tailwindcss", "1.8.10"))

I tried creating a tailwindcss.js in my webpack.config.d with this content

config.module.rules.push({
        test: /\.css$/i,
        use: [
            'style-loader',
            'css-loader',
            {
                loader: 'postcss-loader',
                options: {
                    postcssOptions: {
                        plugins: [
                            [
                                'tailwindcss'
                            ],
                        ],
                    },
                },
            }
        ]
    }
);

But that doesn't do anything. I also tried modifying this with multiple options, but I was never able to get tailwindcss to compile. I also tried disabling and enabling the KotlinJS CSS support in build.gradle.kts

I can't find any info on how to add postcss to KotlinJS project.

Thank you for any help.

Upvotes: 5

Views: 2366

Answers (4)

Duale Siad
Duale Siad

Reputation: 1

An alternative answer is using the gradle-tailwind Gradle plugin. The plugin utilises pre-built executables published by Tailwind (that bundle PostCSS & Autoprefixer), over Tailwind's npm package.

// build.gradle.kts
plugins {
    id "au.id.wale.tailwind" version "0.2.0"
}

tailwind {
    version = "3.4.1"
    configPath = "src/main/resources"
    // replace with the relevant `tailwind.css` input paths
    input = "src/main/resources/tailwind/tailwind.css"
    output = "src/main/resources/css/example.css"
}

Disclaimer: I am the author of the Gradle plugin.

Upvotes: 0

Koch
Koch

Reputation: 594

The linked I posted is the answer, the whole repository. It is not just a part of it

If you instead want me to copy/paste the whole repository instead here you're

= Kotlin/JS + Tailwind CSS =

 This is a small sample repository to show the idiomatic way of 
 configuring these two systems together.

 == Running it ==

 . Run `./gradlew run`.
 . Open `http://localhost:8080/` in your browser.
 . 🎉 Notice we're using Tailwind CSS classes successfully.

  == How To == 

 Steps taken to make this work:

  === Dependencies ===

  Add the following dependencies to your JS target (`jsMain` dependencies) in your Gradle file:

  [source,kotlin]
  ----
  implementation("org.jetbrains:kotlin-extensions:1.0.1-pre.148-kotlin-1.4.21")
  implementation(npm("postcss", "8.2.6"))
  implementation(npm("postcss-loader", "4.2.0")) // 5.0.0 seems not to work
  implementation(npm("autoprefixer", "10.2.4"))
  implementation(npm("tailwindcss", "2.0.3"))
  ----

  * `kotlin-extensions` is necessary to get the JavaScript                   link:https://github.com/JetBrains/kotlin-wrappers/blob/master/kotlin-extensions/src/main/kotlin/kotlinext/js/CommonJS.kt#L20[`require`] function.
    ** Make sure the version number matches your version of the Kotlin multiplatform plugin at the top of your Gradle file.
    ** Kotlin Multiplatform 1.4.30 gave me `No descriptor found for library` errors. Try 1.4.21.
    ** Find the latest versions link:https://bintray.com/kotlin/kotlin-js-wrappers/kotlin-extensions[here].
    * `postcss` and `autoprefixer` are link:https://tailwindcss.com/docs/installation#install-tailwind-via-        npm[dependencies] as mentioned in the Tailwind CSS docs.
    * `postcss-loader` is required because Kotlin/JS is built on top of Webpack.
    ** Note that while 5.0.0 is out, using it gave me build errors. The latest         4.x seems to work.
    * `tailwindcss` is obviously what we're here for.

    === Add Tailwind as a PostCSS plugin ===

    Just do link:https://tailwindcss.com/docs/installation#add-tailwind-as-a-post-css-plugin[this step].

    If unsure, create this file in your project root:

    [source,javascript]
    ----
    // postcss.config.js
    module.exports = {
      plugins: {
tailwindcss: {},
autoprefixer: {},
      }
    }
    ----

    === Create your configuration file (optional) ===

    link:https://tailwindcss.com/docs/installation#create-your-configuration-file[Official documentation].

    Creating the `tailwind.config.js` file is a little tricky because simply `npx` won't work, as we haven't installed any
    `node_modules`. Fortunately, Kotlin/JS has already done this for us.

    Run the following:

    [source,shell]
    ----
    $ ./gradlew kotlinNpmInstall
    $ ( cd build/js/ && npx tailwindcss init && mv tailwind.config.js         ../../ )
    ----

    This generates `tailwind.config.js` in the `build/js/` directory and then moves it up two directories to the project

root. Kotlin/JS generates the node modules into build/js/node_modules when the kotlinNpmInstall task runs.

    This assumes your JavaScript module is `js`. If it's not, you'll need to change the `cd build/js/` part. If you're not

sure where your node_modules directory is, run find . -maxdepth 3 -name node_modules.

    You should now have all your dependencies set up and config files created.

    === Create and Reference a Regular CSS File ===

    _If you already have a CSS file that you're loading in your app, you can skip this step._

    Create `app.css` in your `jsMain/resources/` directory. Put something obvious in there so you know

when it's loaded:

    [source,css]
    ----
    body {
background-color: red;
    }
    ----

    This file will get copied into the same folder as your transpiled JavaScript files.

    In your JavaScript file (`client.kt` in this package), add:

    [source,javascript]
    ----
    kotlinext.js.require("./app.css")
    ----

to your main method. You can of course import the require method if you prefer.

    If you run `./gradlew run`, you should be able to see a red page at `http://localhost:8080/`.

    We're almost there, but we have two more steps: tell Webpack to use PostCSS and to finally inject Tailwind CSS.

    === Using PostCSS with Webpack ===

    We want to "monkeypatch" the Webpack configuration that Kotlin/JS generates for us. This hook is

documented in the link:https://kotlinlang.org/docs/js-project-setup.html#webpack-bundling[webpack bundling] section. Basically, if we create .js files in webpack.config.d/, they'll be automatically merged into build/js/packages/projectName/webpack.config.js, which exists after a build and you can go inspect.

    The "problem", if you have `cssSupport.enabled = true` in your Gradle file (which you should!), is that this line

generates a webpack rule matching /\.css$/. We can't simply create another rule matching the same files...that won't work.

    So, we need to find the original rule and modify it. Create the following file relative to your project root:

    [source,javascript]
    ----
    // in webpack.config.d/postcss-loader.config.js

    (() => {
        const cssRule = config.module.rules.find(r => "test.css".match(r.test));
if (!cssRule) {
    throw new Error("Could not resolve webpack rule matching .css      files.");
     }
     cssRule.use.push({
    loader: "postcss-loader",
    options: {}
     });
 })();
 ----

 We use an IIFE so that our new variable doesn't potentially interfere with other unseen variables.

 Now PostCSS is working!

 With PostCSS configured and the `tailwindcss` npm module in our dependencies, all that's left now

is to use it.

 === Importing Tailwind CSS ===

 We're basically smooth sailing from here. Follow the link:https://tailwindcss.com/docs/installation#include-tailwind-in-your-css[Include Tailwind in your CSS] directions.

 Just stick the following in your `app.css`:

 [source,css]
 ----
 @tailwind base;
 @tailwind components;
 @tailwind utilities;
 ----

 If you start the server again, it should **Just Work**! It's a bit hard to tell, but if you check the devtools,
 you should see the tw classes loading and massive js.js file being loaded (9.20mb!) which contains all of Tailwind CSS.

 == Areas for Improvement ==

 === Modifications to app.css ===

 Changes made to app.css don't get picked up unless you do a full `./gradlew clean` first, which is painful.

 Adding the following line to build.gradle.kts seems to fix this:

 [source,kotlin]
 ----
 tasks.withType(KotlinWebpack::class.java).forEach { t ->
t.inputs.files(fileTree("src/jsMain/resources"))
 }
 ----

 === Getting --continuous working ===

 Even with the above fix, --continuous doesn't seem to work. 🤷

 == Future Topics ==

 * link:https://tailwindcss.com/docs/installation#building-for-production[Building for Production]

Upvotes: 0

CLOVIS
CLOVIS

Reputation: 998

The accepted answer seems to not work anymore. Also, using the Node Gradle plugin is sub-optimal (KotlinJS already maintains its own package.json and yarn installation).

I managed to get Tailwind to work with KotlinJS thanks for this repository (GitHub) with a few small updates that you can find here (GitLab).

Upvotes: 2

tbl
tbl

Reputation: 41

A basic integration can be achieved with the node-gradle plugin.

In your build.gradle.kts:

plugins {
   id("com.github.node-gradle.node") version "3.0.0-rc2"
}

Also in build.gradle.kts define a task called "tailwindcss" that calls the tailwind CLI via npx. For example:

val tailwindCss = tasks.register<com.github.gradle.node.npm.task.NpxTask>("tailwindcss") {

  // Output CSS location
  val generatedFile = "build/resources/main/static/css/tailwind-generated.css"

  // Location of the tailwind config file
  val tailwindConfig = "css/tailwind.css"

  command.set("tailwind")
  args.set(listOf("build", tailwindConfig, "-o", generatedFile))

  dependsOn(tasks.npmInstall)

  // The location of the source files which Tailwind scans when running ```purgecss```
  inputs.dir("src/main/kotlin/path/to/your/presentation/files")

  inputs.file(tailwindConfig)
  outputs.file(generatedFile)
}

Finally, in build.gradle.kts bind the task to your processResources step, so that it runs automatically. Note you may want to refine this later, because running tailwind every time the processResources step is invoked will slow down your dev cycle.

tasks.processResources {
  dependsOn(tailwindCss)
}

Now we need a minimal package.json in the root of your project. For example:

{
  "name": "MyProject",
  "devDependencies": {
    "tailwindcss": "^1.7.0"
  }
}

Finally, we configure our tailwind config in the location defined by our NpxTask, in the example ```css/tailwind.css"

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

So now after the processResource step is run, gradle will invoke the Tailwind npx task, consume your source and write the CSS to the location you specified.

Upvotes: 2

Related Questions