Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Docs]: Help wanted! #475

Closed
cvladan opened this issue Jun 7, 2023 · 16 comments
Closed

[Docs]: Help wanted! #475

cvladan opened this issue Jun 7, 2023 · 16 comments
Labels
🛑 Abandoned The issue or Pull Request will not be worked on 📚 Documentation The documentation is lacking or missing something

Comments

@cvladan
Copy link

cvladan commented Jun 7, 2023

Documentation Is:

Confusing

Link to relevant page or pages

Everywhere

Please Explain in Detail...

Really. There are two sites with documentation, and both have a lot of conflicting information. Moreover, there is a discussion about the performance impact of loading - Notes on Twind runtime performance. And now, how can a person implement it simply?

All that is needed is a simple and straightforward way to render Tailwind CSS locally. What should I download, and how do I run it? It's really confusing. Why philosophize about Twind CDN and the like and skip the most basic vanilla JS application from the local?

  1. The script is on the local machine
  2. I have the complete functionality to select where it will be injected and what will be observed

This works when pulled from online, but I'm pretty sure it's not the most optimal version, and I don't see a way to copy these files locally and have them work.

import * as core from "https://unpkg.com/twind@1.0.0-next.25?module";
import presetTailwind from "https://unpkg.com/@twind/preset-tailwind@1.0.0-next.25?module";
import presetExt from "https://unpkg.com/@twind/preset-ext@1.0.0-next.25?module";

Object.assign(globalThis, core);

const tw = twind(
  {
    preflight: false,
    hash: false,
    presets: [
      presetTailwind({ enablePreflight: false }),
      presetExt()
    ],
    theme: {
      extend: {
        colors: {
          'primary': '#007b90',
          'secondary': '#3B5998',
        },
      },
    },
  },

  cssom()
  // cssom(document.querySelector("#__twind"))
  // dom(document.querySelector("#__twind"))
);

observe(tw, document.querySelector("body"));

Please, someone with more experience tell me. Simply, I want the same thing as above, but to load scripts locally - or one script if possible.

Which script should I download? There are 700 of them in 700 variations.

Maybe I'll give up.
It was supposed to be simple, but it turned out to be 100 times more complicated.

Help wanted!

Your Proposal for Changes

Dunno. Just to run away?

Alternatives considered

No response

@cvladan cvladan added the 📚 Documentation The documentation is lacking or missing something label Jun 7, 2023
@cvladan
Copy link
Author

cvladan commented Jun 7, 2023

The first instruction states to "use the shim," but then later docs states that the shim is even not recommended. However, that same second docs do have explanations for using Shim Mode, Library Mode, Twind instance Mode, and more.

Also, I am unsure if using the shim means I am on an older version?

@cvladan
Copy link
Author

cvladan commented Jun 7, 2023

All is well-documented for use with Gatsby, Lit, Next.js, React, Remix, SvelteKit, and Web Components.

But where is the documentation for vanilla JS?
Simple JavaScript loading from MY site?

@lnfel
Copy link

lnfel commented Aug 7, 2023

Hello there @cvladan, I also experienced the same frustrations at the beginning. Especially when the first docs I read about Twind is their old documentation until I found out there was another doc site for Twind. All latest features and best practices are laid out on that new site.

You can follow usage of either the basic if your site can utilize javascript modules or twind-cdn and use it like tailwind-cdn. I hope this helps. Btw twind also has a library mode that can be used when authoring component packages which I really like.

@mfissehaye
Copy link

Hello there @cvladan, I also experienced the same frustrations at the beginning. Especially when the first docs I read about Twind is their old documentation until I found out there was another doc site for Twind. All latest features and best practices are laid out on that new site.

You can follow usage of either the basic if your site can utilize javascript modules or twind-cdn and use it like tailwind-cdn. I hope this helps. Btw twind also has a library mode that can be used when authoring component packages which I really like.

Can you provide an example of how to use twind in library mode.

@lnfel
Copy link

lnfel commented Sep 27, 2023

There is already a code sample in the docs that I linked, the idea is to create the usual twind config file. Then create another file that will use that twind config and export tw:

// twind.js
import {
  twind,
  virtual,
  cssom,
  tx as tx$,
  injectGlobal as injectGlobal$,
  keyframes as keyframes$,
} from '@twind/core'
// import the twind config
import config from './twind.config'
export const tw = /* #__PURE__ */ twind(
  config,
  typeof document === 'undefined' ? virtual() : cssom('style[data-library]'),
)
export const tx = /* #__PURE__ */ tx$.bind(tw)
export const injectGlobal = /* #__PURE__ */ injectGlobal$.bind(tw)
export const keyframes = /* #__PURE__ */ keyframes$.bind(tw)

Then use it in your components:

<script>
  import { tw } from 'twind.js'
</script>

<h1 class="{tw`text-lg text-blue-500`}">Ahoy!</h1>

This will generate the tailwind styles on runtime so no need to bundle up css during build. Users will also won't have access to the twind instance unless it is explicitly exported in package.json

@cvladan
Copy link
Author

cvladan commented Sep 27, 2023

Is this vanilla JS without build tools?
How to load JS from MY site, not remote CDN?

I need to improve some old HTML site.

@lnfel
Copy link

lnfel commented Sep 28, 2023

Twind CDN should work without any build tools, the steps in the docs are pretty straightforward.

@cvladan
Copy link
Author

cvladan commented Sep 29, 2023

Thanks for the suggestion!

However, I have already written several times, in the issue description and in the previous comment, that I'm actually interested in how to load it from my site, locally, not from CDN. I posted my implementation at the top loading it from unpkg.com, which is both ugly and not very elegant, but I'm shocked that not a single example shows a simple local deployment in vanilla JS.

Twind's CDN is definitely not local.

No need to worry.
It's pointless to go on with this.

Apparently nobody really uses it, and it's going down that "abandoned" road.

@craigerskine
Copy link

To load it locally in your site you need to build all the presets and your config into something like esbuild that will output the compiled and tree-shook Js.

I run Twind from a compiled static Js on ALL my sites. I just use a super simple esbuild script. My script build logic looks like this:

const esbuild = require('esbuild');
await esbuild.build({
  entryPoints: ['_app.js'],
  outfile: 'public/_assets/js/_app.js',
  bundle: true,
  minify: true,
  sourcemap: false,
});

And here's a sample _app.js twind config:

// twind
import { install, injectGlobal } from '@twind/core';
import presetAutoprefix from '@twind/preset-autoprefix';
import presetTailwind from '@twind/preset-tailwind';
import presetLineClamp from '@twind/preset-line-clamp';
install({
  presets: [presetAutoprefix(), presetTailwind(), presetLineClamp()],
  darkMode: 'class',
  hash: false,
  theme: {
    screens: {
      'sm': '640px',
      'md': '768px',
      'lg': '960px',
    },
    extend: {
      colors: ({ theme }) => ({
        brand: theme('colors.rose'),
      }),
      fontFamily: ({ theme }) => ({
        sans: ['Inter', ...theme('fontFamily.sans')],
      }),
    },
  },
  rules: [
    [ 'text-wrap-(unset|wrap|nowrap|balance)', 'textWrap' ],
  ],
});
injectGlobal`
  @layer base {
    hr { @apply border-gray-500/25; }
  }
`

This outputs the static Js and works great ALL my sites:

NOTE: These sites are ALL static HTML. The only build process is 11ty (njk -> html) and esbuild. You can also view the source of all these sites on GitHub from my profile repo list or from footer links on each individual site.


P.S.
You can also use modern browser's module support for a quick and dirty route (I know it uses CDN, but this is the quickest solution):

<!doctype html>
<html lang="en" class="bg-transparent antialiased">

  <head>
    <meta charset="utf-8" />
    <meta http-equiv="x-ua-compatible" content="ie=edge" />
    <title>Twind + CDN + Auto Dark</title>
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1" />
    <link href="https://fonts.gstatic.com" rel="preconnect" />
    <link href="https://fonts.googleapis.com/css2?family=Inter:wght@100..900&display=swap" rel="stylesheet" />

    <script>
      // color mode init
      if (localStorage.getItem('color-mode') === 'dark' || (window.matchMedia('(prefers-color-scheme: dark)').matches && !localStorage.getItem('color-mode'))) {
        document.documentElement.classList.add('dark');
      }
    </script>

  </head>

  <body class="bg-gray-50 text-gray-700 !block" style="display: none;">
    <div id="app" class="min-h-screen flex-(& col)" x-cloak>
      <header class="px-4 flex-none">
        <div class="mx-auto border-(b gray-500/25) py-4 max-w-7xl">
          <nav class="flex-(& col) items-center gap-3 md:(flex-row justify-between)">
            <a href="#" class="text-brand-500"><iconify-icon icon="mdi:google-podcast" inline="false" class="iconify text-4xl"></iconify-icon></a>
            <ul class="flex items-center gap-6">
              <li><a href="#" class="motion-safe:(transition) hover:(text-brand-500)">Nav</a></li>
              <li><a href="#" class="motion-safe:(transition) hover:(text-brand-500)">Nav</a></li>
              <li>
                <button class="color-mode text-xl flex items-center motion-safe:(transition) hover:(text-brand-500)" aria-label="Toggle color mode">
                  <span class="block dark:(hidden)"><iconify-icon icon="mdi:weather-sunny" inline="false" class="iconify"></iconify-icon> <span class="sr-only">Switch to dark mode</span></span>
                  <span class="hidden dark:(block)"><iconify-icon icon="mdi:weather-night" inline="false" class="iconify"></iconify-icon> <span class="sr-only">Switch to light mode</span></span>
                </button>
              </li>
            </ul>
          </nav>
        </div>
      </header>
      <main class="py-8 px-4 flex-1 md:(py-16)">
        <section class="mx-auto max-w-7xl">
          <article class="space-y-8">
            <h1 class="text-xl leading-tight font-black lg:(text-[calc(2.5vw)] tracking-tight)">Twind Example <small class="flex items-center gap-3 text-(base gray-400) tracking-normal font-bold before:(w-5 h-1 bg-current opacity-30 content-[''])">Module + CDN + Auto Dark</small></h1>
            <p>Paragraph...</p>
            <hr />
            <p class="flex-(& wrap) items-center gap-2">
              <span class="w-full">Some dynamic buttons:</span>
              <a href="#" class="btn-brand">Brand</a>
              <a href="#" class="btn-gray">Gray</a>
              <a href="#" class="btn-rose">Rose</a>
            </p>
          </article>
        </section>
      </main>
      <footer class="px-4 text-(gray-500 sm center) flex-none md:(text-end)">
        <div class="mx-auto border-(t gray-500/25) py-4 max-w-7xl">Footer info</div>
      </footer>
    </div>
    <script type="module">
      // color mode
      const toggleColorMode = function() {
        if (document.documentElement.classList.contains('dark')) {
          document.documentElement.classList.remove('dark');
          localStorage.setItem('color-mode', 'light')
          return;
        }
        document.documentElement.classList.add('dark');
        localStorage.setItem('color-mode', 'dark');
      };
      document.querySelectorAll('.color-mode').forEach(btn => {
        btn.addEventListener('click', toggleColorMode);
      });

      // icons
      import 'https://esm.run/iconify-icon';

      // twind
      import { install, injectGlobal, autoDarkColor } from 'https://esm.run/@twind/core';
      import presetAutoprefix from 'https://esm.run/@twind/preset-autoprefix';
      import presetTailwind from 'https://esm.run/@twind/preset-tailwind';
      install({
        presets: [presetAutoprefix(), presetTailwind()],
        darkMode: 'class',
        darkColor: autoDarkColor,
        hash: false,
        theme: {
          extend: {
            colors: ({ theme }) => ({
              brand: theme('colors.indigo'),
            }),
            fontFamily: ({ theme }) => ({
              sans: ['Inter', ...theme('fontFamily.sans')],
            }),
          },
        },
        rules: [
          ['text-wrap-(unset|wrap|nowrap|balance)', 'textWrap'],
          ['btn-', ({ $$ }) => `py-1.5 px-3 bg-${$$}-200 text-${$$}-800 inline-flex items-center gap-1.5 rounded-md motion-safe:(transition) hover:(bg-${$$}-700 text-${$$}-50 ring-(4 ${$$}-500/50))`],
        ],
      });
      // global css
      injectGlobal`
        @layer base {
          hr { @apply border-gray-500/25; }
        }
      `
    </script>
  </body>

</html>

@cvladan
Copy link
Author

cvladan commented Dec 13, 2023

Thanks @craigerskine . Finally a proper answer.

I was hoping that with the heaps of code they have, the Twind authors themselves could have made an esbuilt JS that I could just copy to my site.

I guess vanilla JS isn't trendy anymore.

Eh.

@craigerskine
Copy link

You could probably use jsdelivr to pre-compile it for you using their examples as well:

https://twind.style/installation#browser-usage

https://cdn.jsdelivr.net/combine/npm/@twind/core@1,npm/@twind/preset-autoprefix@1,npm/@twind/preset-tailwind@1

Just grab the resulting code from this link and create your own local js file.

Then you can adjust the config with syntax like this:

<script>
  twind.install({
    presets: [twind.presetAutoprefix(/* options */), twind.presetTailwind(/* options */)],
    /* tailwind config */
  })
</script>

@cvladan
Copy link
Author

cvladan commented Dec 15, 2023

Actually, the last one is not working. That's how I hit a wall initially, because it simply doesn't work. Just including the grabbed resulting code from jsdelivr and placing the local script into the head. Even from CDN I get errors... Can you try and test it, please?

image

  • works: https://cdn.jsdelivr.net/npm/@twind/core@1
  • works: https://cdn.jsdelivr.net/combine/npm/@twind/core@1,npm/@twind/preset-autoprefix@1
  • does not: https://cdn.jsdelivr.net/combine/npm/@twind/core@1,npm/@twind/preset-autoprefix@1,npm/@twind/preset-tailwind@1
  • not working with same error: https://cdn.jsdelivr.net/combine/npm/@twind/core@1,npm/@twind/preset-tailwind@1

In Firefox, error is little bit different:

image

@craigerskine
Copy link

Yeah... seems like a bug with the tailwind preset. Since @sastan has been MIA for quite awhile now, it may not get fixed unless someone else picks up the reigns.


You are really going out of your way to use Twind in a way it wasn't really intended to be used. It's way easier to just use the module syntax over esm/skypack cdn or compile it yourself.

I understand you want something static, but you can use a SSG to get the same result, plus have a WAAAAY easier time dealing with Js packages and much cleaner source.

@volkandkaya
Copy link

@craigerskine what's your plans with v3.4 coming out?

@craigerskine
Copy link

@craigerskine what's your plans with v3.4 coming out?

@volkandkaya

Honestly, I've built things with Twind v0 that will never need upgrading. Basic CSS stuff.

I love some of the updates to Tailwind and v3 in general, but some of the stuff on the horizon I just do not need. I'm OK with just creating Twind rules to add stuff I might need.

For example:

// twind config
rules: [
  // .text-wrap-balance
  ['text-wrap-(unset|wrap|nowrap|balance)', 'textWrap'],
]

I feel like I can just use the existing Twind v1 for many many years.

I'm hopeful that Tailwind will eventually switch to a CSS-in-JS model. They are already almost there with their CDN playground. It's only a matter of time.

And with stuff like UnoCSS and MasterCSS breaking into this space, Tailwind will need to keep pace.

I really hope Twind is not done though. The grouping syntax alone is just too good.

@stale stale bot added the 🛑 Abandoned The issue or Pull Request will not be worked on label Sep 15, 2024
Copy link

stale bot commented Oct 17, 2024

Hey folks. This issue hasn't received any traction for 90 days, so we're going to close this for housekeeping. If this is still an ongoing issue, please do consider contributing a Pull Request to resolve it. Further discussion is always welcome even with the issue closed. If anything actionable is posted in the comments, we'll consider reopening it.

@stale stale bot closed this as completed Oct 17, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
🛑 Abandoned The issue or Pull Request will not be worked on 📚 Documentation The documentation is lacking or missing something
Projects
None yet
Development

No branches or pull requests

5 participants