惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

爱范儿
爱范儿
博客园_首页
W
WeLiveSecurity
S
Secure Thoughts
S
Security @ Cisco Blogs
Recent Commits to openclaw:main
Recent Commits to openclaw:main
Hugging Face - Blog
Hugging Face - Blog
www.infosecurity-magazine.com
www.infosecurity-magazine.com
H
Hacker News: Front Page
Project Zero
Project Zero
cs.CV updates on arXiv.org
cs.CV updates on arXiv.org
U
Unit 42
N
News and Events Feed by Topic
N
News and Events Feed by Topic
Hacker News - Newest:
Hacker News - Newest: "LLM"
Forbes - Security
Forbes - Security
T
Tor Project blog
I
Intezer
B
Blog
F
Full Disclosure
Security Archives - TechRepublic
Security Archives - TechRepublic
F
Fortinet All Blogs
Schneier on Security
Schneier on Security
T
Threat Research - Cisco Blogs
AI
AI
Google DeepMind News
Google DeepMind News
L
LINUX DO - 最新话题
Cloudbric
Cloudbric
L
Lohrmann on Cybersecurity
WordPress大学
WordPress大学
博客园 - 聂微东
雷峰网
雷峰网
P
Privacy International News Feed
让小产品的独立变现更简单 - ezindie.com
让小产品的独立变现更简单 - ezindie.com
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
PCI Perspectives
PCI Perspectives
Y
Y Combinator Blog
Spread Privacy
Spread Privacy
Simon Willison's Weblog
Simon Willison's Weblog
罗磊的独立博客
Vercel News
Vercel News
A
Arctic Wolf
The Register - Security
The Register - Security
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Microsoft Azure Blog
Microsoft Azure Blog
H
Heimdal Security Blog
Know Your Adversary
Know Your Adversary
P
Proofpoint News Feed
C
Cybersecurity and Infrastructure Security Agency CISA
P
Proofpoint News Feed

Sass Blog

New JS API Release Candidate is Live Sass: Request for Comments: New JS API Request for Comments: First-Class Calc Sass: LibSass is Deprecated Request for Comments: HWB Functions
Sass: The Discontinuation of node-fibers
Natalie Weiz · 2021-03-27 · via Sass Blog

Posted 26 March 2021 by Natalie Weizenbaum

We have recently received the unfortunate but not entirely surprising news that the node-fibers package has reached its end-of-life and will not be updated for compatibility with Node 16. Dart Sass has historically allowed JavaScript users to pass in node-fibers to improve the performance of the asynchronous render() method, but going forward this will unfortunately no longer be an option in Node 16 and on.

There are a number of alternative options for reclaiming this lost performance, some of them which are available today, some which are in development, and some which are theoretical but could be made real with pull requests from users like you. Sadly, none of the options that are ready today are drop-in solutions with the same level of ease-of-use as node-fibers, so if that performance is crucial to you we recommend staying on Node 14 for the time being.

What Happened?What Happened? permalink

In order to understand how we got here, it’s important to know two pieces of history. First, why does Dart Sass use node-fibers in the first place? And second, why is node-fibers dying?

This section is fairly technical, so feel free to skip ahead if you don’t care about the gory details.

Fibers in SassFibers in Sass permalink

Dart Sass inherited its JavaScript API from the now-deprecated Node Sass. This API has two main functions for compiling Sass files: renderSync() which synchronously returned the compiled CSS, and render() which instead takes a callback to which it passes the compiled CSS asynchronously. Only render() allowed asynchronous plugins, including widely-used importers such as webpack’s sass-loader, so render() became very widely used in practice.

For Node Sass, the performance difference between render() and renderSync() was negligible, because it was built on C++ code which had few restrictions on how it handled asynchrony. However, Dart Sass runs as pure JavaScript, which makes it subject to JavaScript’s strict async rules. Asynchrony in JavaScript is contagious, which means that if any function (such as an importer plugin) is asynchronous, then everything that calls it must be asynchronous, and so on until the entire program is asynchronous.

And asynchrony in JavaScript isn’t free. Every asynchronous function call has to allocate callbacks, store them somewhere, and take a trip back to the event loop before invoking those callbacks, and that all takes time. In fact, it takes enough time that the asynchronous render() in Dart Sass tends to be 2-3x slower than renderSync().

Enter fibers. Fibers are a very cool concept, available in languages like Ruby and C++, that give the programmer more control over asynchronous functions. They can even allow a chunk of synchronous code (such as the Sass compiler) to call asynchronous callbacks (such as the webpack plugin). The node-fibers package did some arcane magick with the V8 virtual machine to implement Fibers in JavaScript, which allowed Dart Sass to use the fast synchronous code to implement the asynchronous render() API. And for a time, it was great.

The Death of FibersThe Death of Fibers permalink

Unfortunately, the arcane magick that node-fibers used involved accessing some parts of V8 that were not officially part of its public API. There was no guarantee that the interfaces they were using would stay the same from release to release, and indeed they tended to change fairly regularly. For a long time, those changes were small enough that it was possible to release a new version of node-fibers that supported them, but with Node.js 16 the luck ran out.

The latest version of V8 involves some major overhauls to its internals. These will eventually allow it to implement some cool improvements, so its hard to begrudge, but a side effect is that the APIs node-fibers was using are completely gone without an obvious replacement. This is no one’s fault: since those interfaces weren’t part of V8’s public API, they were under no obligation to keep them stable. Sometimes in software that’s just the way things go.

Reclaiming PerformanceReclaiming Performance permalink

There are a few options for getting back the performance that’s lost by no longer being able to pass node-fibers to sass.render(). In order from nearest to longest term:

Avoid Asynchronous PluginsAvoid Asynchronous Plugins permalink

This is something you can do today. If it’s at all possible to make the plugins you pass in to Sass synchronous, you can use the renderSync() method which doesn’t need fibers to go fast. This may require rewriting some existing plugins, but it will pay dividends immediately.

Embedded Dart SassEmbedded Dart Sass permalink

While it’s not ready for prime-time yet, the Sass team is working on a project called "embedded Dart Sass". This involves running Dart Sass as a subprocess, rather than a library, and communicating with it using a special protocol. This provides several important improvements over the existing alternatives:

  • Unlike running sass from the command line, this will still work with plugins like the webpack importer. In fact, we plan to match the existing JavaScript API as closely as possible. This will probably run asynchronous plugins even faster than synchronous ones.

  • Unlike the existing JS-compiled version, this will use the Dart VM. Due to the more static nature of the Dart language, the Dart VM runs Sass substantially faster than Node.js, which will provide about a 2x speed improvement for large stylesheets.

The Node.js host for Embedded Sass is still in active development, but there’s a beta release available (with minimal features) if you want to kick the tires.

Worker ThreadsWorker Threads permalink

We’ve explored the possibility of running the pure-JS Dart Sass in a Node.js worker thread. Worker threads work a bit like fibers in that they make it possible for synchronous code to wait for asynchronous callbacks to run. Unfortunately, they’re also extremely restrictive about what sorts of information can be passed across the thread boundary, which makes it much harder to use them to wrap a complex API like Sass’s.

At the moment, the Sass team is focused on Embedded Sass, so we don’t have the spare bandwidth to dive into worker threads as an alternative. That said, we’d be happy to help a motivated user implement this. If you’re interested, follow up on the GitHub issue!

Reanimating node-fibersReanimating node-fibers permalink

There’s one other potential solution, although it would take true dedication to turn into reality. It would in principle be possible to add a new API to V8 that would officially support the hooks node-fibers needs to do its good work. This would allow the package to return gloriously to life and Sass to make render() fast on into the future.

The Sass team has contacted both the V8 team and the owner of node-fibers, and both of them are amenable to this idea in principle. While neither one has the time to see it through to completion themselves, they’ve expressed willingness to help an engineer who’s willing to give it a shot.

This isn’t a contribution for the faint of heart, though: it requires knowledge of C++, a willingness to learn at least the basics of the node-fibers codebase and V8’s isolate APIs, and skills in both API design and human interaction to negotiate a stable API that will meet the needs of node-fibers and that the V8 team feels comfortable committing to maintain. But if you’re interested, please don’t hesitate to reach out!