From c0137eb6fe7c85cea1f9c0960b2170342c6af1c4 Mon Sep 17 00:00:00 2001 From: Bee Date: Wed, 15 Jan 2020 18:10:31 -0800 Subject: [PATCH 01/12] Setup initial import of 'worker_threads' node library --- lib/src/node/worker_threads.dart | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) create mode 100644 lib/src/node/worker_threads.dart diff --git a/lib/src/node/worker_threads.dart b/lib/src/node/worker_threads.dart new file mode 100644 index 000000000..ba3f84c2c --- /dev/null +++ b/lib/src/node/worker_threads.dart @@ -0,0 +1,22 @@ +// Copyright 2017 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. + +import 'package:js/js.dart'; + +class WorkerOptions extends Object { +} + +@JS("worker_threads") +class Worker { + external Worker on(String message, Function callback); + + external factory Worker(String filename, WorkerOptions options); +} + +@JS("worker_threads") +class ParentPort { + external ParentPort postMessage(Object value, + {List transferList = const []}); +} + From ad65b61d889c87852c2bc09116c05b6445d3e21d Mon Sep 17 00:00:00 2001 From: Bee Date: Tue, 21 Jan 2020 16:01:48 -0800 Subject: [PATCH 02/12] Add worker_threads interop file and implementation Something here is not working 100%, on running render `ParentPort` is null and it should be an object if its on the worker thread. --- lib/src/node.dart | 83 ++++++++++++++++---------------- lib/src/node/worker_threads.dart | 46 +++++++++++++++--- 2 files changed, 79 insertions(+), 50 deletions(-) diff --git a/lib/src/node.dart b/lib/src/node.dart index dd202b993..3173af438 100644 --- a/lib/src/node.dart +++ b/lib/src/node.dart @@ -27,6 +27,7 @@ import 'node/render_result.dart'; import 'node/types.dart'; import 'node/value.dart'; import 'node/utils.dart'; +import 'node/worker_threads.dart'; import 'parse/scss.dart'; import 'syntax.dart'; import 'value.dart'; @@ -63,26 +64,15 @@ void main() { /// [render]: https://github.com/sass/node-sass#options void _render( RenderOptions options, void callback(JSError error, RenderResult result)) { - if (options.fiber != null) { - options.fiber.call(allowInterop(() { - try { - callback(null, _renderSync(options)); - } catch (error) { - callback(error as JSError, null); - } - return null; - })).run(); - } else { - _renderAsync(options).then((result) { - callback(null, result); - }, onError: (Object error, StackTrace stackTrace) { - if (error is SassException) { - callback(_wrapException(error), null); - } else { - callback(_newRenderError(error.toString(), status: 3), null); - } - }); - } + _renderAsync(options).then((result) { + callback(null, result); + }, onError: (Object error, StackTrace stackTrace) { + if (error is SassException) { + callback(_wrapException(error), null); + } else { + callback(_newRenderError(error.toString(), status: 3), null); + } + }); } /// Converts Sass to CSS asynchronously. @@ -90,29 +80,38 @@ Future _renderAsync(RenderOptions options) async { var start = DateTime.now(); var file = options.file == null ? null : p.absolute(options.file); CompileResult result; - if (options.data != null) { - result = await compileStringAsync(options.data, - nodeImporter: _parseImporter(options, start), - functions: _parseFunctions(options, asynch: true), - syntax: isTruthy(options.indentedSyntax) ? Syntax.sass : null, - style: _parseOutputStyle(options.outputStyle), - useSpaces: options.indentType != 'tab', - indentWidth: _parseIndentWidth(options.indentWidth), - lineFeed: _parseLineFeed(options.linefeed), - url: options.file == null ? 'stdin' : p.toUri(file).toString(), - sourceMap: _enableSourceMaps(options)); - } else if (options.file != null) { - result = await compileAsync(file, - nodeImporter: _parseImporter(options, start), - functions: _parseFunctions(options, asynch: true), - syntax: isTruthy(options.indentedSyntax) ? Syntax.sass : null, - style: _parseOutputStyle(options.outputStyle), - useSpaces: options.indentType != 'tab', - indentWidth: _parseIndentWidth(options.indentWidth), - lineFeed: _parseLineFeed(options.linefeed), - sourceMap: _enableSourceMaps(options)); + if (isMainThread == true) { + var worker = Worker(p.current, WorkerOptions(workerData: {options})); + worker.on('message', (CompileResult msg) => result = msg); + worker.on('error', (JSError error) { + jsThrow(_wrapException(error)); + }); } else { - throw ArgumentError("Either options.data or options.file must be set."); + if (options.data != null) { + result = await compileStringAsync(options.data, + nodeImporter: _parseImporter(options, start), + functions: _parseFunctions(options, asynch: true), + syntax: isTruthy(options.indentedSyntax) ? Syntax.sass : null, + style: _parseOutputStyle(options.outputStyle), + useSpaces: options.indentType != 'tab', + indentWidth: _parseIndentWidth(options.indentWidth), + lineFeed: _parseLineFeed(options.linefeed), + url: options.file == null ? 'stdin' : p.toUri(file).toString(), + sourceMap: _enableSourceMaps(options)); + } else if (options.file != null) { + result = await compileAsync(file, + nodeImporter: _parseImporter(options, start), + functions: _parseFunctions(options, asynch: true), + syntax: isTruthy(options.indentedSyntax) ? Syntax.sass : null, + style: _parseOutputStyle(options.outputStyle), + useSpaces: options.indentType != 'tab', + indentWidth: _parseIndentWidth(options.indentWidth), + lineFeed: _parseLineFeed(options.linefeed), + sourceMap: _enableSourceMaps(options)); + } else { + throw ArgumentError("Either options.data or options.file must be set."); + } + ParentPort.postMessage(result, PortOptions()); } return _newRenderResult(options, result, start); diff --git a/lib/src/node/worker_threads.dart b/lib/src/node/worker_threads.dart index ba3f84c2c..6ddea3129 100644 --- a/lib/src/node/worker_threads.dart +++ b/lib/src/node/worker_threads.dart @@ -1,22 +1,52 @@ // Copyright 2017 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. +@JS() +library worker_threads; import 'package:js/js.dart'; +import 'package:js/js_util.dart'; -class WorkerOptions extends Object { +@JS() +external Object _requireWorkerThreads(String path); + +final workers = _requireWorkerThreads("worker_threads"); + +@JS() +external Object get workerData; + +@JS() +external bool get isMainThread; + +@JS() +@anonymous +class WorkerOptions { + external factory WorkerOptions( + {List argv, + Object env, + bool eval, + List execArgv, + Object workerData}); } -@JS("worker_threads") +@JS() class Worker { - external Worker on(String message, Function callback); + external void on(String message, Function callback); - external factory Worker(String filename, WorkerOptions options); + external const factory Worker(fileName, WorkerOptions options); } -@JS("worker_threads") -class ParentPort { - external ParentPort postMessage(Object value, - {List transferList = const []}); +@JS() +@anonymous +class PortOptions { + external List get transferList; + external factory PortOptions({List transferList = const []}); } +@JS() +external ParentPort get parentPort; + +@JS() +class ParentPort { + external static void postMessage(Object message, PortOptions options); +} From 7a5c0f5ced20f0d95b9f0cb03bd2f93cdafe8050 Mon Sep 17 00:00:00 2001 From: Bee Date: Tue, 21 Jan 2020 16:06:11 -0800 Subject: [PATCH 03/12] Remove tests for fibers package --- test/node_api/importer_test.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/node_api/importer_test.dart b/test/node_api/importer_test.dart index 870ff52fd..565a20b66 100644 --- a/test/node_api/importer_test.dart +++ b/test/node_api/importer_test.dart @@ -668,6 +668,8 @@ void main() { " stdin 1:9 root stylesheet"))); }); + //TODO: Remove these tests + /******* Deprecated fibers tests group("with fibers", () { setUpAll(() { try { @@ -749,5 +751,6 @@ void main() { " stdin 1:9 root stylesheet"))); }); }); + */ }); } From ec997846a8c76c2906ff145faacd63fef8fd4604 Mon Sep 17 00:00:00 2001 From: Bee Date: Tue, 21 Jan 2020 17:04:18 -0800 Subject: [PATCH 04/12] Fix naming of portOptions --- lib/src/node.dart | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/lib/src/node.dart b/lib/src/node.dart index 3173af438..1e3d5c9b4 100644 --- a/lib/src/node.dart +++ b/lib/src/node.dart @@ -81,7 +81,8 @@ Future _renderAsync(RenderOptions options) async { var file = options.file == null ? null : p.absolute(options.file); CompileResult result; if (isMainThread == true) { - var worker = Worker(p.current, WorkerOptions(workerData: {options})); + print(p.current); + final worker = Worker(p.current, WorkerOptions(workerData: {options})); worker.on('message', (CompileResult msg) => result = msg); worker.on('error', (JSError error) { jsThrow(_wrapException(error)); @@ -111,7 +112,7 @@ Future _renderAsync(RenderOptions options) async { } else { throw ArgumentError("Either options.data or options.file must be set."); } - ParentPort.postMessage(result, PortOptions()); + parentPort.postMessage(result, PortOptions()); } return _newRenderResult(options, result, start); From 19fc75cd0fce85c16de650e14133a64297de56f9 Mon Sep 17 00:00:00 2001 From: Bee Date: Wed, 22 Jan 2020 13:30:02 -0800 Subject: [PATCH 05/12] Make tweaks to parent class def --- lib/src/node/worker_threads.dart | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/lib/src/node/worker_threads.dart b/lib/src/node/worker_threads.dart index 6ddea3129..0b39833bd 100644 --- a/lib/src/node/worker_threads.dart +++ b/lib/src/node/worker_threads.dart @@ -1,16 +1,19 @@ // Copyright 2017 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. -@JS() +@JS("worker_threads") library worker_threads; import 'package:js/js.dart'; import 'package:js/js_util.dart'; -@JS() -external Object _requireWorkerThreads(String path); +typedef _WorkerThreads = void Function() Function( + String Function(String), String Function(String)); + +@JS('require') +external Object _requireWorkerThreads(String name); -final workers = _requireWorkerThreads("worker_threads"); +final _worker = _requireWorkerThreads("worker_threads"); @JS() external Object get workerData; @@ -46,7 +49,9 @@ class PortOptions { @JS() external ParentPort get parentPort; -@JS() -class ParentPort { - external static void postMessage(Object message, PortOptions options); +@JS("parentPort") +@anonymous +abstract class ParentPort { + external factory ParentPort({Function postMessage}); + external void postMessage(Object message, PortOptions options); } From 79981a91ff557a61a52bdfb6cdc88de0df4ecd75 Mon Sep 17 00:00:00 2001 From: Bee Date: Fri, 24 Jan 2020 21:29:19 -0800 Subject: [PATCH 06/12] Remove fibers tests --- test/node_api/function_test.dart | 89 -------------------------------- 1 file changed, 89 deletions(-) diff --git a/test/node_api/function_test.dart b/test/node_api/function_test.dart index e42ef79a9..d51f383e0 100644 --- a/test/node_api/function_test.dart +++ b/test/node_api/function_test.dart @@ -287,95 +287,6 @@ void main() { data: "", functions: jsify({"foo(": allowInterop(neverCalled)}))); expect(error.toString(), contains('Invalid signature')); }); - - group("with fibers", () { - setUpAll(() { - try { - fiber; - } catch (_) { - throw "Can't load fibers package.\n" - "Run pub run grinder before-test."; - } - }); - - test("runs a synchronous function", () { - expect( - render(RenderOptions( - data: "a {b: foo()}", - functions: jsify({ - "foo": allowInterop( - (void _) => callConstructor(sass.types.Number, [1])) - }), - fiber: fiber)), - completion(equalsIgnoringWhitespace("a { b: 1; }"))); - }); - - test("runs an asynchronous function", () { - expect( - render(RenderOptions( - data: "a {b: foo()}", - functions: jsify({ - "foo": allowInterop((void done(Object result)) { - Timer(Duration.zero, () { - done(callConstructor(sass.types.Number, [1])); - }); - }) - }), - fiber: fiber)), - completion(equalsIgnoringWhitespace("a { b: 1; }"))); - }); - - test("reports a synchronous error", () async { - var error = await renderError(RenderOptions( - data: "a {b: foo()}", - functions: - jsify({"foo": allowInterop((void _) => throw "aw beans")}), - fiber: fiber)); - expect(error.toString(), contains('aw beans')); - }); - - test("reports an asynchronous error", () async { - var error = await renderError(RenderOptions( - data: "a {b: foo()}", - functions: jsify({ - "foo": allowInterop((void done(Object result)) { - Timer(Duration.zero, () { - done(JSError("aw beans")); - }); - }) - }), - fiber: fiber)); - expect(error.toString(), contains('aw beans')); - }); - - test("reports a null return", () async { - var error = await renderError(RenderOptions( - data: "a {b: foo()}", - functions: jsify({ - "foo": allowInterop((void done(Object result)) { - Timer(Duration.zero, () { - done(null); - }); - }) - }), - fiber: fiber)); - expect(error.toString(), contains('must be a Sass value type')); - }); - - test("reports a call to done without arguments", () async { - var error = await renderError(RenderOptions( - data: "a {b: foo()}", - functions: jsify({ - "foo": allowInterop((void done()) { - Timer(Duration.zero, () { - done(); - }); - }) - }), - fiber: fiber)); - expect(error.toString(), contains('must be a Sass value type')); - }); - }); }); // Node Sass currently doesn't provide any representation of first-class From 0d8d273e15f7cf3e6310d6a8470a7c1d619191f6 Mon Sep 17 00:00:00 2001 From: Bee Date: Tue, 28 Jan 2020 15:50:02 -0800 Subject: [PATCH 07/12] Add worker theads to grinder requires --- lib/src/node.dart | 5 +- lib/src/node/worker_threads.dart | 48 ++++----- package/package.json | 2 +- tool/grind/npm.dart | 169 +++++++++++++++++++++++++++++++ 4 files changed, 192 insertions(+), 32 deletions(-) create mode 100644 tool/grind/npm.dart diff --git a/lib/src/node.dart b/lib/src/node.dart index 1e3d5c9b4..91f6e914e 100644 --- a/lib/src/node.dart +++ b/lib/src/node.dart @@ -80,6 +80,9 @@ Future _renderAsync(RenderOptions options) async { var start = DateTime.now(); var file = options.file == null ? null : p.absolute(options.file); CompileResult result; + + print(StackTrace.current); + if (isMainThread == true) { print(p.current); final worker = Worker(p.current, WorkerOptions(workerData: {options})); @@ -112,7 +115,7 @@ Future _renderAsync(RenderOptions options) async { } else { throw ArgumentError("Either options.data or options.file must be set."); } - parentPort.postMessage(result, PortOptions()); + parentPort.postMessage(result); } return _newRenderResult(options, result, start); diff --git a/lib/src/node/worker_threads.dart b/lib/src/node/worker_threads.dart index 0b39833bd..d374d1770 100644 --- a/lib/src/node/worker_threads.dart +++ b/lib/src/node/worker_threads.dart @@ -1,57 +1,45 @@ // Copyright 2017 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. -@JS("worker_threads") +@JS("workerThreads") library worker_threads; +//Import is failing here import 'package:js/js.dart'; -import 'package:js/js_util.dart'; - -typedef _WorkerThreads = void Function() Function( - String Function(String), String Function(String)); - -@JS('require') -external Object _requireWorkerThreads(String name); - -final _worker = _requireWorkerThreads("worker_threads"); @JS() -external Object get workerData; +external WorkerThreads get workerThreads; + +bool isMainThread = workerThreads.isMainThread; +ParentPort parentPort = workerThreads.parentPort; @JS() -external bool get isMainThread; +abstract class WorkerThreads { + @JS('Worker') + external Worker get worker; + external bool get workerData; + external bool get isMainThread; + external ParentPort get parentPort; + external const factory WorkerThreads(); +} @JS() @anonymous class WorkerOptions { external factory WorkerOptions( - {List argv, - Object env, - bool eval, - List execArgv, - Object workerData}); + {Object env, bool eval, List execArgv, Object workerData}); } @JS() class Worker { external void on(String message, Function callback); - external const factory Worker(fileName, WorkerOptions options); + external const factory Worker(String fileName, WorkerOptions options); } -@JS() -@anonymous -class PortOptions { - external List get transferList; - external factory PortOptions({List transferList = const []}); -} - -@JS() -external ParentPort get parentPort; - @JS("parentPort") @anonymous abstract class ParentPort { - external factory ParentPort({Function postMessage}); - external void postMessage(Object message, PortOptions options); + external factory ParentPort(); + external void postMessage(Object message); } diff --git a/package/package.json b/package/package.json index 379ba662d..d2b100f9b 100644 --- a/package/package.json +++ b/package/package.json @@ -14,7 +14,7 @@ "url": "https://github.com/nex3" }, "engines": { - "node": ">=8.9.0" + "node": ">=12.14.1" }, "dependencies": { "chokidar": ">=2.0.0 <4.0.0" diff --git a/tool/grind/npm.dart b/tool/grind/npm.dart new file mode 100644 index 000000000..951ea99ad --- /dev/null +++ b/tool/grind/npm.dart @@ -0,0 +1,169 @@ +// Copyright 2018 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. + +import 'dart:convert'; +import 'dart:io'; + +import 'package:charcode/charcode.dart'; +import 'package:grinder/grinder.dart'; +import 'package:meta/meta.dart'; +import 'package:node_preamble/preamble.dart' as preamble; +import 'package:path/path.dart' as p; +import 'package:source_span/source_span.dart'; + +import 'utils.dart'; + +@Task('Compile to JS in dev mode.') +void js() => _js(release: false); + +@Task('Compile to JS in release mode.') +void jsRelease() => _js(release: true); + +/// Compiles Sass to JS. +/// +/// If [release] is `true`, this compiles minified with +/// --trust-type-annotations. Otherwise, it compiles unminified with pessimistic +/// type checks. +void _js({@required bool release}) { + ensureBuild(); + var destination = File('build/sass.dart.js'); + + Dart2js.compile(File('bin/sass.dart'), outFile: destination, extraArgs: [ + '--categories=Server', + '-Dnode=true', + '-Dversion=$version', + '-Ddart-version=$dartVersion', + // We use O4 because: + // + // * We don't care about the string representation of types. + // * We expect our test coverage to ensure that nothing throws subtypes of + // Error. + // * We thoroughly test edge cases in user input. + // + // We don't minify because download size isn't especially important + // server-side and it's nice to get readable stack traces from bug reports. + if (release) ...["-O4", "--no-minify", "--fast-startup"] + ]); + var text = destination + .readAsStringSync() + // Some dependencies dynamically invoke `require()`, which makes Webpack + // complain. We replace those with direct references to the modules, which + // we load explicitly after the preamble. + .replaceAllMapped(RegExp(r'self\.require\("([a-zA-Z0-9_-]+)"\)'), + (match) => "self.${match[1]}"); + + if (release) { + // We don't ship the source map, so remove the source map comment. + text = + text.replaceFirst(RegExp(r"\n*//# sourceMappingURL=[^\n]+\n*$"), "\n"); + } + + // Reassigning require() makes Webpack complain. + var preambleText = + preamble.getPreamble().replaceFirst("self.require = require;\n", ""); + + destination.writeAsStringSync(""" +$preambleText +self.fs = require("fs"); +self.chokidar = require("chokidar"); +self.readline = require("readline"); +self.workerThreads = require("worker_threads"); +$text"""); +} + +@Task('Build a pure-JS dev-mode npm package.') +@Depends(js) +void npmPackage() => _npm(release: false); + +@Task('Build a pure-JS release-mode npm package.') +@Depends(jsRelease) +void npmReleasePackage() => _npm(release: true); + +/// Builds a pure-JS npm package. +/// +/// If [release] is `true`, this compiles minified with +/// --trust-type-annotations. Otherwise, it compiles unminified with pessimistic +/// type checks. +void _npm({@required bool release}) { + var json = { + ...(jsonDecode(File('package/package.json').readAsStringSync()) + as Map), + "version": version + }; + + _writeNpmPackage('build/npm', json); + if (release) { + _writeNpmPackage('build/npm-old', {...json, "name": "dart-sass"}); + } +} + +/// Writes a Dart Sass NPM package to the directory at [destination]. +/// +/// The [json] will be used as the package's package.json. +void _writeNpmPackage(String destination, Map json) { + var dir = Directory(destination); + if (dir.existsSync()) dir.deleteSync(recursive: true); + dir.createSync(recursive: true); + + log("copying package/package.json to $destination"); + File(p.join(destination, 'package.json')).writeAsStringSync(jsonEncode(json)); + + copy(File(p.join('package', 'sass.js')), dir); + copy(File(p.join('build', 'sass.dart.js')), dir); + + log("copying package/README.npm.md to $destination"); + File(p.join(destination, 'README.md')) + .writeAsStringSync(_readAndResolveMarkdown('package/README.npm.md')); +} + +final _readAndResolveRegExp = RegExp( + r"^$", + multiLine: true); + +/// Reads a Markdown file from [path] and resolves include directives. +/// +/// Include directives have the syntax `""`, +/// which must appear on its own line. PATH is a relative file: URL to another +/// Markdown file, and HEADER is the name of a header in that file whose +/// contents should be included as-is. +String _readAndResolveMarkdown(String path) => File(path) + .readAsStringSync() + .replaceAllMapped(_readAndResolveRegExp, (match) { + String included; + try { + included = File(p.join(p.dirname(path), p.fromUri(match[1]))) + .readAsStringSync(); + } catch (error) { + _matchError(match, error.toString(), url: p.toUri(path)); + } + + Match headerMatch; + try { + headerMatch = "# ${match[2]}\n".allMatches(included).first; + } on StateError { + _matchError(match, "Could not find header.", url: p.toUri(path)); + } + + var headerLevel = 0; + var index = headerMatch.start; + while (index >= 0 && included.codeUnitAt(index) == $hash) { + headerLevel++; + index--; + } + + // The section goes until the next header of the same level, or the end + // of the document. + var sectionEnd = included.indexOf("#" * headerLevel, headerMatch.end); + if (sectionEnd == -1) sectionEnd = included.length; + + return included.substring(headerMatch.end, sectionEnd).trim(); + }); + +/// Throws a nice [SourceSpanException] associated with [match]. +void _matchError(Match match, String message, {Object url}) { + var file = SourceFile.fromString(match.input, url: url); + throw SourceSpanException(message, file.span(match.start, match.end)); +} From fd2eead73b0daa9708a2cb5fa2fa93ba82f29f95 Mon Sep 17 00:00:00 2001 From: Bee Date: Tue, 7 Apr 2020 10:33:35 -0700 Subject: [PATCH 08/12] Add worker_threads to import and start to implement --- lib/src/node.dart | 10 +++++----- lib/src/node/worker_threads.dart | 14 +++++--------- package/package.json | 2 +- tool/grind.dart | 7 ++++++- 4 files changed, 17 insertions(+), 16 deletions(-) diff --git a/lib/src/node.dart b/lib/src/node.dart index 91f6e914e..1044cf2eb 100644 --- a/lib/src/node.dart +++ b/lib/src/node.dart @@ -81,16 +81,14 @@ Future _renderAsync(RenderOptions options) async { var file = options.file == null ? null : p.absolute(options.file); CompileResult result; - print(StackTrace.current); - if (isMainThread == true) { - print(p.current); + print("Creating worker thread"); final worker = Worker(p.current, WorkerOptions(workerData: {options})); worker.on('message', (CompileResult msg) => result = msg); worker.on('error', (JSError error) { jsThrow(_wrapException(error)); }); - } else { + } else if (isMainThread == false) { if (options.data != null) { result = await compileStringAsync(options.data, nodeImporter: _parseImporter(options, start), @@ -115,7 +113,9 @@ Future _renderAsync(RenderOptions options) async { } else { throw ArgumentError("Either options.data or options.file must be set."); } - parentPort.postMessage(result); + parentPort?.postMessage(result); + } else { + throw UnsupportedError("Failed to create worker thread."); } return _newRenderResult(options, result, start); diff --git a/lib/src/node/worker_threads.dart b/lib/src/node/worker_threads.dart index d374d1770..bbf116e0e 100644 --- a/lib/src/node/worker_threads.dart +++ b/lib/src/node/worker_threads.dart @@ -1,17 +1,13 @@ -// Copyright 2017 Google Inc. Use of this source code is governed by an +// Copyright 2018 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. -@JS("workerThreads") -library worker_threads; -//Import is failing here - import 'package:js/js.dart'; -@JS() -external WorkerThreads get workerThreads; +@JS("worker_threads") +external WorkerThreads get worker_threads; -bool isMainThread = workerThreads.isMainThread; -ParentPort parentPort = workerThreads.parentPort; +bool isMainThread = worker_threads?.isMainThread; +ParentPort parentPort = worker_threads?.parentPort; @JS() abstract class WorkerThreads { diff --git a/package/package.json b/package/package.json index d2b100f9b..3debe3e1e 100644 --- a/package/package.json +++ b/package/package.json @@ -14,7 +14,7 @@ "url": "https://github.com/nex3" }, "engines": { - "node": ">=12.14.1" + "node": ">=11.7.0" }, "dependencies": { "chokidar": ">=2.0.0 <4.0.0" diff --git a/tool/grind.dart b/tool/grind.dart index 5eb558b6f..de7aa2350 100644 --- a/tool/grind.dart +++ b/tool/grind.dart @@ -26,7 +26,12 @@ void main(List args) { pkg.chocolateyNuspec = _nuspec; pkg.homebrewRepo = "sass/homebrew-sass"; pkg.homebrewFormula = "sass.rb"; - pkg.jsRequires = {"fs": "fs", "chokidar": "chokidar", "readline": "readline"}; + pkg.jsRequires = { + "fs": "fs", + "chokidar": "chokidar", + "readline": "readline", + "workerThreads": "worker_threads" + }; pkg.jsModuleMainLibrary = "lib/src/node.dart"; pkg.npmPackageJson = json.decode(File("package/package.json").readAsStringSync()) From 6da563068dc3396c132968118fd53e2cd0f352d2 Mon Sep 17 00:00:00 2001 From: Bee Date: Wed, 15 Jan 2020 18:10:31 -0800 Subject: [PATCH 09/12] Setup initial import of 'worker_threads' node library --- lib/src/node/worker_threads.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/src/node/worker_threads.dart b/lib/src/node/worker_threads.dart index bbf116e0e..08ca4efd6 100644 --- a/lib/src/node/worker_threads.dart +++ b/lib/src/node/worker_threads.dart @@ -1,4 +1,4 @@ -// Copyright 2018 Google Inc. Use of this source code is governed by an +// Copyright 2020 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. import 'package:js/js.dart'; From 734a2a1c65a092005e84d484e48f254557f16709 Mon Sep 17 00:00:00 2001 From: Bee Date: Tue, 7 Apr 2020 10:46:24 -0700 Subject: [PATCH 10/12] Add worker_threads interop file and implementation Something here is not working 100%, on running render `ParentPort` is null and it should be an object if its on the worker thread. --- lib/src/node.dart | 1 - lib/src/node/worker_threads.dart | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/src/node.dart b/lib/src/node.dart index 1044cf2eb..ca4187656 100644 --- a/lib/src/node.dart +++ b/lib/src/node.dart @@ -80,7 +80,6 @@ Future _renderAsync(RenderOptions options) async { var start = DateTime.now(); var file = options.file == null ? null : p.absolute(options.file); CompileResult result; - if (isMainThread == true) { print("Creating worker thread"); final worker = Worker(p.current, WorkerOptions(workerData: {options})); diff --git a/lib/src/node/worker_threads.dart b/lib/src/node/worker_threads.dart index 08ca4efd6..b5f4b57ce 100644 --- a/lib/src/node/worker_threads.dart +++ b/lib/src/node/worker_threads.dart @@ -1,6 +1,9 @@ // Copyright 2020 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. +@JS() +library worker_threads; + import 'package:js/js.dart'; @JS("worker_threads") From 5f9e09c90d809da833bfaa442b1d9700f2de183a Mon Sep 17 00:00:00 2001 From: Bee Date: Tue, 21 Jan 2020 17:04:18 -0800 Subject: [PATCH 11/12] Fix naming of portOptions --- lib/src/node.dart | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/lib/src/node.dart b/lib/src/node.dart index ca4187656..7c3e4bbfc 100644 --- a/lib/src/node.dart +++ b/lib/src/node.dart @@ -81,7 +81,7 @@ Future _renderAsync(RenderOptions options) async { var file = options.file == null ? null : p.absolute(options.file); CompileResult result; if (isMainThread == true) { - print("Creating worker thread"); + print(p.current); final worker = Worker(p.current, WorkerOptions(workerData: {options})); worker.on('message', (CompileResult msg) => result = msg); worker.on('error', (JSError error) { @@ -112,9 +112,7 @@ Future _renderAsync(RenderOptions options) async { } else { throw ArgumentError("Either options.data or options.file must be set."); } - parentPort?.postMessage(result); - } else { - throw UnsupportedError("Failed to create worker thread."); + parentPort.postMessage(result, PortOptions()); } return _newRenderResult(options, result, start); From 4d6caaa1c249e603a272dae3e8273729485885e1 Mon Sep 17 00:00:00 2001 From: Bee Date: Wed, 22 Jan 2020 13:30:02 -0800 Subject: [PATCH 12/12] Make tweaks to parent class def --- lib/src/node/worker_threads.dart | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/lib/src/node/worker_threads.dart b/lib/src/node/worker_threads.dart index b5f4b57ce..36bb0d8f1 100644 --- a/lib/src/node/worker_threads.dart +++ b/lib/src/node/worker_threads.dart @@ -1,7 +1,7 @@ // Copyright 2020 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. -@JS() +@JS("worker_threads") library worker_threads; import 'package:js/js.dart'; @@ -36,9 +36,16 @@ class Worker { external const factory Worker(String fileName, WorkerOptions options); } +@JS("parentPort") +@anonymous +class PortOptions { + external List get transferList; + external factory PortOptions({List transferList = const []}); +} + @JS("parentPort") @anonymous abstract class ParentPort { - external factory ParentPort(); - external void postMessage(Object message); + external factory ParentPort({Function postMessage}); + external void postMessage(Object message, PortOptions options); }