soranoo / next-css-obfuscator

A package deeply inspired by PostCSS-Obfuscator but for Next.js.
https://next-css-obfuscator.vercel.app
MIT License
71 stars 3 forks source link

[Feature Request] Supporting new `native CSS nesting` #20

Open hoangnhan2ka3 opened 6 months ago

hoangnhan2ka3 commented 6 months ago

Checklist

  1. [x] Read all documentation
  2. [x] No related request
  3. [x] 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 commented 6 months ago

TOO LONG MUST READ !!! 🀣🀣

hoangnhan2ka3 commented 6 months ago

Not related, but look at your hard work @soranoo , so satisfying πŸš€

Screenshot 2024-02-15 151340

Compare with 🀒

Screenshot 2024-02-15 151939
soranoo commented 6 months ago

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

hoangnhan2ka3 commented 6 months ago

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 commented 6 months ago

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

hoangnhan2ka3 commented 6 months ago

U mean the minified one?? but no obfuscated?

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

hoangnhan2ka3 commented 6 months ago

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 commented 6 months ago

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 commented 6 months ago

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

hoangnhan2ka3 commented 6 months ago

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 commented 6 months ago

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 commented 6 months ago

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 commented 6 months ago

Checkout #21

hoangnhan2ka3 commented 6 months ago

Okay...

soranoo commented 6 months ago

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 commented 6 months ago

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 commented 6 months ago

It works @soranoo πŸš€