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

Support Tailwind v3 #834

Closed
vwkd opened this issue Oct 12, 2022 · 26 comments · Fixed by #946
Closed

Support Tailwind v3 #834

vwkd opened this issue Oct 12, 2022 · 26 comments · Fixed by #946
Assignees

Comments

@vwkd
Copy link
Contributor

vwkd commented Oct 12, 2022

It would be great if fresh could support Tailwind v3. Currently, the twind plugin only supports Tailwind v2.

Tailwind v3 supports among other things custom properties, which are needed for example to use pseudo elements with after:content-['']. Also built-in colors without configuration is nice.

@zephraph
Copy link

I believe this would essentially require updating to the 1.0 release of twind (which is still in beta) and adding in @twind/preset-tailwind.

@psimk
Copy link
Contributor

psimk commented Oct 24, 2022

I managed to get the 1.0 version of twind + its tailwind preset working with fresh on a personal project.
This might prove useful to someone of you for whom lack of Tailwind 3 support is a dealbreaker. I basically just rewrote the twind plugin with an updated version, using the API's provided by twind 1.0, see sanban/tree/plugins.

@vicary
Copy link

vicary commented Oct 25, 2022

@psimk I would like to fork and try the same, but it can't seem to locate sheet in your project. Did I missed something?

@psimk
Copy link
Contributor

psimk commented Oct 25, 2022

@vicary

I am not sure exactly what is missing, could you open an issue in my project? that way we won't pollute this one 😄

@syntacticallyWrong
Copy link

Twind 1.0(.1) is now released!

The documentation is now at: twind.style

Here is the official migration guide: twind.style/migration

@tzakharko
Copy link

Now that twind 1 is officially out, it would be great if Fresh twind plugin were updated to support it.

@UrielCh
Copy link

UrielCh commented Dec 2, 2022

after a lazy replacement of

    "twind": "https://esm.sh/twind@0.16.17",
    "twind/": "https://esm.sh/twind@0.16.17/",

by

    "twind": "https://esm.sh/twind@1.0.2-canary-b1acc2e",
    "twind/": "https://esm.sh/twind@1.0.2-canary-b1acc2e/",

The ESM gateway crash.
see
unexpected...

/* esm.sh - error */
throw new Error("[esm.sh] " + "checkESM: open /tmp/esm-build-49b477dff79a43e0aeab929ce2871cc9ac71af25-f3160f04/node_modules/twind/sheets.mjs: no such file or directory");
export default null;

@tristanisham
Copy link

So it appears to be an import issue. Twind-next hasn't been published to NPM yet, so the latest version we can pull is 0.16.18.

tw-in-js/twind#384

@trescenzi
Copy link
Contributor

trescenzi commented Dec 13, 2022

It's not actually an import issue. Twind switched their module name from twind/core to @twind/core. The following imports work:

import { defineConfig } from "https://esm.sh/@twind/core@1.0.3"
import presetTailwind from "https://esm.sh/@twind/preset-tailwind@1.0.1";

If anyone is looking to use twind 1.0+ the following works(at least for me). I'm tempted to open a PR but it's so much less code than the existing plugin that I worry I'm missing behavior that I'm not taking advantage of.

EDIT: The code below doesn't work as expected. I've opened a pr though that should so reference that instead

twindPlugin.ts

import { JSX, options as preactOptions, VNode } from "preact";
import { setup as twindSetup, TwindConfig, Sheet, tw, virtual, stringify } from "https://esm.sh/@twind/core@1.0.3";
import { Plugin } from "$fresh/server.ts";

export const STYLE_ELEMENT_ID = "__FRSH_TWIND";

export interface Options {
  config: TwindConfig;
  selfURL: string;
}

declare module "preact" {
  namespace JSX {
    interface DOMAttributes<Target extends EventTarget> {
      class?: string;
      className?: string;
    }
  }
}

export function setup(options: Options, sheet: Sheet) {
  twindSetup(options.config, sheet);

  const originalHook = preactOptions.vnode;
  // deno-lint-ignore no-explicit-any
  preactOptions.vnode = (vnode: VNode<JSX.DOMAttributes<any>>) => {
    if (typeof vnode.type === "string" && typeof vnode.props === "object") {
      const { props } = vnode;
      const classes: string[] = [];
      if (props.class) {
        classes.push(tw(props.class));
        props.class = undefined;
      }
      if (props.className) {
        classes.push(tw(props.className));
      }
      if (classes.length) {
        props.class = classes.join(" ");
      }
    }

    originalHook?.(vnode);
  };
}

export function plugin(options: Options): Plugin {
  const sheet = virtual();
  setup(options, sheet);
  const main = `data:application/javascript,import hydrate from "${
    new URL("./twind/main.ts", import.meta.url).href
  }";
import options from "${options.selfURL}";
export default function(state) { hydrate(options, state); }`;
  return {
    name: "twind",
    entrypoints: { "main": main },
    render(ctx) {
      const res = ctx.render();
      const  cssText = stringify(sheet.target);
      const scripts = [];
      if (res.requiresHydration) scripts.push({ entrypoint: "main", state: [] });
      return {
        scripts,
        styles: [{ cssText, id: STYLE_ELEMENT_ID }],
      };
    },
  };
}

twind.config.js

import { defineConfig } from "https://esm.sh/@twind/core@1.0.3"
import presetTailwind from "https://esm.sh/@twind/preset-tailwind@1.0.1";

export default defineConfig({
  presets: [presetTailwind()],
});

main.ts

import { start } from "$fresh/server.ts";
import manifest from "./fresh.gen.ts";

import twindConfig from "./twind.config.ts";
import {plugin as twindPlugin2} from './twindPlugin.ts';

await start(manifest, { plugins: [
  twindPlugin2({
    config: twindConfig, 
    selfURL: import.meta.url
  }),
]});

@vicary
Copy link

vicary commented Dec 13, 2022

@trescenzi Do you mean sheets are still there, we only need to import it from the new core module instead?

@UrielCh
Copy link

UrielCh commented Dec 13, 2022

@trescenzi if you have published a twind/core@1.0.3 version on Deno deploy, it's easy to compare the effect on a website.

Simply compare css sheets data size with the default twind integration with your version.

I give is a try I change my mains.ts as:

import { start, Plugin } from "$fresh/server.ts";
import manifest from "./fresh.gen.ts";
// https://twind.dev/handbook/configuration.html

const plugins: Plugin[] = [];

// twindV1 Plugin
// import twindConfig from "./twindV1.config.ts";
// import twindPluginV1 from "$fresh/plugins/twind.ts";
// plugins.push(twindPluginV1(twindConfig))

// twindV2 Plugin
import twindPluginV2 from './twindPlugin.ts';
import twindConfig from "./twindV2.config.ts";
plugins.push(twindPluginV2({
    config: twindConfig,
    selfURL: import.meta.url
}));

await start(manifest, { plugins });

and pathed twindPlugin.ts to use default export, so V1 and V2 looks the same

@trescenzi
Copy link
Contributor

trescenzi commented Dec 14, 2022

@vicary sheets are still there however the behavior is slightly different. It appears that there is very little that is required for this to work as there's now simply a stringify function which if you pass a sheet to it it'll pull everything out you need.

@UrielCh I've got two versions of the Fresh Hacker News demo setup in deno deploy. It appears as the new version is smaller which would be nice. I'll look to clean things up and open a pr. Although I'm still not 100% sure it's not missing some edge case I'm unaware of:

Edit After playing with the v1 version it looks like it's not correctly functioning with islands/hydration which is kinda what I'd expected.

@UrielCh
Copy link

UrielCh commented Dec 14, 2022

yep, not working in islands, I rolled back to v1.

@trescenzi
Copy link
Contributor

The code in the pr that's linked should work in islands. If there's an issue though if you could share it on the pr, maybe with the island it's not working with, and I can look into what's still wrong.

@UrielCh
Copy link

UrielCh commented Dec 14, 2022

@trescenzi, we have mostly 12h of time shift.
I may only try your last version only tomorrow morning.

@UrielCh
Copy link

UrielCh commented Dec 14, 2022

It's late but I test it, island works better.

more tests tomorrow.

for now you should change in twindv1.ts
export function plugin(options: Options): Plugin {
to
export default function plugin(options: Options): Plugin {

the old twind plugins is exported as a default not as plugin

@trescenzi
Copy link
Contributor

Oh awesome thanks for taking a look. I'll make that change.

@vicary vicary mentioned this issue Dec 16, 2022
10 tasks
@seanaye
Copy link

seanaye commented Dec 25, 2022

I'm using the code from the PR locally. It looks like the styles are not recomputed when islands update their classes. e.g.
class={`${active ? 'text-red-500' : 'text-blue-500'`} will never update.

@KyleJune
Copy link

I don't use fresh but I did recently get twind 1.0.6 working in deno with React 18. Sharing my example here because I thought it might be helpful for other people's efforts to make twind 1.0.6 work with fresh/preact.

https://deno-twind-with-react.deno.dev/
https://github.com/KyleJune/deno-twind-with-react

@trescenzi
Copy link
Contributor

I was looking to release the code in my pr as a separate plug-in and came across another version of this code called freshwind. Assuming it doesn't have the issues with the code in my pr it's probably the better solution to this problem.

@trescenzi
Copy link
Contributor

I'm using the code from the PR locally. It looks like the styles are not recomputed when islands update their classes. e.g.

class={`${active ? 'text-red-500' : 'text-blue-500'`} will never update.

Sweet thank you for this. I'll look into it tomorrow.

@UrielCh
Copy link

UrielCh commented Dec 27, 2022

I'm still using your fork, I also tried custom animation, and everything is still working fine.

@UrielCh
Copy link

UrielCh commented Dec 27, 2022

esm.sh v100 or v101 contains breaking change that make @twind/core non functional.

I use these import maps to make it work today:

{
    "@twind/core": "https://esm.sh/v99/@twind/core@1.0.3",
    "@twind/preset-tailwind": "https://esm.sh/v99/@twind/preset-tailwind@1.0.1",
}

v99 is forced.

@KyleJune
Copy link

KyleJune commented Dec 27, 2022

What's the error that you are getting? I use v100 in my project with no issue, but I'm using the latest @twind/core version. Also I recommend always pinning your version of esm.sh to avoid updates to it breaking your build.

@UrielCh
Copy link

UrielCh commented Jan 11, 2023

I think that the error was caused by V101, only with old @twind/core versions.

@saolof
Copy link

saolof commented Feb 15, 2023

Following the steps outlined in this repository made it work for me:
https://github.com/y3km21/fresh-twindv1-plugin

@ry ry closed this as completed in #946 Feb 24, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.