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

Incorrect Class Conversion Table Generation #11

Closed soranoo closed 7 months ago

soranoo commented 7 months ago

Sorry, I have a problem unrelated to this issue, which is caching.

You know, every time you run build the obfuscate process will start from the beginning, meaning the random obfuscated classes will be completely different from the previous time. This causes nextjs cache related issue.

If a user has visited my page before, then after I update (new deployed), and they reload the page without clearing the cache, it will look like this:

image

And no matter how many times they try to 'refresh' the website, it will still look the same.

Unless they press Ctrl + Shift + R (aka hard reload), the site is updated.

image

Even when I try view page source without hard reload, the css file doesn't have any new obfuscated class, which causes an error like my website doesn't have css at all.

Do you have the same problem in your version of Next Js, or do you have any advice for me, I've been searching for it all night.

Originally posted by @hoangnhan2ka3 in https://github.com/soranoo/next-css-obfuscator/issues/10#issuecomment-1925819091


Additional Infomation-

hoangnhan2ka3 commented 7 months ago

The problem probably only occurs when I enable next-css-obfuscator.

If you don't enable it from the beginning, the TW classes will just update the new values ​​after each deployment, and the old classes don't need to be changed, and it will be cached, I think.

hoangnhan2ka3 commented 7 months ago

Bruhh is that easy ?=))), the problem may actually be caching, I don't see that being fixed in 2.1.5, are there any more steps needed?

I still think this will be a Nextjs cache control header problem, thank you~

soranoo commented 7 months ago

If yes, then that is out of the scope of this package.

BUT the issue was just caused by the different obfuscation results in every run. In other words, this is due to the incorrect behaviour of the refreshClassConversionJson option.

hoangnhan2ka3 commented 7 months ago

Yes, it's annoying.

I think I'll split the current repo into a separate repo to be the source for hoangnhan.co.uk, it seems to be enough to be considered a demo site.

After that I thought I would have to turn this plugin off and turn it back on when everything is done, or I need too hard refresh every time deployed πŸ˜„

hoangnhan2ka3 commented 7 months ago

Yesss, I think we need to do an option opposite to refreshClassConversionJson, I mean just updating new classes, that could also help reduce the overall obfuscate time, even though it is already very fast πŸ‘€

Now:

image

In expected:

Updated 02 more CSS rules to a6ee7635e9d39b73.css
soranoo commented 7 months ago
// next-css-obfuscator.config.cjs

module.exports = {
    //...
    refreshClassConversionJson: false,
    //...
};
hoangnhan2ka3 commented 7 months ago

Haha what a beautiful prospect

hoangnhan2ka3 commented 7 months ago

I never even set the refreshClassConversionJson to true sir πŸ₯²

Every time I want to try 'run build', I delete the old .next/cache folder and css-obfuscator folder before running the command. This makes me feel safer.

soranoo commented 7 months ago

Yesss, I think we need to do an option opposite to refreshClassConversionJson, I mean just updating new classes, that could also help reduce the overall obfuscate time, even though it is already very fast πŸ‘€

Now:

image

In expected:

Updated 02 more CSS rules to a6ee7635e9d39b73.css

Your expectations will never happen. NEXT JS generate a brand new CSS file in every build so the obfuscator has to obfuscate the whole CSS again and again.

soranoo commented 7 months ago

I never even set the refreshClassConversionJson to true sir πŸ₯²

Every time I want to try 'run build', I delete the old .next/cache folder and css-obfuscator folder before running the command. This makes me feel safer.

That is the problem I mentioned as follows.

If yes, then that is out of the scope of this package.

BUT the issue was just caused by the different obfuscation results in every run. In other words, this is due to the incorrect behaviour of the refreshClassConversionJson option.

hoangnhan2ka3 commented 7 months ago

U mean I should set it to true when deploying or is there an error in refreshClassConversionJson?

Perhaps there is no way to preserve the previously obfuscated class name? (based on the previous conversion.json file?), if possible, it seems that the pre-production steps will be more cumbersome hmm πŸ€”

soranoo commented 7 months ago

Please reference to πŸ“– Config Options.

The obfuscator will use the old table if refreshClassConversionJson = false and push new obfuscation to the table if needed. Otherwise( if refreshClassConversionJson = true), a new table will be generated with brand new obfuscated selectors.

It is HIGHLY recommended to run the build cmd twice to see if there are any changes in the conversion.json and I believe most of your confusion will be resolved by doing this.

hoangnhan2ka3 commented 7 months ago

But the problem is that Vercel will build the css-obfuscator folder from scratch every time it is deployed. Am I right?

And I've also included the css-obfuscator folder in .gitignore, should I? If not, do I have to run run build every time I deploy to update conversion.json?

Can you briefly recount the most accurate workflow for me?

soranoo commented 7 months ago

The deployment procedure is up to you.

But I will add css-obfuscator to .gitignore and let Vercel do the job. That is no reason I have to update the conversion table by myself. If you are concerned about the cache, yes updating manually maybe an ideal option.

hoangnhan2ka3 commented 7 months ago

Okay, as I mentioned

But the problem is that Vercel will build the css-obfuscator folder from scratch every time it is deployed. Am I right?

And

I've also included the css-obfuscator folder in .gitignore

Present:

image

Then I edited a letter in /home, then deployed again

image

So what u mean

The obfuscator will use the old table if refreshClassConversionJson = false and push new obfuscation to the table if needed.

Is that true or did I set it up wrong somewhere?

image

.gitignore:

image

GitHub repo:

image

soranoo commented 7 months ago

Vercel will download the repo to an empty folder(kind of) and everything has to be generated from scratch so you can see different obfuscated class names.

I can add a predictable obfuscation mode, tell me if u need it.

hoangnhan2ka3 commented 7 months ago

What u mean predictable πŸ˜„, any ref?

I just ran run build twice, it's true that it only updates the new class, you're right.

But I wonder, when I deploy the whole css-obfuscator folder, what happens? Let me check.

Perhaps run build before deploying wouldn't be such a bad idea if it solved the caching problem

soranoo commented 7 months ago

predictable same input same output

hoangnhan2ka3 commented 7 months ago

Is there any way for Vercel to keep the old resources? Even though they say they do, perhaps the npm install process refreshes these resources each time they deploy?

And I just found out, if refreshClassConversionJson is false, yes, it will update the new class if there is one and also keep the old obfuscated class intact. But when I delete the newly added class and run build again, the log says {previous CSS rules} - 1

eg: 236 to 235

But when I check conversion.json the class has not been removed

hoangnhan2ka3 commented 7 months ago

Oh no, even when I uploaded css-obfuscator folder, Vercel didn't respect my old css-obfuscator one, they generated brand new class:

First deployment:

image

I update something not related and deploy again:

image

It kept the old class (in html), but in new css (view page source):

image

hoangnhan2ka3 commented 7 months ago

What's wrong 🀑🀑🀑

soranoo commented 7 months ago

Try redeploy with the Use existing build cache option disabled.

hoangnhan2ka3 commented 7 months ago

Oh sorry, it's my fault again. I should have made a hard reload to simulate a new user entering the site for the first time before doing the steps above, and I forgot about that. Now everything seems to be fine, there's only the problem of 'not automatically deleting the class'

soranoo commented 7 months ago

This is an expected behaviour of the obfuscator to keep the removed selector obfuscation data.

hoangnhan2ka3 commented 7 months ago

Do u mean to keep unnecessary classes for later use?

Btw...

Yeah, and there's probably no better way than updating conversion.json manually (I can even give custom names to the classes I want πŸ˜„), just run build is really long, but if you don't do that the plugin won't run because it gets the build data from .next

hoangnhan2ka3 commented 7 months ago

It's okay, at least it lives up to my expectations ✨

hoangnhan2ka3 commented 7 months ago

Hey @soranoo , do you plan to also obfuscate id too? like PostCSS-Obfuscator

soranoo commented 7 months ago

not now, I may do it after fixing the Partial Obfuscation

soranoo commented 7 months ago

@hoangnhan2ka3 Check out the latest update, and the following https://github.com/soranoo/next-css-obfuscator?tab=readme-ov-file#6-how-to-deal-with-css-cache-in-paas-like-vercel

Hope this can help you out.

hoangnhan2ka3 commented 7 months ago

This means just letting the Math.random().toString() expression do its thing without worrying about whether it will change or if I need to create my own random string and put it here?

image

And one more thing, can I safely put the css-obfuscator folder into .gitignore now?

hoangnhan2ka3 commented 7 months ago

I put the css-obfuscator folder into .gitignore and I see the class name still changes after each deployment, so caching problem still there hmmm

First:

Screenshot 2024-02-05 145124

Second:

Screenshot 2024-02-05 145722
soranoo commented 7 months ago

As I mentioned in the πŸ’‘ Tips section, you have to PROVODE a seed.

hoangnhan2ka3 commented 7 months ago

Yes I tried

image

But useless

hoangnhan2ka3 commented 7 months ago

Another case is that I still deploy the css-obfuscator folder but I no longer need to run build before deploying it.

But it doesn't look very promising...

My config now:

module.exports = {
    enable: true, // Enable or disable the plugin.
    mode: "predictable", // 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: "", // Prefix of the obfuscated class name.
    classSuffix: "", // Suffix of the obfuscated class name.

    classIgnore: [
        "no",
        "dark",
        "light",
        "no-transition",
        "opa-hidden",
        "big",
        "small",
        /lenis*/
    ], // 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: 840817818898, // The seed for the random generator.

    logLevel: "info", // Log level
};
hoangnhan2ka3 commented 7 months ago

I think 'generating a seed' seems like a good and promising idea, just like the seed in 'Stable Diffusion'.

But is it really as easy as you think, like having to prepare the class name in advance for all possible situations?

soranoo commented 7 months ago

I think 'generating a seed' seems like a good and promising idea, just like the seed in 'Stable Diffusion'.

But is it really as easy as you think, like having to prepare the class name in advance for all possible situations?

Would you mind showing me how others can reverse a random string back to a class name?

The random function doesn't take the original class name as input, I don't think it can be reversed.

hoangnhan2ka3 commented 7 months ago

Sorry, I can't because that's not my expertise.

Have you ever used Stable Diffusion, seed in SD will look like this:

image

It means that if the value in the seed box is -1 then each time generate the image will use a different number string (random).

And if you fill in the seed box with a certain sequence of numbers (it doesn't matter what the number and magnitude limit is: it can be 1, 11, 111 or 9516515132159). So each time you generate the image with the same initial prompt the image will look the same (just a very very very little bit diffrent in small details) until you change to a different seed.

That's what I expect from predictable mode or it should called preserved mode if you can do it, it's really difficult just imagining it isn't it?

soranoo commented 7 months ago

13

The issue was fixed

hoangnhan2ka3 commented 7 months ago

So one last time

can I safely put the css-obfuscator folder into .gitignore now?

And let it automatically added just new classes?

soranoo commented 7 months ago

css-obfuscator is a generated folder so it is safe to put it into .gitignore

hoangnhan2ka3 commented 7 months ago

And I hope that in future 'deploys', the old class names will remain the same as last time and only 'new classes' will be added if any?

That's what predictable mode does, right? I need you to confirm so I can move the css-obfuscator folder into .gitignore for the 3rd time today πŸ™‚

And I need you to confirm one more issue:

generatorSeed needs to be a number between 0 and 1 like 0.132156479 (separated by a dot .), right?

soranoo commented 7 months ago

Please read the πŸ“– Config Options Reference carefully!!!!

  1. "predictable" means the obfuscated class name will be the same if the same CSS file is provided.
  2. generatorSeed is a STRING, just put some random characters you like
hoangnhan2ka3 commented 7 months ago

But every time you deploy, Vercel will create a new css file

if the same CSS file is provided

, so is predictable mode useless in production?

soranoo commented 7 months ago

OK, sorry for misleading, it should be,

"predictable" means the obfuscated class name will be the same if the same CSS content is provided.

hoangnhan2ka3 commented 7 months ago
  1. same content, do you mean the seed that I provide to the config file initially will save the current content of the CSS file, then if I add anything new, it will ONLY OBFUSCATE THE NEW CLASSES (content). That's it, right? And then it loops the process again?

  2. Or when I add a new class and the content is changed, the obfuscate process will completely refresh both old and new class name?

Please choose 1 or 2, I hope it's 1

soranoo commented 7 months ago

Neither is correct, the obfuscation is expected to run after the build is completed. A new conversion table will be generated every time but with the given seed(the seed will used to feed the pseudorandom number generator). If the seed is set and the sequence of CSS selectors inside the CSS file is the same as the last build then the table will be the same. So if a new class is added and Tailwind puts it inside the sequence(break the old sequence), an obfuscated class name will be assigned and NEXT JS will give another file name with the new CSS content which will invalidate the old cache (based on my experience).

hoangnhan2ka3 commented 7 months ago

The answer I want to hear from you is that if a new TW class is added, all the old class names will not be kept and will be changed to different class names, right?

If that's the case, then I think you should leave predictable out, or merge it with random if there really is something better than random.

soranoo commented 7 months ago
  1. PLEASE READ THE COMMENT CAREFULLY, short answer: can be different/ the same
  2. Yes, Im going to merge predictable to random and simplify mode
hoangnhan2ka3 commented 7 months ago

I know but

an obfuscated class name will be assigned and NEXT JS will give another file name with the new CSS content which will invalidate the old cache (based on my experience).

What do u mean assigned, and don't worry about caching problem, it's too soon.

I want to know the result, a solid answer, about what would happen if a new TW class were added.

soranoo commented 7 months ago

Why don't I make your wish come true instead of explaining it in a text?

Let's move to #14