Skip to content

Commit

Permalink
Fix crash in browser when running alongside NextJS (#2114)
Browse files Browse the repository at this point in the history
* Fix crash in browser when running alongside NextJS

Fixes #2113

* update sass_api pubspec
  • Loading branch information
Goodwine authored Oct 10, 2023
1 parent 887c511 commit c62fe6a
Show file tree
Hide file tree
Showing 18 changed files with 62 additions and 70 deletions.
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
Loading

0 comments on commit c62fe6a

Please sign in to comment.