near / bos-web-engine

Improved execution layer for NEAR decentralized frontend components
https://roc-docs.near.dev/
26 stars 6 forks source link

🔷 [Epic] CSS: LightningCSS integration #280

Closed mpeterdev closed 4 months ago

mpeterdev commented 5 months ago

LightningCSS ships as WASM and could power our CSS modules implementation while offering additional benefits like syntax lowering

I tried to load it in our current project but was experiencing an import error. Instead of spending time trying to resolve that, I created a minimal test Vite app. The following is a functional app TSX with the ouput of the LightningCSS transform included as comments

App.tsx

import { useEffect } from "react";

import init, { transform } from "https://esm.run/lightningcss-wasm";

function App() {
  useEffect(() => {
    init().then(() => {
      console.log("WASM module loaded");
      const { code, exports } = transform({
        filename: "style.css",
        code: new TextEncoder().encode(
          `
.foo {
  color: red;
}

.foo:hover {
  color: blue;
}
`
        ),
        cssModules: true,
        // minify: true,
      });
      console.log(new TextDecoder().decode(code));
      // OUTPUT:
      //
      // .fz3d1W_foo {
      //   color: red;
      // }
      //
      // .fz3d1W_foo:hover {
      //   color: #00f;
      // }

      console.log("exports", JSON.stringify(exports, null, 2));
      // OUTPUT:
      //
      // {
      //   "foo": {
      //     "name": "fz3d1W_foo",
      //     "composes": [],
      //     "isReferenced": false
      //   }
      // }
    });
  }, []);

  return (
    <>
      <h1>LightningCSS Test</h1>
    </>
  );
}

export default App;
calebjacob commented 5 months ago

This definitely looks promising. Related: https://github.com/near/bos-web-engine/issues/253

mpeterdev commented 4 months ago

@andy-haynes thoughts on making this an official P0 epic? Any chance you think we might not want to this route?

andy-haynes commented 4 months ago

Yeah I think this is the way to go. The only unknowns for me are running WASM in a worker and performance (given what we saw with SWC) but I don't expect major challenges.

andy-haynes commented 4 months ago

I'm trying to run the ESM in your example in the worker, but Webpack, which only works with experimental features enabled, needs to analyze the dynamic import in order to bundle the module. Unfortunately there's a reference to a non-existent package, which breaks bundling. Based on the Webpack docs, it looks like the way around this might be a proxy HTTP server that returns an empty 200.

Looking at that URL in the example more closely, I noticed that the WASM it imports is 10.5MB: https://cdn.jsdelivr.net/npm/lightningcss-wasm/lightningcss_node.wasm. Is that going to be too big?

Test branch: https://github.com/near/bos-web-engine/tree/feat/lightning-css

mpeterdev commented 4 months ago

Looking at that URL in the example more closely, I noticed that the WASM it imports is 10.5MB: https://cdn.jsdelivr.net/npm/lightningcss-wasm/lightningcss_node.wasm. Is that going to be too big?

That certainly isn't ideal, but I can't say whether it would cause a performance impact that would outweigh the value we get from a battle tested CSS toolchain

I am inclined to lean towards stability while gaining traction then looking towards optimization when our focus shifts to more widespread adoption

calebjacob commented 4 months ago

Looking at that URL in the example more closely, I noticed that the WASM it imports is 10.5MB: https://cdn.jsdelivr.net/npm/lightningcss-wasm/lightningcss_node.wasm. Is that going to be too big?

😱 That is pretty massive. We're just starting to dig into performance and SEO issues with the current gateway and VM. A 10.5MB service worker on top of everything makes me a bit nervous.

I'll share any other alternatives that pop up on my radar as I come across them.

andy-haynes commented 4 months ago

I mentioned this in a separate issue but SASS apparently has an in-browser parser. I'm pretty ignorant of the difference in coverage though or whether that's a viable/palatable option.

Another option might be to fork and compile the LightningCSS WASM with some trimmed down functionality, e.g. without filesystem operations.

andy-haynes commented 4 months ago

The WASM in the Vercel build weighs in at 2.4MB. I'm assuming there's some kind of linking going on as part of the bundling that drops most of that 10.5MB but I haven't looked into it.