Skip to content
This repository was archived by the owner on Mar 6, 2020. It is now read-only.

How to configure Tailwind in a svelte project? #254

Open
gokatz opened this issue May 2, 2019 · 26 comments
Open

How to configure Tailwind in a svelte project? #254

gokatz opened this issue May 2, 2019 · 26 comments

Comments

@gokatz
Copy link

gokatz commented May 2, 2019

I wonder how to configure tailwind in a new svelte project and any project that uses rollup.

@tlgreg
Copy link

tlgreg commented May 2, 2019

You can process <style> tags in two ways with rollup-plugin-svelte.

  1. Use emitCss: true option, this will pass the content of style tags as css files to rollup, so you can use rollup plugins, like rollup-plugin-postcss
  2. Use preprocess: { style } option (preprocessor options (v2)) to use preprocessors' js api directly (postcss js api).

@gokatz
Copy link
Author

gokatz commented May 3, 2019

Thanks for the response, @tlgreg. Will try it out.

@marcograhl
Copy link

Anybody got it to work? Im stuck trying it myself... After the Tailwind 1.0 release Im hyped to try it out with svelte. If anybody got it to work I would appreciate to look at an example.

@tlgreg
Copy link

tlgreg commented May 15, 2019

Example with emitCss: true method: https://github.com/tlgreg/svelte-tailwindcss-example

There is an issue currently which makes using @apply impossible with components in practice. (Compiler throws an error if there is more then one declaration-block with an @apply.) Hopefully, that gets fixed soon.

sveltejs/svelte#1113 (comment)

@marcograhl
Copy link

Thats/Your awesome 🎉🎉🎉🎉🎉
Thank you very much, I got frustrated with this... you helped me a lot. If they manage to fix the problem
with @apply = pure awesomeness

@marcograhl
Copy link

marcograhl commented May 21, 2019

Hey guys,
try this template https://github.com/marcograhl/tailwindcss-svelte-starter,
it all works, Im just not sure how I can set up purgeCss to get the file size down.

@tobias-kuendig
Copy link

What's the performance like of your solution, @marcograhl? I've just added tailwind using svelte-preprocess and now every build takes nearly 20s!

@tlgreg
Copy link

tlgreg commented May 21, 2019

I still couldn't come back to my sapper/svelte side-project to look into this more, unfortunately. Last time I also ran into some issues with sapper too and importing global postcss, but it might have been on my end.

@marcograhl With your setup using svelte-preprocess-postcss does the compiler still throws an error if multiple declaration blocks have an @apply in a component?

But I did try svelte-preprocess too, its auto-preprocess function (default export) will be very slow as it processes template, style and script blocks with multiple preprocessors by default. They do export their individual preprocess functions though, so you can do something like import { postcss } from 'svelte-preprocess' and use on the preprocess option like { preprocess: postcss() }.

@marcograhl
Copy link

marcograhl commented May 21, 2019

@tlgreg Yes u can use mutiple @apply blocks... I did it inside your Button component

@tobias-kuendig , we need a way so the main.css wont get compiled everytime, only when u add something to the tailwind.config.js and in production we need to purge the css...

@tlgreg
Copy link

tlgreg commented May 21, 2019

Yeah, svelte-preprocess-postcss is definitely faster, svelte-preprocess is a more general preprocessor, I believe the slowness comes from that.

Just from a quick look, seems like using svelte-preprocess-postcss or by not using emitCss fixes the @apply issue, though it still shows up as a problem in vscode, but it does builds fine.

ps.: Poor github user apply, he must have a lot of notifications. :)

@tobias-kuendig
Copy link

@tlgreg Do you have a working example you could share?

@marcograhl
Copy link

@marcograhl
Copy link

marcograhl commented May 22, 2019

If somebody can give me a hint, how we can strip the css from the global.css (in the temp. its main.pcss) in the build process - that would be great. And if we can prevent the compiler in the !production to compile the main.css every time (only when we change the tailwindcss config).

@primos63
Copy link

@marcograhl I'm not sure what you are asking with "how we can strip the css from the global.css (in the temp. its main.pcss) in the build process". There's no global.css in your project.

To run purgecss with postcss only in production, add the following to the postcss.config.js

const purgecss = require("@fullhuman/postcss-purgecss");

const production = !process.env.ROLLUP_WATCH;

Then add the following to the end of the plugins array:

 production &&
      purgecss({
        content: ["./**/*.html", "./**/*.svelte"],
        defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || []
      })

For me, the main.css file went from 175K (dev) to 4.8K (prod). I added the navigation and card examples found on the Tailwind site to App.svelte.

@marcograhl
Copy link

@primos63 thats awesome, I tried to implement the postcss-purgecss plugin and messed up somehow. Now it is working like a charm 🎉🎉🎉. Im sry for the confusing global.css... Its the main.css that I wanted to purge => thank you. I will update the template cheers 👍

@lahickey
Copy link

Relating to this, does anyone have a clue how to solve the vscode errors/warnings? I assume it's an issue with the svelte vscode plugin or the language server and have submitted an issue here (jamesbirtles/svelte-vscode#47)

@lahickey
Copy link

lahickey commented Jun 5, 2019

Quick follow-up. You can fix all the warnings by following the steps in this issue: jamesbirtles/svelte-vscode#47

@yaliv
Copy link

yaliv commented Jun 9, 2019

BTW, using Tailwind in a Sapper project is a different story.

I still need svelte-preprocess-postcss to process PostCSS in Svelte <style> blocks as suggested here:
sveltejs/sapper#699 (comment)

Then using rollup-plugin-postcss, I tried to import my main.pcss file from src/client.js, but it failed to recognize the @tailwind directives.
Been stuck here for a while, fortunately I found this example:
https://github.com/tailwindcss/setup-examples/tree/master/examples/sapper
Basically it uses a separate CLI to compile the "global" Tailwind (and PostCSS in general). A bit impractical, but everything works now! 🎉

Just one note:
When including the compiled stylesheet (index.css) in src/template.html, it's better to put it before the custom one (global.css).

@alexdilley
Copy link

alexdilley commented Jun 15, 2019

@yaliv you can work around the slight scripted feel of @adamwathan's solution using svelte-preprocess; see here.

@yaliv
Copy link

yaliv commented Jun 16, 2019

@alexdilley I'm afraid of the slow compilation.
Most of the time, compiling the global CSS doesn't need to be repetitive.
But obviously, this is not the case when we need to live editing the global CSS or Tailwind config.
(I came from Vue.js & still a Vue dev)

EDIT:
I've tried your solution, the compilation time is not bad.
~11s for the first build or when editing the Tailwind config.
~1s for the component level rebuilds.
👍 👍 👍 👍 👍

@joshmanderson
Copy link

joshmanderson commented Aug 3, 2019

An added note regarding an issue I ran into using Sapper + Tailwind + post-css CLI:

To ensure you don't lose tailwind styles used in class directives, you'll need to use a more customised purge-css extractor:

purgecss({
  content: ["./**/*.svelte", "./**/*.html"],
  defaultExtractor: content => {
    const regExp = new RegExp(/[A-Za-z0-9-_:/]+/g);

    const matchedTokens = [];

    let match = regExp.exec(content);

    while (match) {
        if (match[0].startsWith('class:')) {
            matchedTokens.push(match[0].substring(6));
        } else {
            matchedTokens.push(match[0]);
        }

        match = regExp.exec(content);
    }

    return matchedTokens;
  }
})

If your extractor simply returns content.match(/[A-Za-z0-9-_:/]+/g) || [], then you lose any tailwind classes used in a class directive, because the class: is part of the matched token.

Example:
NavItem.svelte

<script>
    export let segment;
    export let path;
    export let text;

    $: selected = path !== '.' ? segment === path : !segment;
</script>

<li class="p-3" class:border-b-2={selected} class:border-teal-100={selected}>
    <a
        class="font-semibold hover:text-teal-100"
        class:text-teal-100={selected}
        class:text-teal-200={!selected}
        rel=prefetch
        href={path}
    >
        {text}
    </a>
</li>

The class:border-b-2 is matched in its entirety, and that doesn't match the border-b-2 tailwind class, so your tailwind css output from post-css will not include that class (unless you've used it elsewhere in a different fashion of course).

It's a pretty sneaky problem, because there are no errors or warnings that you'll run into – elements will just be missing styles here and there, and you may not even notice for some time. Hopefully this might help other people avoid headaches like the one I've just given myself 😂

@darrenmothersele
Copy link

I also had to add this to prevent Svelte generated styles from being removed:

  whitelistPatterns: [/svelte-/],

@alexdilley
Copy link

alexdilley commented Nov 13, 2019

I take a somewhat different approach and purge against the compiled output (.js), rather than the source (.svelte). And only the Tailwind bundle actually needs purging; Svelte's bundle is already as minimal as it should be, assuming you heed any warnings it emits regarding unused styles rules – compilers are good like that :)

Relevant snippets from my setup:

{
  "scripts": {
    "build:tailwind": "postcss src/styles/index.css -o public/global.css",
    "build": "NODE_ENV=production npm run build:tailwind && rollup -c",
    "postbuild": "purgecss -c purgecss.config.js -o public"
  },
  "devDependencies": {
    "cssnano": "^4.1.10",
    "purgecss": "^1.4.1"
  }
}
// rollup.config.js
export default {
  input: 'src/main.js',
  output: {
    name: 'app',
    format: 'esm',
    sourcemap: true,
    dir: 'public',
  },
  plugins: [
    svelte({
      // Extract any component CSS out into a separate file — better for perf.
      css: css => css.write('public/bundle.css'),
      preprocess: sveltePreprocess({ postcss: true }),
    }),
  ],
};
// postcss.config.js
module.exports = {
  plugins: [
    require('tailwindcss'),
    ...(process.env.NODE_ENV === 'production' ? [require('cssnano')] : []),
  ],
};
// purgecss.config.js
module.exports = {
  content: ['public/index.html', 'public/*.js'],
  css: ['public/global.css'],
  defaultExtractor: content => content.match(/[A-Za-z0-9-_:/]+/g) || [],
};

@darrenmothersele
Copy link

Thanks, I'll try out some of those ideas and maybe combine with my own Svelte/Tailwind starter: https://github.com/darrenmothersele/svelte-tailwindcss-starter

@JakubKoralewski
Copy link

JakubKoralewski commented Nov 26, 2019

Guys I have a bit of a nitpicky problem. PurgeCSS is working but it still outputs some things that are not used. I am using pyoner's ts template so there is only a button, but why anyway would so much junk still be left?

Here's the CSS beginning output
html{line-height:1.15;-webkit-text-size-adjust:100%}body{margin:0}main{display:block}h1{font-size:2em;margin:.67em 0}a{background-color:transparent}b,strong{font-weight:bolder}button,input{font-family:inherit;font-size:100%;line-height:1.15;margin:0;overflow:visible}button{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button}[type=button]::-moz-focus-inner,[type=reset]::-moz-focus-inner,[type=submit]::-moz-focus-inner,button::-moz-focus-inner{border-style:none;padding:0}[type=button]:-moz-focusring,[type=reset]:-moz-focusring,[type=submit]:-moz-focusring,button:-moz-focusring{outline:1px dotted ButtonText}legend{color:inherit;display:table;max-width:100%;white-space:normal}[type=checkbox],[type=radio],legend{box-sizing:border-box;padding:0}[type=number]::-webkit-inner-spin-button,[type=number]::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}[type=search]::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}[hidden]{display:none}html{box-sizing:border-box;font-family:sans-serif}*,:after,:before{box-sizing:inherit}h1,p{margin:0}button{background:transparent;padding:0}button:focus{outline:1px dotted;outline:5px auto -webkit-focus-ring-color}html{font-family:-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;line-height:1.5}*,:after,:before{border:0 solid #e2e8f0}input::-webkit-input-placeholder{color:#a0aec0}input::-moz-placeholder{color:#a0aec0}input:-ms-input-placeholder{color:#a0aec0}input::-ms-input-placeholder{color:#a0aec0}input::placeholder{color:#a0aec0}[role=button],button{cursor:pointer}h1{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}button,input{padding:0;line-height:inherit;color:inherit}canvas,object{display:block;vertical-align:middle}

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests