Skip to content

Conversation

@RobinMalfait
Copy link
Member

@RobinMalfait RobinMalfait commented Sep 27, 2024

This PR inserts the @import in a more sensible location when running codemods.

The idea is that we replace @tailwind base; @tailwind components; @tailwind utilities; with the much simple @import "tailwindcss";. We did this by adding the @import to the top of the file.

While this is correct, this means that the diff might not be as clear. For example, if you have a situation where you have a license comment:

/**! My license comment */
@tailwind base;
@tailwind components;
@tailwind utilities;

This resulted in:

@import "tailwindcss";
/**! My license comment */

While it is not wrong, it feels weird that this behaves like this. In this commit we make sure that it is injected in-place (the first @tailwind at-rule we find) and fixup the position if we can't inject it in-place.

The above example results in this:

/**! My license comment */
@import "tailwindcss";

However, there are scenario's where you can't replace the @tailwind directives directly. E.g.:

/**! My license comment */
html {
  color: red;
}
@tailwind base;
@tailwind components;
@tailwind utilities;

If we replace the @tailwind directives in-place, it would look like this:

/**! My license comment */
html {
  color: red;
}
@import "tailwindcss";

But this is invalid CSS, because you can't have CSS above an @import at-rule. There are some exceptions like:

  • @charset
  • @import
  • @layer foo, bar; (just the order, without a body)
  • comments

In this scenario, we inject the import in the nearest place where it is allowed to. In this case:

/**! My license comment */
@import "tailwindcss";
@layer base {
  html {
     color: red;
  }
}

Additionally, we will wrap the existing CSS in an @layer of the first Tailwind directive we saw. In this case an @layer base. This ensures that utilities still win from the default styles.

Also note that the (license) comment is allowed to exist before the @import, therefore we do not put the @import above it. This also means that the diff doesn't touch the license header at all, which makes the diffs cleaner and easier to reason about.

@RobinMalfait RobinMalfait changed the title CSS codemod: inject @improt in a more expected location CSS codemod: inject @import in a more expected location Sep 27, 2024
/**!
* License header
*/
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't add html {} before these imports because that would be an invalid input.

function migrate(root: Root) {
let baseNode: AtRule | null = null
let utilitiesNode: AtRule | null = null
let baseNode = null as AtRule | null
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer the let baseNode: AtRule | null = null approach, but the types were wrong after the fact (either null or never). Didn't want to change tsconfigs (since they are shared) so solved it this way.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems really weird to me because the behavior between the declarations should be identical 🤔

@adamwathan
Copy link
Member

@RobinMalfait In this scenario:

/**! My license comment */
html {
  color: red;
}
@tailwind base;
@tailwind components;
@tailwind utilities;

...I think it's important that it compiles to this:

/**! My license comment */
@import "tailwindcss";
@layer base {
  html {
    color: red;
  }
}

…otherwise any utility classes you add to the <html> element that conflict with those custom base styles won't work 👍

@RobinMalfait RobinMalfait force-pushed the fix/improve-import-location branch 3 times, most recently from c8968bb to 6ed62bd Compare September 30, 2024 11:56
This test makes sure that we inject the new `@import` in the correct
locations.
The idea is that we replace `@tailwind base; @tailwind components;
@tailwind utilities;` with the much simple `@import "tailwindcss";`. We
did this by adding the `@import` to the top of the file.

While this is correct, this means that the diff might not be as clear.
For example, if you have a situation where you have a license comment:
```css
/**! My license comment */
@tailwind base;
@tailwind components;
@tailwind utilities;
```

This resulted in:
```css
@import "tailwindcss";
/**! My license comment */
```

While it is not wrong, it feels weird that this behaves like this. In
this commit we make sure that it is injected in-place (the first
`@tailwind` at-rule we find) and fixup the position if we can't inject
it in-place.

The above example results in this:
```css
/**! My license comment */
@import "tailwindcss";
```

However, there are scenario's where you can't replace the `@tailwind`
directives directly. E.g.:
```css
/**! My license comment */
html {
  color: red;
}
@tailwind base;
@tailwind components;
@tailwind utilities;
```

If we replace the `@tailwind` directives in-place, it would look like
this:
```css
/**! My license comment */
html {
  color: red;
}
@import "tailwindcss";
```

But this is invalid CSS, because you can't have CSS above an `@import`
at-rule. There are some exceptions like:
- `@charset`
- `@import`
- `@layer foo, bar;` (just the order, without a body)
- comments

In this scenario, we inject the import in the nearest place where it is
allowed to. In this case:

```css
/**! My license comment */
@import "tailwindcss";
html {
  color: red;
}
```

Note that the (license) comment is allowed to exist before the
`@import`, therefore we do not put the `@import` above it. This also
means that the diff doesn't touch the license header at all, which makes
the diffs cleaner and easier to reason about.
1. One of the experimental codemods is new, and not a fix
2. Grouped the codemods together
These don't have to be wrapped in a layer.
@RobinMalfait RobinMalfait force-pushed the fix/improve-import-location branch from 6ed62bd to 67ae8b4 Compare September 30, 2024 12:52
@RobinMalfait RobinMalfait enabled auto-merge (squash) September 30, 2024 13:21
@RobinMalfait RobinMalfait merged commit 4f8ca55 into next Sep 30, 2024
3 checks passed
@RobinMalfait RobinMalfait deleted the fix/improve-import-location branch September 30, 2024 13:32
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 this pull request may close these issues.

5 participants