Skip to content

Commit

Permalink
Improve Node file load speed.
Browse files Browse the repository at this point in the history
  • Loading branch information
nex3 committed Feb 3, 2017
1 parent d9ef7d0 commit d513692
Show file tree
Hide file tree
Showing 8 changed files with 56 additions and 43 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,8 @@

* Error out if a function is passed an unknown named parameter.

* Improve the speed of loading large files on Node.

## 1.0.0-alpha.8

* Add the `content-exists()` function.
Expand Down
5 changes: 3 additions & 2 deletions lib/sass.dart
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,9 @@
import 'package:path/path.dart' as p;

import 'src/ast/sass.dart';
import 'src/exception.dart';
import 'src/io.dart';
import 'src/sync_package_resolver.dart';
import 'src/utils.dart';
import 'src/visitor/perform.dart';
import 'src/visitor/serialize.dart';

Expand All @@ -23,7 +24,7 @@ import 'src/visitor/serialize.dart';
/// Finally throws a [SassException] if conversion fails.
String render(String path,
{bool color: false, SyncPackageResolver packageResolver}) {
var contents = readSassFile(path);
var contents = readFile(path);
var url = p.toUri(path);
var sassTree = p.extension(path) == '.sass'
? new Stylesheet.parseSass(contents, url: url, color: color)
Expand Down
2 changes: 1 addition & 1 deletion lib/src/executable.dart
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ Future<String> _loadVersion() async {

var libDir =
p.fromUri(await Isolate.resolvePackageUri(Uri.parse('package:sass/')));
var pubspec = readFileAsString(p.join(libDir, '..', 'pubspec.yaml'));
var pubspec = readFile(p.join(libDir, '..', 'pubspec.yaml'));
return pubspec
.split("\n")
.firstWhere((line) => line.startsWith('version: '))
Expand Down
10 changes: 5 additions & 5 deletions lib/src/io/interface.dart
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ class Stderr {
void flush() {}
}

/// An error thrown by [readFileAsBytes] and [readFileAsString].
/// An error thrown by [readFile].
class FileSystemException {
String get message => null;
}
Expand All @@ -28,11 +28,11 @@ Stderr get stderr => null;
/// Returns whether or not stdout is connected to an interactive terminal.
bool get hasTerminal => false;

/// Reads the file at [path] as a list of bytes.
List<int> readFileAsBytes(String path) => null;

/// Reads the file at [path] as a UTF-8 encoded string.
String readFileAsString(String path) => null;
///
/// Throws a [FileSystemException] if reading fails, and a [SassException] if
/// the file isn't valid UTF-8.
String readFile(String path) => null;

/// Returns whether a file at [path] exists.
bool fileExists(String path) => null;
Expand Down
25 changes: 22 additions & 3 deletions lib/src/io/node.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,14 @@
// MIT-style license that can be found in the LICENSE file or at
// https://opensource.org/licenses/MIT.

import 'dart:convert';
import 'dart:typed_data';

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

import '../exception.dart';

@JS()
class _FS {
Expand Down Expand Up @@ -51,14 +56,28 @@ external _FS _require(String name);

final _fs = _require("fs");

List<int> readFileAsBytes(String path) => _readFile(path) as Uint8List;
String readFile(String path) {
// TODO(nweiz): explicitly decode the bytes as UTF-8 like we do in the VM when
// it doesn't cause a substantial performance degradation for large files. See
// also dart-lang/sdk#25377.
var contents = _readFile(path, 'utf8');
if (!contents.contains("�")) return contents;

var sourceFile = new SourceFile(contents, url: p.toUri(path));
for (var i = 0; i < contents.length; i++) {
if (contents.codeUnitAt(i) != 0xFFFD) continue;
throw new SassException(
"Invalid UTF-8.", sourceFile.location(i).pointSpan());
}

String readFileAsString(String path) => _readFile(path, 'utf8') as String;
// This should be unreachable.
return string;
}

/// Wraps `fs.readFileSync` to throw a [FileSystemException].
_readFile(String path, [String encoding]) {
try {
return _fs.readFileSync(path);
return _fs.readFileSync(path, encoding);
} catch (error) {
throw new FileSystemException._(_cleanErrorMessage(error as _SystemError));
}
Expand Down
25 changes: 22 additions & 3 deletions lib/src/io/vm.dart
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,28 @@ io.Stdout get stderr => io.stderr;

bool get hasTerminal => io.stdout.hasTerminal;

List<int> readFileAsBytes(String path) => new io.File(path).readAsBytesSync();

String readFileAsString(String path) => new io.File(path).readAsStringSync();
String readFile(String path) {
var bytes = readFile(path);

try {
return UTF8.decode(bytes);
} on FormatException {
var decoded = UTF8.decode(bytes, allowMalformed: true);
var sourceFile = new SourceFile(decoded, url: p.toUri(path));

// TODO(nweiz): Use [FormatException.offset] instead when
// dart-lang/sdk#28293 is fixed.
for (var i = 0; i < bytes.length; i++) {
if (decoded.codeUnitAt(i) != 0xFFFD) continue;
throw new SassException(
"Invalid UTF-8.", sourceFile.location(i).pointSpan());
}

// This should be unreachable, but we'll rethrow the original exception just
// in case.
rethrow;
}
}

bool fileExists(String path) => new io.File(path).existsSync();

Expand Down
28 changes: 0 additions & 28 deletions lib/src/utils.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,16 +3,13 @@
// https://opensource.org/licenses/MIT.

import 'dart:collection';
import 'dart:convert';
import 'dart:math' as math;

import 'package:charcode/charcode.dart';
import 'package:collection/collection.dart';
import 'package:path/path.dart' as p;
import 'package:source_span/source_span.dart';

import 'ast/node.dart';
import 'exception.dart';
import 'io.dart';
import 'util/character.dart';

Expand Down Expand Up @@ -257,31 +254,6 @@ List/*<T>*/ longestCommonSubsequence/*<T>*/(
}
}

/// Reads a Sass source file from diskx, and throws a [SassException] if UTF-8
/// decoding fails.
String readSassFile(String path) {
var bytes = readFileAsBytes(path);

try {
return UTF8.decode(bytes);
} on FormatException {
var decoded = UTF8.decode(bytes, allowMalformed: true);
var sourceFile = new SourceFile(decoded, url: p.toUri(path));

// TODO(nweiz): Use [FormatException.offset] instead when
// dart-lang/sdk#28293 is fixed.
for (var i = 0; i < bytes.length; i++) {
if (decoded.codeUnitAt(i) != 0xFFFD) continue;
throw new SassException(
"Invalid UTF-8.", sourceFile.location(i).pointSpan());
}

// This should be unreachable, but we'll rethrow the original exception just
// in case.
rethrow;
}
}

/// Prints a warning to standard error, associated with [span].
///
/// If [color] is `true`, this uses terminal colors.
Expand Down
2 changes: 1 addition & 1 deletion lib/src/visitor/perform.dart
Original file line number Diff line number Diff line change
Expand Up @@ -636,7 +636,7 @@ class _PerformVisitor
return _importedFiles.putIfAbsent(path, () {
String contents;
try {
contents = readSassFile(path);
contents = readFile(path);
} on SassException catch (error) {
var frames = _stack.toList()..add(_stackFrame(import.span));
throw new SassRuntimeException(
Expand Down

0 comments on commit d513692

Please sign in to comment.