Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for running in the browser #1895

Merged
merged 64 commits into from May 19, 2023
Merged

Add support for running in the browser #1895

merged 64 commits into from May 19, 2023

Conversation

jerivas
Copy link
Contributor

@jerivas jerivas commented Feb 24, 2023

WIP, but this gets us closer to fixing #25

lib/src/io/node.dart Outdated Show resolved Hide resolved
pubspec.yaml Outdated Show resolved Hide resolved
@jerivas

This comment was marked as outdated.

@nex3
Copy link
Contributor

nex3 commented Feb 24, 2023

I may have mispoken on the call earlier—compile{,ToResult}{,Async} are all fundamentally not going to work on the web. They take a filesystem path as a parameter, not a URL, and there's no real way to make that make sense in a web context. They should all just throw errors indicating that they're not supported and users should use compileStringToResult{,Async} instead.

tool/grind.dart Outdated Show resolved Hide resolved
lib/src/io/node.dart Outdated Show resolved Hide resolved
lib/src/io/node.dart Outdated Show resolved Hide resolved
lib/src/io/node.dart Show resolved Hide resolved
lib/src/io/node.dart Outdated Show resolved Hide resolved
lib/src/io/node.dart Outdated Show resolved Hide resolved
@jerivas

This comment was marked as outdated.

Copy link
Contributor Author

@jerivas jerivas left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added some basic browsers tests. Most of them are already passing, but I'm having trouble witha few things

.github/workflows/ci.yml Outdated Show resolved Hide resolved
test/browser_test.dart Outdated Show resolved Hide resolved
test/browser_test.dart Outdated Show resolved Hide resolved
pubspec.yaml Outdated Show resolved Hide resolved
Copy link
Contributor

@jgerigmeyer jgerigmeyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nex3 @jerivas I think this is ready for another (close to final?) round of review. With the changes in 4cb6b77 to enable logging, and the changes in https://github.com/sass/dart-sass/pull/1895/files/4cb6b772f55c82ca083dffcd786ead16580bf6dd..ae772f5f66fb5096ce299485375cf79f4e0f189d to run the JS API spec tests as part of CI, I'm not aware of any further items on the to-do list?


- name: Check out sass-spec
uses: sass/clone-linked-repo@v1
# TODO update this to use "sass/sass-spec" directly
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Remember to update this before merging.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you send a PR to the official sass-spec repo, you can link to it in the PR description here and this PR will automatically run against that one.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed.

Comment on lines 46 to 50
if (_stderr == null) {
console.error("${object ?? ''}\n");
} else {
_stderr?.write("${object ?? ''}\n");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This works (as in, it does log), but I think it's probably not ideal?

Screenshot 2023-05-03 at 9 00 11 AM

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a better solution than stubbing out stderr in the browser might be to have a separate BrowserLogger that directly calls console.error().

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nex3 What do you think of the revised approach in d30dd42?

Screenshot 2023-05-15 at 3 01 24 PM

Copy link
Contributor

@nex3 nex3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Other than the logger stuff, this is looking very good!


- name: Check out sass-spec
uses: sass/clone-linked-repo@v1
# TODO update this to use "sass/sass-spec" directly
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If you send a PR to the official sass-spec repo, you can link to it in the PR description here and this PR will automatically run against that one.

Comment on lines 46 to 50
if (_stderr == null) {
console.error("${object ?? ''}\n");
} else {
_stderr?.write("${object ?? ''}\n");
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think a better solution than stubbing out stderr in the browser might be to have a separate BrowserLogger that directly calls console.error().

void write(Object object) => _stderr.write(object.toString());
void write(Object object) {
if (_stderr == null) {
console.error(object.toString());
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note that stderr.write() doesn't append a newline, while console.error() does. If we do decide we need to fake stderr in the browser, we'll need to build up a buffer here and only emit it once we hit an actual newline.

@jerivas jerivas requested a review from nex3 May 16, 2023 15:51
* main: (162 commits)
  Move source and test files to namespaced subdirectories
  Update Dart Sass version and release
  Update Dart Sass version and release
  Update Dart Sass version and release
  Update Dart Sass version and release
  Update Dart Sass version and release
  Update Dart Sass version and release
  Revert "Remove workaround for dart-lang/setup-dart#59 (sass#151)" (sass#153)
  Update Dart Sass version and release
  Update Dart Sass version and release
  Remove workaround for dart-lang/setup-dart#59 (sass#151)
  Update Dart Sass version and release
  Update Dart Sass version and release
  Fix qemu releases (sass#149)
  Update Dart Sass version and release
  Bump sass_api from 4.2.1 to 5.0.0 (sass#143)
  Bump meta from 1.8.0 to 1.9.0 (sass#144)
  Bump grinder from 0.9.2 to 0.9.3 (sass#145)
  Add missing setup-dart step in qemu release (sass#147)
  Use buf instead of protoc to compile protobufs (sass#146)
  ...
Copy link
Contributor

@nex3 nex3 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few relatively small comments, but overall looks great!

Comment on lines 28 to 35
abstract class Console {
external void log(String data);
external void info(String data);
external void warn(String data);
external void error(String data);
}

Console? get console => throw '';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The IO library is really for interfaces that are shared across the VM and JS. Something like the console that's only ever available in JS should go in a separate library in lib/src/node/.

import 'package:node_interop/fs.dart';
import 'package:node_interop/node_interop.dart';
import 'package:node_interop/node_interop.dart' as n hide process;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You should only need to either import this with a prefix or hide a conflicting name, not both.

@@ -21,7 +23,12 @@ abstract class Logger {

/// Creates a logger that prints warnings to standard error, with terminal
/// colors if [color] is `true` (default `false`).
const factory Logger.stderr({bool color}) = StderrLogger;
factory Logger.stderr({bool color = false}) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately, converting a factory constructor from const to non-const is a breaking change in Dart. This means that instead of a separate BrowserLogger class, you'll need to use if (isBrowser) in StderrLogger itself. Sorry I didn't catch this earlier.

@@ -218,6 +218,54 @@ jobs:
run: npm run js-api-spec -- --sassPackage ../embedded-host-node --sassSassRepo ../language
working-directory: sass-spec

sass_spec_js_browser:
name: "JS API Tests | Pure JS | Dart ${{ matrix.dart_channel }} | Browser"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make this a little easier to differentiate in the web UI, let's make it

Suggested change
name: "JS API Tests | Pure JS | Dart ${{ matrix.dart_channel }} | Browser"
name: "JS API Tests | Browser | Dart ${{ matrix.dart_channel }}"

since "browser" implies "pure JS" anyway.

* main:
  Use the embedded protocol from the Sass language repo (sass#1966)
  Format with dart 3.0.1 (sass#1967)
  Pull more repeated GH Action tasks into sub-actions (sass#1964)
  Fix printing usage when no args provided (sass#1963)
Copy link
Contributor

@jgerigmeyer jgerigmeyer left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nex3 Ready for another round of review (564a4ce).

@@ -10,7 +10,7 @@ runs:
steps:
- uses: dart-lang/setup-dart@v1
with:
sdk: "${{ inputs.sdk }}"
sdk: "${{ inputs.dart-sdk }}"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nex3 I think this is a typo in the main branch.

@@ -9,8 +9,9 @@ import 'package:stack_trace/stack_trace.dart';
import '../io.dart';
import '../logger.dart';
import '../utils.dart';
import '../node/console_stub.dart' if (dart.library.js) '../node/console.dart';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nex3 Is there a better way to do this that still avoids Dart library 'dart:js_util' is not available on this platform errors?

Copy link
Contributor

@nex3 nex3 May 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately no :(. The Dart VM still needs to know how to typecheck the APIs even if it won't actually run them in practice.

I think, in retrospect, that the cleanest approach here is probably to hide even more of the implementation and just expose a printError() function. I don't want to make you undo all the refactors so I've just gone and made the change myself.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@nex3 Makes sense, and LGTM! 🚀

Comment on lines 1 to 12
// Copyright 2023 Google Inc. Use of this source code is governed by an
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

abstract class Console {
external void log(String data);
external void info(String data);
external void warn(String data);
external void error(String data);
}

Console get console => throw '';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This seems a bit silly, but it doesn't seem like you can conditionally import a package without also having a fallback package.

@@ -9,8 +9,9 @@ import 'package:stack_trace/stack_trace.dart';
import '../io.dart';
import '../logger.dart';
import '../utils.dart';
import '../node/console_stub.dart' if (dart.library.js) '../node/console.dart';
Copy link
Contributor

@nex3 nex3 May 19, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Unfortunately no :(. The Dart VM still needs to know how to typecheck the APIs even if it won't actually run them in practice.

I think, in retrospect, that the cleanest approach here is probably to hide even more of the implementation and just expose a printError() function. I don't want to make you undo all the refactors so I've just gone and made the change myself.

@ntkme ntkme mentioned this pull request May 19, 2023
@nex3 nex3 merged commit cca9464 into sass:main May 19, 2023
45 checks passed
@jgerigmeyer jgerigmeyer deleted the browser branch May 19, 2023 20:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants