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

Fix crash in browser when running alongside NextJS #2114

Merged
merged 2 commits into from
Oct 10, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 1.69.2

### JS API

* Fix a bug where Sass crashed when running in the browser if there was a global
variable named `process`.

## 1.69.1

* No user-visible changes.
Expand Down
1 change: 1 addition & 0 deletions lib/src/async_compile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

import 'dart:convert';

import 'package:cli_pkg/js.dart';
import 'package:path/path.dart' as p;

import 'ast/sass.dart';
Expand Down
1 change: 1 addition & 0 deletions lib/src/async_import_cache.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

import 'package:cli_pkg/js.dart';
import 'package:collection/collection.dart';
import 'package:meta/meta.dart';
import 'package:package_config/package_config_types.dart';
Expand Down
3 changes: 2 additions & 1 deletion lib/src/compile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,15 @@
// DO NOT EDIT. This file was generated from async_compile.dart.
// See tool/grind/synchronize.dart for details.
//
// Checksum: c2982db43bcd56f81cab3f51b5669e0edd3cfafb
// Checksum: 5178e366228bde7854df12221393857bb3022628
//
// ignore_for_file: unused_import

export 'async_compile.dart';

import 'dart:convert';

import 'package:cli_pkg/js.dart';
import 'package:path/path.dart' as p;

import 'ast/sass.dart';
Expand Down
2 changes: 1 addition & 1 deletion lib/src/deprecation.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

import 'package:cli_pkg/js.dart';
import 'package:collection/collection.dart';
import 'package:pub_semver/pub_semver.dart';

import 'io.dart';
import 'util/nullable.dart';

/// A deprecated feature in the language.
Expand Down
3 changes: 2 additions & 1 deletion lib/src/import_cache.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,11 @@
// DO NOT EDIT. This file was generated from async_import_cache.dart.
// See tool/grind/synchronize.dart for details.
//
// Checksum: ff52307a3bc93358ddc46f1e76120894fa3e071f
// Checksum: 342e907cf10e1dd80d7045fc32db43c74376654e
//
// ignore_for_file: unused_import

import 'package:cli_pkg/js.dart';
import 'package:collection/collection.dart';
import 'package:meta/meta.dart';
import 'package:package_config/package_config_types.dart';
Expand Down
9 changes: 0 additions & 9 deletions lib/src/io/interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,6 @@ bool get isMacOS => throw '';
/// Returns whether or not stdout is connected to an interactive terminal.
bool get hasTerminal => throw '';

/// Whether we're running as JS (browser or Node.js).
const bool isJS = false;

/// Whether we're running as Node.js (not browser or Dart VM).
bool get isNode => throw '';

/// Whether we're running as browser (not Node.js or Dart VM).
bool get isBrowser => throw '';

/// Whether this process is connected to a terminal that supports ANSI escape
/// sequences.
bool get supportsAnsiEscapes => throw '';
Expand Down
69 changes: 30 additions & 39 deletions lib/src/io/js.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@

import 'dart:async';
import 'dart:convert';
import 'dart:js_util';

import 'package:cli_pkg/js.dart';
import 'package:js/js.dart';
import 'package:node_interop/fs.dart';
import 'package:node_interop/node_interop.dart' hide process;
import 'package:node_interop/util.dart';
import 'package:path/path.dart' as p;
import 'package:source_span/source_span.dart';
import 'package:watcher/watcher.dart';
Expand All @@ -17,7 +18,12 @@ import '../exception.dart';
import '../js/chokidar.dart';

@JS('process')
external final Process? process; // process is null in the browser
external final Process? _nodeJsProcess; // process is null in the browser

/// The Node.JS [Process] global variable.
///
/// This value is `null` when running the script is not run from Node.JS
Process? get _process => isNodeJs ? _nodeJsProcess : null;

class FileSystemException {
final String message;
Expand All @@ -29,23 +35,23 @@ class FileSystemException {
}

void safePrint(Object? message) {
if (process case var process?) {
if (_process case var process?) {
process.stdout.write("${message ?? ''}\n");
} else {
console.log(message ?? '');
}
}

void printError(Object? message) {
if (process case var process?) {
if (_process case var process?) {
process.stderr.write("${message ?? ''}\n");
} else {
console.error(message ?? '');
}
}

String readFile(String path) {
if (!isNode) {
if (!isNodeJs) {
throw UnsupportedError("readFile() is only supported on Node.js");
}
// TODO(nweiz): explicitly decode the bytes as UTF-8 like we do in the VM when
Expand All @@ -69,23 +75,23 @@ Object? _readFile(String path, [String? encoding]) =>
_systemErrorToFileSystemException(() => fs.readFileSync(path, encoding));

void writeFile(String path, String contents) {
if (!isNode) {
if (!isNodeJs) {
throw UnsupportedError("writeFile() is only supported on Node.js");
}
return _systemErrorToFileSystemException(
() => fs.writeFileSync(path, contents));
}

void deleteFile(String path) {
if (!isNode) {
if (!isNodeJs) {
throw UnsupportedError("deleteFile() is only supported on Node.js");
}
return _systemErrorToFileSystemException(() => fs.unlinkSync(path));
}

Future<String> readStdin() async {
var process_ = process;
if (process_ == null) {
var process = _process;
if (process == null) {
throw UnsupportedError("readStdin() is only supported on Node.js");
}
var completer = Completer<String>();
Expand All @@ -96,15 +102,15 @@ Future<String> readStdin() async {
});
// Node defaults all buffers to 'utf8'.
var sink = utf8.decoder.startChunkedConversion(innerSink);
process_.stdin.on('data', allowInterop(([Object? chunk]) {
process.stdin.on('data', allowInterop(([Object? chunk]) {
sink.add(chunk as List<int>);
}));
process_.stdin.on('end', allowInterop(([Object? _]) {
process.stdin.on('end', allowInterop(([Object? _]) {
// Callback for 'end' receives no args.
assert(_ == null);
sink.close();
}));
process_.stdin.on('error', allowInterop(([Object? e]) {
process.stdin.on('error', allowInterop(([Object? e]) {
printError('Failed to read from stdin');
printError(e);
completer.completeError(e!);
Expand All @@ -121,7 +127,7 @@ String _cleanErrorMessage(JsSystemError error) {
}

bool fileExists(String path) {
if (!isNode) {
if (!isNodeJs) {
throw UnsupportedError("fileExists() is only supported on Node.js");
}
return _systemErrorToFileSystemException(() {
Expand All @@ -142,7 +148,7 @@ bool fileExists(String path) {
}

bool dirExists(String path) {
if (!isNode) {
if (!isNodeJs) {
throw UnsupportedError("dirExists() is only supported on Node.js");
}
return _systemErrorToFileSystemException(() {
Expand All @@ -163,7 +169,7 @@ bool dirExists(String path) {
}

void ensureDir(String path) {
if (!isNode) {
if (!isNodeJs) {
throw UnsupportedError("ensureDir() is only supported on Node.js");
}
return _systemErrorToFileSystemException(() {
Expand All @@ -180,7 +186,7 @@ void ensureDir(String path) {
}

Iterable<String> listDir(String path, {bool recursive = false}) {
if (!isNode) {
if (!isNodeJs) {
throw UnsupportedError("listDir() is only supported on Node.js");
}
return _systemErrorToFileSystemException(() {
Expand All @@ -202,15 +208,15 @@ Iterable<String> listDir(String path, {bool recursive = false}) {
}

DateTime modificationTime(String path) {
if (!isNode) {
if (!isNodeJs) {
throw UnsupportedError("modificationTime() is only supported on Node.js");
}
return _systemErrorToFileSystemException(() =>
DateTime.fromMillisecondsSinceEpoch(fs.statSync(path).mtime.getTime()));
}

String? getEnvironmentVariable(String name) {
var env = process?.env;
var env = _process?.env;
return env == null ? null : getProperty(env as Object, name) as String?;
}

Expand All @@ -229,36 +235,21 @@ T _systemErrorToFileSystemException<T>(T callback()) {
/// from `node_interop` declares `isTTY` as always non-nullably available, but
/// in practice it's undefined if stdout isn't a TTY.
/// See: https://github.com/pulyaevskiy/node-interop/issues/93
bool get hasTerminal => process?.stdout.isTTY == true;

bool get isWindows => process?.platform == 'win32';

bool get isMacOS => process?.platform == 'darwin';

const bool isJS = true;

/// The fs module object, used to check whether this has been loaded as Node.
///
/// It's safest to check for a library we load in manually rather than one
/// that's ambiently available so that we don't get into a weird state in
/// environments like VS Code that support some Node.js libraries but don't load
/// Node.js entrypoints for dependencies.
@JS('fs')
external final Object? _fsNullable;
bool get hasTerminal => _process?.stdout.isTTY == true;

bool get isNode => _fsNullable != null;
bool get isWindows => _process?.platform == 'win32';

bool get isBrowser => isJS && !isNode;
bool get isMacOS => _process?.platform == 'darwin';

// Node seems to support ANSI escapes on all terminals.
bool get supportsAnsiEscapes => hasTerminal;

int get exitCode => process?.exitCode ?? 0;
int get exitCode => _process?.exitCode ?? 0;

set exitCode(int code) => process?.exitCode = code;
set exitCode(int code) => _process?.exitCode = code;

Future<Stream<WatchEvent>> watchDir(String path, {bool poll = false}) {
if (!isNode) {
if (!isNodeJs) {
throw UnsupportedError("watchDir() is only supported on Node.js");
}
var watcher = chokidar.watch(
Expand Down
6 changes: 0 additions & 6 deletions lib/src/io/vm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,6 @@ bool get isMacOS => io.Platform.isMacOS;

bool get hasTerminal => io.stdout.hasTerminal;

const bool isJS = false;

bool get isNode => false;

bool get isBrowser => false;

bool get supportsAnsiEscapes {
if (!hasTerminal) return false;

Expand Down
4 changes: 2 additions & 2 deletions lib/src/js/compile.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import 'utils.dart';
/// See https://github.com/sass/sass/spec/tree/main/js-api/compile.d.ts for
/// details.
NodeCompileResult compile(String path, [CompileOptions? options]) {
if (!isNode) {
if (!isNodeJs) {
jsThrow(JsError("The compile() method is only available in Node.js."));
}
var color = options?.alertColor ?? hasTerminal;
Expand Down Expand Up @@ -88,7 +88,7 @@ NodeCompileResult compileString(String text, [CompileStringOptions? options]) {
/// See https://github.com/sass/sass/spec/tree/main/js-api/compile.d.ts for
/// details.
Promise compileAsync(String path, [CompileOptions? options]) {
if (!isNode) {
if (!isNodeJs) {
jsThrow(JsError("The compileAsync() method is only available in Node.js."));
}
var color = options?.alertColor ?? hasTerminal;
Expand Down
4 changes: 2 additions & 2 deletions lib/src/js/legacy.dart
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ import 'utils.dart';
/// [render]: https://github.com/sass/node-sass#options
void render(
RenderOptions options, void callback(Object? error, RenderResult? result)) {
if (!isNode) {
if (!isNodeJs) {
jsThrow(JsError("The render() method is only available in Node.js."));
}
if (options.fiber case var fiber?) {
Expand Down Expand Up @@ -118,7 +118,7 @@ Future<RenderResult> _renderAsync(RenderOptions options) async {
///
/// [render]: https://github.com/sass/node-sass#options
RenderResult renderSync(RenderOptions options) {
if (!isNode) {
if (!isNodeJs) {
jsThrow(JsError("The renderSync() method is only available in Node.js."));
}
try {
Expand Down
2 changes: 1 addition & 1 deletion lib/src/value/color.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,13 @@

import 'dart:math' as math;

import 'package:cli_pkg/js.dart';
import 'package:meta/meta.dart';
import 'package:source_span/source_span.dart';

import '../deprecation.dart';
import '../evaluation_context.dart';
import '../exception.dart';
import '../io.dart';
import '../util/number.dart';
import '../value.dart';
import '../visitor/interface/value.dart';
Expand Down
2 changes: 1 addition & 1 deletion lib/src/visitor/async_evaluate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import 'dart:async';
import 'dart:collection';
import 'dart:math' as math;

import 'package:cli_pkg/js.dart';
import 'package:charcode/charcode.dart';
import 'package:collection/collection.dart';
import 'package:path/path.dart' as p;
Expand Down Expand Up @@ -33,7 +34,6 @@ import '../functions/meta.dart' as meta;
import '../importer.dart';
import '../importer/legacy_node.dart';
import '../interpolation_map.dart';
import '../io.dart';
import '../logger.dart';
import '../module.dart';
import '../module/built_in.dart';
Expand Down
4 changes: 2 additions & 2 deletions lib/src/visitor/evaluate.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
// DO NOT EDIT. This file was generated from async_evaluate.dart.
// See tool/grind/synchronize.dart for details.
//
// Checksum: 358960b72c6e4f48d3e2e9d52be3abbe9e8b5a9f
// Checksum: 58ef9912c6a9d9cfe9c3f5d991f625ab1a627e7a
//
// ignore_for_file: unused_import

Expand All @@ -15,6 +15,7 @@ export 'async_evaluate.dart' show EvaluateResult;
import 'dart:collection';
import 'dart:math' as math;

import 'package:cli_pkg/js.dart';
import 'package:charcode/charcode.dart';
import 'package:collection/collection.dart';
import 'package:path/path.dart' as p;
Expand Down Expand Up @@ -42,7 +43,6 @@ import '../functions/meta.dart' as meta;
import '../importer.dart';
import '../importer/legacy_node.dart';
import '../interpolation_map.dart';
import '../io.dart';
import '../logger.dart';
import '../module.dart';
import '../module/built_in.dart';
Expand Down
4 changes: 4 additions & 0 deletions pkg/sass_api/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
## 9.2.2

* No user-visible changes.

## 9.2.1

* No user-visible changes.
Expand Down