nvh95 / jest-preview

Debug your Jest tests. Effortlessly.🛠🖼
https://www.jest-preview.com
MIT License
2.34k stars 76 forks source link

[CSS REWRITE] [BIG UPDATE] Change how to process CSS #252

Open nvh95 opened 2 years ago

nvh95 commented 2 years ago

What is it?

Current approach to process CSS

Is there any better solution

Yes. But first, let me describe how I come up with that idea.

A few days ago, I was working on #230. The issue is that when a CSS file that contains an @import statement, jest-preview could not load the content of the imported file:

// index.css. This file is imported to the setupTest.js
@import "base.css";
@import "components.css";
@import "utils.css";

If you are curious, I handled this in #248, by inline the imported CSS, using (postcss-import). But the thing is, when opening Jest Preview Dashboard my index.css will automatically request CSS files that are imported. (It's a CSS standard)

Response:

This opens a new horizon for me to resolve all those issues above. What if instead of processing CSS at Jest Code Transformation, the "Jest Preview Dashboard" will process the CSS? I was in the middle of dinner with my family and I had to stop to think and draft the solution.

An HTTP-based approach

This is briefly how it would work:

function processCss(src, filename) {
  return {
    code: `const relativeCssPath = "${relativeFilename}";
          const link = document.createElement('link');
          link.rel = 'stylesheet';
          link.href = relativeCssPath;
          document.head.appendChild(link);
          module.exports = JSON.stringify(relativeCssPath);`,
  };
}

By doing this, we are moving the computation from Jest process to our "Jest Preview Server" process. Let's see the pros and cons Pros

  1. Jest will run faster the first time and in the CI environment (see one of my attempts at #247)
  2. (The most important one) We can write asynchronous code to process CSS
  3. No stale CSS if we update the implementation of the transformer (Jest does not automatically clear cache if code transforms changes. We are clearing the cache in postinstall script, after user installs/ updates jest-preview, see https://github.com/nvh95/jest-preview/issues/51#issuecomment-1221358730)
  4. As a result of 3, we can remove postinstall script, which is considered bad for "security". See https://socket.dev/npm/package/jest-preview

Cons

  1. jsdom does not contain CSS anymore. If someone wants to do some kinds of "visual testing" using jest-preview/transforms/css. It wouldn't be possible. (Or would it be? Can we reuse processCss?)
  2. Redundant CSS processing. Every time "Jest Preview Dashboard" request a CSS file, "Jest Preview Dashboard" needs to compile the CSS. However, we can handle this by some caching mechanism on both the server (in-memory is enough, cache to disk and LRU are OK but would be overkill) and client (browser cache headers like cache-control/ etag) sides.
  3. (Not really a con) The computation does not go anywhere, it just shifts from Jest to "Jest Preview Server".

Are any caveats?

Describe alternatives you've considered

Do not implement this at all 😂. Even though the current (Jest Transformation) approach might be slow in CI, but it's not too slow and it's cache-able. If implementing this is too hard. We can just leave it AS-IS

Additional context

241

247

nvh95 commented 2 years ago

Hey @ntt261298, please see my note above on a new approach to handle CSS. It would be great if you can give some of your thoughts. Thanks.

ntt261298 commented 2 years ago

I think this approach is really promising. (Reduce the test running time, Be able to handle async tasks so we can scale easier in the future,…) I still have some thoughts about this approach:

To summarize, I think it’s feasible to implement the new approach and will bring more pros than cons.

nvh95 commented 2 years ago

[Just a note] This can fix #260

szamanr commented 1 year ago

hi, is this on the roadmap? i would like to reduce the runtime in CI or make it only parse css based on some env variable. looks like this rewrite would solve that.