webdiscus / pug-loader

Pug loader for Webpack renders pug to HTML or template function
https://webdiscus.github.io/pug-loader/pug-filters
ISC License
72 stars 5 forks source link

How to use it with tailwindcss and server side rendering? #13

Closed Bessonov closed 2 years ago

Bessonov commented 2 years ago

Thanks for great loader!

What would I like to achieve

Following template:

// index.pug
doctype html
html(lang="en")
  head
    link(rel='stylesheet', href='tailwind-generated.css')
  body
    h1.bg-red-500 #{myVar}

and following backend function:

// index.ts
import indexTpl from './index.pug'

function index(): string {
    return indexTpl({
        myVar: 'some value got from elsewhere'
    })
}

should produce html string and generate following file with tailwindcss' jit:

/* tailwind-generated.css */
.bg-red-500 {
    --tw-bg-opacity: 1;
    background-color: rgb(239 68 68 / var(--tw-bg-opacity));
}

What I already got

ATM I get the value myVar into generated html-string, but I fail at generating and including the css file.

Any idea how to achieve that? I can create a small repro, if needed.

webdiscus commented 2 years ago

Hello @Bessonov,

I have no experience with tailwind css. Can you please create a repo with your usage case, including expected result?

webdiscus commented 2 years ago

The pug-loader is designed for Webpack only and can't be used for server side rendering.

Bessonov commented 2 years ago

Thank you very mich for your quick response!

I think I was wrong. Probably, the question isn't related to pug-loader at all. Usually, tailwindcss' jit use html (or jsx/tsx) to extract class names and then generate appropriate css definitions (see working frontend example). Then they are injected through webpack.

Instead, pug-loader creates a callable function from pug files. Because of control structures it's "too late" at this point. Therefore classes should be extracted directly from pug files.

If I don't miss something, this question can be closed.

Anyway, you can find the repro here: https://github.com/Bessonov/pug-loader-tailwindcss-repro With npm start you see the generated result, but I wasn't able to generate tailwind-generated.css file with webpack. Expected output can be generated with npm run simulate-tailwindcss.

Bessonov commented 2 years ago

Well, I got one step further and now I have pug-loader/pug-plugin related question/issue. With this change I get at least generated and expected css output. But it's inlined instead of separate file:

<!DOCTYPE html><html lang="en"><head><link rel="stylesheet" href="{&quot;default&quot;:[[&quot;./src/main.css&quot;,&quot;/*\n! tailwindcss v3.0.23
[...]
.bg-red-500 {\n  --tw-bg-opacity: 1;\n  background-color: rgb(239 68 68 / var(--tw-bg-opacity));\n}\nbody {\n    background-color: aqua;\n}&quot;,&quot;&quot;]]}"></head><body><h1 class="bg-red-500">some value got from elsewhere</h1></body></html>

If I use mini-css-extract-plugin (which I shouldn't), then it creates generated file, but produces empty webpack chunk inside generated index.js and following html output:

<!DOCTYPE html><html lang="en"><head><link rel="stylesheet" href="{}"></head><body><h1 class="bg-red-500">some value got from elsewhere</h1></body></html>

Any idea?

webdiscus commented 2 years ago

Thank you for the feedback. I can reproduce the problem. I try to find a solution.

Bessonov commented 2 years ago

Forgot to mention that the issue isn't related to tailwindcss/postcss-loader. You can remove postcss-loader and @tailwind definitions in main.css.

Bessonov commented 2 years ago

I think I got a solution. I must confirm it and then I will post it here.

Bessonov commented 2 years ago

So, after trying multiple things I got it working :tada:

The change is self explanatory, but in the core I replaced css-loader with webpack 5 asset configuration and add postcss-loader:

            {
                test: /\.pug$/,
                loader: '@webdiscus/pug-loader',
            },
            {
                test: /\.css$/,
                type: 'asset/resource',
                use: 'postcss-loader',
            },

After that I got:

<!DOCTYPE html><html lang="en"><head><link rel="stylesheet" href="/e9ee15a03b9e6daca3ad.css"></head><body><h1 class="bg-red-500">some value got from elsewhere</h1></body></html>
$ ls dist/
e9ee15a03b9e6daca3ad.css  index.js
/* dist/e9ee15a03b9e6daca3ad.css */
/*
! tailwindcss v3.0.23 | MIT License | https://tailwindcss.com
*//*
[...]
.bg-red-500 {
  --tw-bg-opacity: 1;
  background-color: rgb(239 68 68 / var(--tw-bg-opacity));
}
body {
    background-color: aqua;
}

:+1:

webdiscus commented 2 years ago

cool :-)

The pug-plugin can extract css from required styles in pug, but self pug must be defined in entry-point. In your case the css is required from nested require, like require(pug(require(css))), then so deep require(css) is not work.

andrejcesen commented 1 year ago

So, after trying multiple things I got it working 🎉

Great work @Bessonov! Curious to check out your solution, but the link seems to be down. Any chance to resurrect it?

Bessonov commented 1 year ago

@andrejcesen Oh, dear, I have two news for you. A good one and a bad one. The bad one, I have deleted the repo. The good one, I found a copy in my backups and I pushed it again 👍

webdiscus commented 1 year ago

@Bessonov

I see, you have used the pug-plugin v1.5.0. Today actual version of pug-plugin is v4.9.3 and it can much more. For example, using new version the entry point is a Pug file and all source scripts and styles can be loaded directly in Pug via link and script tags:

link(href=require('./style.scss') rel='stylesheet')
script(src=require('./main.ts') defer='defer')

All source resources will be processed via Webpack and generated HTML contains hashed output CSS and JS filenames:

<link href="/assets/css/style.05e4dd86.css" rel="stylesheet">
<script src="/assets/js/main.f4b855d8.js" defer="defer"></script>

Add to Webpack entry a Pug template:

const PugPlugin = require('pug-plugin');
module.exports = {
  entry: {
    // define your Pug files here
    index: './src/views/home/index.pug',  // output dist/index.html
    'route/to/page': './src/views/page/index.pug', // output dist/route/to/page.html
  },
  plugins: [
    new PugPlugin(), // rendering of Pug files defined in Webpack entry
  ],
  module: {
    rules: [
      {
        test: /.pug$/,
        loader: PugPlugin.loader, // Pug loader
      },
      // ... loaders for styles, TS, etc.
    ],
  },
};

You can use a Pug template as any partial in JS (e.g. in your main.ts loaded via script tag In Pug), but this partial should not contains a link or script tags.

webdiscus commented 1 year ago

Here is the working demo repo webpack-tailwind-pug "How to use Tailwind CSS with Pug".