Skip to content
This repository has been archived by the owner on May 15, 2023. It is now read-only.

Commit

Permalink
[PROOF OF CONCEPT] Run each compilation in a separate isolate
Browse files Browse the repository at this point in the history
This structure would fix #112 and may otherwise increase the
throughput of concurrent long-running compilations. However, it also
noticeably increases the startup time of a single non-concurrent
compilation of a small file, which is currently the primary way this
package is used.
  • Loading branch information
nex3 committed Sep 27, 2022
1 parent 905fe50 commit 23d259d
Show file tree
Hide file tree
Showing 4 changed files with 331 additions and 179 deletions.
133 changes: 4 additions & 129 deletions bin/dart_sass_embedded.dart
Expand Up @@ -5,24 +5,15 @@
import 'dart:io';
import 'dart:convert';

import 'package:path/path.dart' as p;
import 'package:sass/sass.dart' as sass;
import 'package:stream_channel/stream_channel.dart';

import 'package:sass_embedded/src/dispatcher.dart';
import 'package:sass_embedded/src/embedded_sass.pb.dart';
import 'package:sass_embedded/src/function_registry.dart';
import 'package:sass_embedded/src/host_callable.dart';
import 'package:sass_embedded/src/importer/file.dart';
import 'package:sass_embedded/src/importer/host.dart';
import 'package:sass_embedded/src/logger.dart';
import 'package:sass_embedded/src/isolate_dispatcher.dart';
import 'package:sass_embedded/src/util/length_delimited_transformer.dart';
import 'package:sass_embedded/src/utils.dart';

void main(List<String> args) {
if (args.isNotEmpty) {
if (args.first == "--version") {
var response = Dispatcher.versionResponse();
var response = IsolateDispatcher.versionResponse();
response.id = 0;
stdout.writeln(
JsonEncoder.withIndent(" ").convert(response.toProto3Json()));
Expand All @@ -37,125 +28,9 @@ void main(List<String> args) {
return;
}

var dispatcher = Dispatcher(
var dispatcher = IsolateDispatcher(
StreamChannel.withGuarantees(stdin, stdout, allowSinkErrors: false)
.transform(lengthDelimited));

dispatcher.listen((request) async {
var functions = FunctionRegistry();

var style = request.style == OutputStyle.COMPRESSED
? sass.OutputStyle.compressed
: sass.OutputStyle.expanded;
var logger = Logger(dispatcher, request.id,
color: request.alertColor, ascii: request.alertAscii);

try {
var importers = request.importers.map((importer) =>
_decodeImporter(dispatcher, request, importer) ??
(throw mandatoryError("Importer.importer")));

var globalFunctions = request.globalFunctions.map((signature) {
try {
return hostCallable(dispatcher, functions, request.id, signature);
} on sass.SassException catch (error) {
throw paramsError('CompileRequest.global_functions: $error');
}
});

late sass.CompileResult result;
switch (request.whichInput()) {
case InboundMessage_CompileRequest_Input.string:
var input = request.string;
result = sass.compileStringToResult(input.source,
color: request.alertColor,
logger: logger,
importers: importers,
importer: _decodeImporter(dispatcher, request, input.importer) ??
(input.url.startsWith("file:") ? null : sass.Importer.noOp),
functions: globalFunctions,
syntax: syntaxToSyntax(input.syntax),
style: style,
url: input.url.isEmpty ? null : input.url,
quietDeps: request.quietDeps,
verbose: request.verbose,
sourceMap: request.sourceMap,
charset: request.charset);
break;

case InboundMessage_CompileRequest_Input.path:
if (request.path.isEmpty) {
throw mandatoryError("CompileRequest.Input.path");
}

try {
result = sass.compileToResult(request.path,
color: request.alertColor,
logger: logger,
importers: importers,
functions: globalFunctions,
style: style,
quietDeps: request.quietDeps,
verbose: request.verbose,
sourceMap: request.sourceMap,
charset: request.charset);
} on FileSystemException catch (error) {
return OutboundMessage_CompileResponse()
..failure = (OutboundMessage_CompileResponse_CompileFailure()
..message = error.path == null
? error.message
: "${error.message}: ${error.path}"
..span = (SourceSpan()
..start = SourceSpan_SourceLocation()
..end = SourceSpan_SourceLocation()
..url = p.toUri(request.path).toString()));
}
break;

case InboundMessage_CompileRequest_Input.notSet:
throw mandatoryError("CompileRequest.input");
}

var success = OutboundMessage_CompileResponse_CompileSuccess()
..css = result.css
..loadedUrls.addAll(result.loadedUrls.map((url) => url.toString()));

var sourceMap = result.sourceMap;
if (sourceMap != null) {
success.sourceMap = json.encode(sourceMap.toJson(
includeSourceContents: request.sourceMapIncludeSources));
}
return OutboundMessage_CompileResponse()..success = success;
} on sass.SassException catch (error) {
var formatted = withGlyphs(
() => error.toString(color: request.alertColor),
ascii: request.alertAscii);
return OutboundMessage_CompileResponse()
..failure = (OutboundMessage_CompileResponse_CompileFailure()
..message = error.message
..span = protofySpan(error.span)
..stackTrace = error.trace.toString()
..formatted = formatted);
}
});
}

/// Converts [importer] into a [sass.Importer].
sass.Importer? _decodeImporter(
Dispatcher dispatcher,
InboundMessage_CompileRequest request,
InboundMessage_CompileRequest_Importer importer) {
switch (importer.whichImporter()) {
case InboundMessage_CompileRequest_Importer_Importer.path:
return sass.FilesystemImporter(importer.path);

case InboundMessage_CompileRequest_Importer_Importer.importerId:
return HostImporter(dispatcher, request.id, importer.importerId);

case InboundMessage_CompileRequest_Importer_Importer.fileImporterId:
return FileImporter(dispatcher, request.id, importer.fileImporterId);

case InboundMessage_CompileRequest_Importer_Importer.notSet:
return null;
}
dispatcher.listen();
}

0 comments on commit 23d259d

Please sign in to comment.