Skip to content

PostCSS warning for custom utility used with before:/after: #13591

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

Closed
gynekolog opened this issue Apr 26, 2024 · 7 comments · Fixed by #17775
Closed

PostCSS warning for custom utility used with before:/after: #13591

gynekolog opened this issue Apr 26, 2024 · 7 comments · Fixed by #17775
Assignees

Comments

@gynekolog
Copy link

What version of Tailwind CSS are you using?

3.4.3

What build tool (or framework if it abstracts the build tool) are you using?

Vite

What version of Node.js are you using?

v21.7.3

What browser are you using?

Chrome

What operating system are you using?

macOS

Reproduction URL

https://stackblitz.com/edit/vitest-dev-vitest-cp1r2y

Describe your issue

There's a PostCSS warning in the console:

A PostCSS plugin did not pass the `from` option to `postcss.parse`. This may cause imported assets to be incorrectly transformed. If you've recently added a PostCSS plugin that raised this warning, please contact the package author to fix the issue.

It starts when you define your own CSS utility and use it with the before: or after:.
Example:

css file:

@tailwind base;
@tailwind components;
@tailwind utilities;

@layer utilities {
  .bg-own {
    background-color: red;
  }
}

Usage:

<div class="before:bg-own" />
@wongjn
Copy link
Collaborator

wongjn commented Apr 30, 2024

This could be related to the before variant core plugin (this would happen with after too), it adds a new Declaration without a source property:

rule.prepend(postcss.decl({ prop: 'content', value: 'var(--tw-content)' }))

The vite-url-rewrite PostCSS plugin internally in Vite relies on this source property:

const importer = declaration.source?.input.file
if (!importer) {
  opts.logger.warnOnce(
    '\nA PostCSS plugin did not pass the `from` option to `postcss.parse`. ' +

As per the 2.4 of the PostCSS Plugin Guidelines:

Every node must have a relevant source so PostCSS can generate an accurate source map.

So if you add a new declaration based on some existing declaration, you should clone the existing declaration in order to save that original source.

if (needPrefix(decl.prop)) {
  decl.cloneBefore({ prop: '-webkit-' + decl.prop })
}

So perhaps we could clone a declaration inside the variant plugin, instead of creating a new one from scratch? But why only with your own declared utilities? The plot thickens!


It seems when we are generating the CSS:

cloneNodes(variantNodes, root.source, {
layer: 'variants',
})

We skip setting source recursively if preserveSource is true:

let shouldPreserveSource = node.raws.tailwind?.preserveSource === true && node.source
if (shouldPreserveSource) {
return false
}

And for @layer-defined class rules, this preserveSource is indeed set to true:

layerPlugins.push(function ({ addUtilities }) {
addUtilities(node, { respectPrefix: false, preserveSource: true })
})

Thus, for plugin-defined utilities, we don't have to worry about retaining source in the before/after plugin but we should do for @layer-defined class rules if seems.


So what would be the best way to solve this? Push the onus on to the plugins that use the PostCSS API to ensure they create appropriate source values? This would mean we could fix the core plugins to match this. Or try to fill in gaps in cloneNodes()? If we do want to fill in the gaps ourselves, should the source point to the original source of the @layer rule or the relevant @tailwind declaration?

Example test for this:
test('source maps for layer rules with injected nodes from plugins', async () => {
  let config = {
    content: [{ raw: `foo:bar` }],
    plugins: [
      function ({ addVariant }) {
        addVariant('foo', ({ container }) => {
          container.walkRules((rule) => {
            rule.prepend(postcss.decl({ prop: 'foo', value: 'baz' }))
          })
        })
      },
    ],
  }

  let input = postcss.parse(
    css`
      @tailwind utilities;

      @layer utilities {
        .bar {
          background-color: red;
        }
      }
    `,
    { from: 'input.css', map: { prev: map } }
  )

  let result = await run(input, config)

  let { sources, annotations } = parseSourceMaps(result)

  // All CSS generated by Tailwind CSS should be annotated with source maps
  // And always be able to point to the original source file
  expect(sources).not.toContain('<no source>')
})

@thecrypticace thecrypticace self-assigned this May 6, 2024
@eugster
Copy link

eugster commented May 22, 2024

Found this, because I just got the same error when using a custom utility with before.
As I got the error after moving the utility-class from an apply to markup I found some additional information:
If used with @apply custom utility combined with before: doesn't throw the error mentioned.
I verified this in the in the Reproduction-Url of gynekolog

EDIT: using @apply custom utility combined with before: doesn't throw an error in develop, but it breaks the build process. At least in one component. In the other the build throws just the same error as with develop, but runs.

@justb3a
Copy link

justb3a commented Jul 3, 2024

Got the same error message, removed all before|after and @apply directives and still got the error message.

Turns out the following lines introduced the message:

  /* This should work, but does apparently not, https://tailwindcss.com/docs/background-image */
  .bg-none {
    background-image: none;
  }

I think, rewriting a reserved name is not allowed. I have no idea why bg-none doesn't work on my side.

@eric-d-johnson
Copy link

eric-d-johnson commented Jul 15, 2024

I'm experiencing this same error message too. I have tracked it down to using .text-black in my tailwind.css file

 .text-black {
   ...//
}

Moving it out side of the @utilities layer works for me.

@onehorsetown
Copy link

I too tracked down a single item that caused the "A PostCSS plugin did not pass the from option to postcss.parse. This may cause imported assets to be incorrect…" warning during vite transformation:

@layer utilities {
  .focus-ring {
    @apply ring-2 ring-sky-400;
  }

As above, taking it out of the @layer utilities section caused the warning to go away.

@mrleblanc101
Copy link

mrleblanc101 commented Jan 20, 2025

Same issue.
I have these utilities:

@layer utilities {
    .flag-right {
        clip-path: path(
            'M-1 0h.768a6 6 0 0 1 4.797 2.396l18.796 25.018a8 8 0 0 1-.038 9.66L4.566 61.64A6 6 0 0 1-.203 64H-1V0Z'
        );
    }
    .flag-left {
        clip-path: path(
            'M3 0h17v64H3.055a3 3 0 0 1-2.44-4.744l15.997-22.383a8 8 0 0 0 .035-9.254L.547 4.726A3 3 0 0 1 3 0Z'
        );
    }
}

And I use class="before:flag-left after:flag-right ..." to apply the clip-path to my pseudo-element.
If I comment out my flag-left and flag-right custom utilities, the error goes away.

@thecrypticace
Copy link
Contributor

thecrypticace commented May 8, 2025

The next release will have support for source maps in development — which should get rid of this warning/error.

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.

8 participants