sass / dart-sass

The reference implementation of Sass, written in Dart.
https://sass-lang.com/dart-sass
MIT License
3.96k stars 360 forks source link

Running Dart Sass in QuickJS? #2212

Closed wch closed 6 months ago

wch commented 7 months ago

I'm not sure where the best place is to ask this question, so I thought I'd open an issue here.

I'm trying to run Dart Sass using QuickJS. I'm currently trying to a get very minimal program running:

import * as sass from "./sass.default.js";

console.log(sass.info);

console.log(1);

const res = sass.compileString(`
.box {
  width: 10px + 15px;
}
`)

console.log(2);

console.log(res);

This is using the browser build of sass.

When I run this with qjs --module 00test.js it prints out sass.info, but then hangs while running sass.compileString(), using 100% CPU:

❯ qjs --module 00test.js       
dart-sass   1.74.1  (Sass Compiler) [Dart]
dart2js 3.3.3   (Dart Compiler) [Dart]
1
^C

Any ideas why this is happening, and if it is feasible to make it work?

For some context, I help maintain the R sass package. It currently uses libsass, but we want to migrate away from it because it is deprecated. I would like to be able to run Dart Sass using QuickJS because QuickJS is simple to build and call from C.

wch commented 6 months ago

One more thing I forgot to mention: this is a gist where I had put my attempt to run Dart Sass in QuickJS. If you just clone the gist and run the command in the README, it should reproduce the issue: https://gist.github.com/wch/eb453b73981a7f5715903992accca35e

nex3 commented 6 months ago

I'm sorry, I'm not sure what's going on here. It's possible that some of the environment sniffing Sass does to try to determine if it's running in a browser environment is returning inaccurate results here, but it's hard to know for sure without more information. If you can debug into the compiled JS code and figure out where it's stalling out, that would help in figuring out what's going on in more detail.

wch commented 6 months ago

Thanks for the suggestion. I dug into it and found a bug in QuickJS! https://github.com/bellard/quickjs/issues/275

The issue is that when a for loop has a label for the body, a break is supposed to exit the loop, but in QuickJS, it does not. For example, this is supposed to just print 1 and then break out of the loop, but with QuickJS, it prints 1, 2, 3, 4.

for (var i=0; i<4; i++)
label: {
  console.log(i);
  break;
}

This code pattern in question occurs in the sass.dart.js file in A.StylesheetParser0.almostAnyValue$1$omitComments(), and because of the bug in QuickJS, it gets stuck in an infinite loop.

nex3 commented 6 months ago

Thanks for digging that up! I'm going to close this out since it's a bug in quickjs.