Skip to content

[Feature Request] Supporting new native CSS nesting #20

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
3 tasks done
hoangnhan2ka3 opened this issue Feb 15, 2024 · 18 comments
Closed
3 tasks done

[Feature Request] Supporting new native CSS nesting #20

hoangnhan2ka3 opened this issue Feb 15, 2024 · 18 comments
Labels
enhancement New feature or request

Comments

@hoangnhan2ka3
Copy link

hoangnhan2ka3 commented Feb 15, 2024

Checklist

  1. Read all documentation
  2. No related request
  3. Meaningful issue title

Is your feature request related to a problem? Please describe.
Maybe not, just a feature request.

Describe the solution you'd like
Supporting obfuscate new native CSS nesting.

Describe alternatives you've considered
1. first, 2. later.

Additional context

👀Version v2.2.7

Note: sorry for the inconvenience, developer.mozilla.org doesn't seem to automatically scroll to the location of ref links in this article (at least for me), you can scroll until If you see any text that is highlighted to see it.


THIS POST HAS 02 BIG SECTIONS:

1. With CSS nesting plugin *before* Tailwind enabled.

next-css-obfuscator work with these plugin enabled! (but there's still a bug which will not replaced the obfuscated class)

2. With CSS nesting plugin *before* Tailwind disabled.

next-css-obfuscator does not work when not enable these plugin! (I can't capture the log cuz it's too long)

So, what is that plugin?

🐽 1. When you using CSS Nesting in NextJs with TailwindCSS, you will receive a notification like this in the log terminal:

(82:2) Nested CSS was detected, but CSS nesting has not been configured correctly.
Please enable a CSS nesting plugin *before* Tailwind in your configuration.
See how here: https://tailwindcss.com/docs/using-with-preprocessors#nesting

And in the instruction link it provides, follow it, and you will get results like this in postcss.config.js:

image

Now CSS Nesting in your global.css file will behave much like .sass after npm run build. That means that even though existing CSS supports native CSS nesting, TailwindCSS will still convert it to normal CSS.

🐽 2. But if you do nothing, just ignore it, it's still works (cuz it became native now), but everytime you save the file, TailwindCSS will yell the above warning

It still works but is not supported by default by TailwindCSS, NextJs...

Before going to the Big sections, let's explain a bit.

✨ Main point:

CSS nesting is different from CSS preprocessors such as Sass in that it is parsed by the browser rather than being pre-compiled by a CSS preprocessor. (ref)

Example TSX:

<div className="note">
  <p>
    <b className="note-title">Note:</b> This demo website is just <u id="note-exp">experimental</u>, so if you see something wrong <i>(like error layout or typography)</i>, please do a &quot;hard reload&quot; (<b>Ctrl + Shift + R</b> or <b>Cmd + Shift + R</b>)
  </p>
</div>

👉 In fact, CSS already supports nesting natively in the form of nesting selector: & like below (ref):

/* global.css */

.note {
  display: flex;
  align-items: center;
  transition: opacity 0.2s ease-out;
  transition-delay: 1.2s;
  opacity: 0.2;
  cursor: help;

  /* class */
  & .note-title {
    letter-spacing: 1rem;
  }

  /* id */
  & #note-exp {
    opacity: 0.2;
  }

  /* pseudo-class */
  &:hover {
    opacity: 1;
    transition-delay: 0s;
  }
  /*! `&:hover` not `& :hover` <- WITH blank no work */

  /* tag */
  & p {
    font-size: 0.875rem;
  }
  /*! `& p` not `&p` <- NO blank no work */
}

👉 But recently (I don't know when), CSS has supported without nesting selector (ref):

/* global.css */

.note {
  display: flex;
  align-items: center;
  transition: opacity 0.2s ease-out;
  transition-delay: 1.2s;
  opacity: 0.2;
  cursor: help;

  /* class */
  .note-title {
    letter-spacing: 1rem;
  }

  /* id */
  #note-exp {
    opacity: 0.2;
  }

  /* pseudo-class */
  &:hover {
    opacity: 1;
    transition-delay: 0s;
  }
  /*! `&:hover` not `& :hover` <- WITH blank no work */

  /* tag */
  p {
    font-size: 0.875rem;
  }
}

Hmmm, except something like :hover, ::before, ::after maybe, I tried and it didn't work without & in front. (I didn't try with :iscuz I can't think of a suitable case)

👉 On the other hand, there exists something called CSS Combinators: + (ref)

The next-sibling combinator (+) separates two selectors and matches the second element only if it immediately FOLLOWS THE FIRST ELEMENT, and both are children of the same parent element. (ref)

h2 {
  color: tomato;
  + p {
    color: white;
    background-color: black;
  }
}

Okay, maybe enough...


🚀 1. With CSS nesting plugin *before* Tailwind ENABLED.

image

IMPORTANT: it appears that TailwindCSS automatically converts these native CSS nesting to normal CSS (without nesting) via PostCSS, even though it doesn't need to be done to run normally
(as evidenced by run dev, or disable next-css-obfuscator plugin and run build + run start).

next-css-obfuscator plugin ENABLED

Obfuscated ✅:

conversion.json

Screenshot 2024-02-15 110435


Not replaced ⛔:

output .css file with next-css-obfuscator plugin enable:

Screenshot 2024-02-15 110141

Please ignore the red comment, it seems to be normal behavior in production

next-css-obfuscator plugin DISABLED

output .css file with next-css-obfuscator plugin disable:

Screenshot 2024-02-15 110924

🚀 2. With CSS nesting plugin *before* Tailwind DISABLED.

image

next-css-obfuscator plugin simply doesn't works when enabled.

But when disable next-css-obfuscator:

This is the output .css file:

Screenshot 2024-02-15 125038

Which truly a native CSS nesting, but when in production, it's still yell:

(82:2) Nested CSS was detected, but CSS nesting has not been configured correctly.
Please enable a CSS nesting plugin *before* Tailwind in your configuration.
See how here: https://tailwindcss.com/docs/using-with-preprocessors#nesting

However, that's just a warning not an error, the build process still successfully!

In conclusion, I think for now you should only focus on fixing part 1., as for part 2., wait until TW and NextJs support native CSS nesting then you can fix it later

@hoangnhan2ka3 hoangnhan2ka3 added the enhancement New feature or request label Feb 15, 2024
@hoangnhan2ka3
Copy link
Author

TOO LONG MUST READ !!! 🤣🤣

@hoangnhan2ka3
Copy link
Author

hoangnhan2ka3 commented Feb 15, 2024

Not related, but look at your hard work @soranoo , so satisfying 🚀

Screenshot 2024-02-15 151340


Compare with 🤢

Screenshot 2024-02-15 151939

@soranoo
Copy link
Owner

soranoo commented Feb 15, 2024

Any sample CSS(before obfuscated) inside the .next folder can be provided? I guess it's just a bug in recursion.

@hoangnhan2ka3
Copy link
Author

hoangnhan2ka3 commented Feb 15, 2024

yaeh maybe 1. is just a bug, but not 2.

However, u mean this?

430633817468dcce.css.txt

Just delete .txt ext or copy it manually.

And this is the obfuscated version one:

430633817468dcce.css.txt

My config:

module.exports = {
	enable: true, // Enable or disable the plugin.
	mode: "random", // Obfuscate mode, "random" or "simplify".
	buildFolderPath: ".next", // Build folder of your project.
	classConversionJsonFolderPath: "./css-obfuscator", // The folder path to store the before obfuscate and after obfuscated classes conversion table.
	refreshClassConversionJson: false, // Refresh the class conversion JSON file.

	classLength: 6, // Length of the obfuscated class name.
	classPrefix: "n", // Prefix of the obfuscated class name.
	classSuffix: "", // Suffix of the obfuscated class name.

	classIgnore: ["dark", "light", "no-transition", "opa-hidden", "big", "small", /__.*/, /os-*/], // The class names to be ignored during obfuscation.

	allowExtensions: [".jsx", ".tsx", ".js", ".ts", ".html", ".rsc"], // The file extensions to be processed.

	contentIgnoreRegexes: [/\.jsxs\)\("\w+"/g], // The regexes to match the file content to be ignored during obfuscation.

	whiteListedFolderPaths: [], // Only obfuscate files in these folders

	blackListedFolderPaths: ["./.next/cache"], // Don't obfuscate files in these folders

	enableMarkers: false, // Enable or disable the obfuscate marker classes.
	markers: ["obf"], // Classes that indicate component(s) need to obfuscate.
	removeMarkersAfterObfuscated: true, // Remove the obfuscation markers from HTML elements after obfuscation.

	removeOriginalCss: true, // Delete original CSS from CSS files if it has a obfuscated version.

	generatorSeed: "84817818898", // The seed for the random generator.

	//! Experimental feature (Alpha)
	enableJsAst: false, // Whether to obfuscate JS files using abstract syntax tree parser (Experimental feature)

	logLevel: "info", // Log level
};

Note: Sorry I forgot that I had changed the class .note in above post to id #note, please pay attention.

@soranoo
Copy link
Owner

soranoo commented Feb 15, 2024

No, I need the stripped CSS file, like the second file u provided

@hoangnhan2ka3
Copy link
Author

hoangnhan2ka3 commented Feb 15, 2024

U mean the minified one?? but no obfuscated?

and would u like me to turn the CSS nesting plugin off?

@hoangnhan2ka3
Copy link
Author

hoangnhan2ka3 commented Feb 15, 2024

I'll give u two

Obfuscation disable + CSS nesting plugin enable:

1c37b5e777b9906b.css.txt

Obfuscation disable + CSS nesting plugin disable:

4c03261ae211d960.css.txt

Sorry but I just keep the &:hover and p tag for now.

@hoangnhan2ka3
Copy link
Author

hoangnhan2ka3 commented Feb 15, 2024

Btw, in your readme.md:

Line 3: start -> starts

Line 41: sulotion -> solution

Line 93: is issue -> is the issue

Line 95: change -> changing

Line 209, 228, 377: convertion -> conversion

Line 209: and obfuscation -> and the obfuscation

Line 212: recommanded -> recommended

Line 313: still at the early stage -> still in the early stages

Line 319: and strongly -> and is strongly

Line 369: found the package not work as expected after updated -> find the package does not work as expected after being updated

Line 414: may referenced -> may be referenced

Line 428: that related to class -> that is related to the class

Line 431: component under obfuscation -> component is under the obfuscation

Line 457: component -> components and children components -> "children" components (although the right one is child, but children maybe a pattern word in our brain so u can just put it in " " :)))

Actually, I was going to send you this from the Domes (Demos) case, but you already edited it, making me forget about this 🤣.

Waiting for the next patch 😶‍🌫️

@soranoo
Copy link
Owner

soranoo commented Feb 15, 2024

Please open a new issue if you are going to mention ANYthing not relevant to the current issue!!

@hoangnhan2ka3
Copy link
Author

Since I'm not a plugin maker, I don't understand what it means to have multiple issues in a project :))), but if you want I will, chill~

@soranoo
Copy link
Owner

soranoo commented Feb 15, 2024

An issue is something like a topic. It is not relevant whether you are a package creator, It is important to the open-source community!!!

@hoangnhan2ka3
Copy link
Author

Okay, so sorry, I will do it from now...

What should I choose for that small grammar fix

image

I think it will be a feature request, but do I have the right to remove your entire template and just leave a small suggestion like above?

@soranoo
Copy link
Owner

soranoo commented Feb 15, 2024

Checkout #21

@hoangnhan2ka3
Copy link
Author

Okay...

@soranoo
Copy link
Owner

soranoo commented Feb 15, 2024

Case 1: Can't reproduce
Case 2: I'm not going to support nesting in the current step. It would overthrow the foundation of version 2. I will consider implementing it if there is significant demand in the future.

@hoangnhan2ka3
Copy link
Author

hoangnhan2ka3 commented Feb 16, 2024

Note: tested with both v2.2.7 and v2.2.8.

To reproduce:

// postcss.config.js

module.exports = {
  plugins: {
    "postcss-import": {}, // add this
    "tailwindcss/nesting": {}, // and this
    tailwindcss: {},
    autoprefixer: {},
  },
};
// next-css-obfuscator.config.cjs

module.exports = {
  enable: true,
  mode: "random",
  buildFolderPath: ".next",
  classConversionJsonFolderPath: "./css-obfuscator",
  refreshClassConversionJson: false,

  classLength: 6,
  classPrefix: "n",
  classSuffix: "",

  classIgnore: ["dark", "light", "no-transition", "opa-hidden", "big", "small", /__.*/, /os-*/],

  allowExtensions: [".jsx", ".tsx", ".js", ".ts", ".html", ".rsc"],

  contentIgnoreRegexes: [/\.jsxs\)\("\w+"/g],

  whiteListedFolderPaths: [],

  blackListedFolderPaths: ["./.next/cache"],

  enableMarkers: false,
  markers: ["obf"],
  removeMarkersAfterObfuscated: true,

  removeOriginalCss: true,

  generatorSeed: "84817818898",

  //! Experimental feature (Alpha)
  enableJsAst: false,

  logLevel: "info",
};
{/* whatever page.tsx you like */}

...

<div className="note">
  <p>
    <b className="note-title">Note:</b> This demo website is just <u id="note-exp">experimental</u>, so if you see something wrong <i>(like error layout or typography)</i>, please do a &quot;hard reload&quot; (<b>Ctrl + Shift + R</b> or <b>Cmd + Shift + R</b>)
  </p>
</div>

...
/* globals.css */

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

.note {
  display: flex;
  align-items: center;
  transition: opacity 0.2s ease-out;
  transition-delay: 1.2s;
  opacity: 0.2;
  cursor: help;

  /* class */
  .note-title {
    letter-spacing: 1rem;
  }

  /* id */
  #note-exp {
    opacity: 0.2;
  }

  /* pseudo-class */
  &:hover {
    opacity: 1;
    transition-delay: 0s;
  }
  /*! `&:hover` not `& :hover` <- WITH blank no work */

  /* tag */
  p {
    font-size: 0.875rem;
  }
}

Delete the .next/cache folder and old css-obfuscator folder with old conversion.json file in it.

=> yarn build

Result:

Obfuscated ✅:

conversion.json

Screenshot 2024-02-15 110435


Not replaced in output css file ⛔:

Screenshot 2024-02-15 110141

=> yarn start

Just replaced in output html file ✅:

Screenshot 2024-02-16 092353

And of course no style on that obfuscated class.

eg: .nu7dy1l which is .note-title and has a style of letter-spacing: 1rem, but there no style applied:

image

image

In expected:

image

@hoangnhan2ka3
Copy link
Author

It works @soranoo 🚀

@soranoo soranoo mentioned this issue May 31, 2025
@soranoo
Copy link
Owner

soranoo commented May 31, 2025

v.3.0.0 now supports nested CSS

Migrate from version 2.x to 3.x

@soranoo soranoo closed this as completed May 31, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

2 participants