Skip to content

Commit 0d8d273

Browse files
committed
Add worker theads to grinder requires
1 parent 79981a9 commit 0d8d273

File tree

4 files changed

+192
-32
lines changed

4 files changed

+192
-32
lines changed

lib/src/node.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,9 @@ Future<RenderResult> _renderAsync(RenderOptions options) async {
8080
var start = DateTime.now();
8181
var file = options.file == null ? null : p.absolute(options.file);
8282
CompileResult result;
83+
84+
print(StackTrace.current);
85+
8386
if (isMainThread == true) {
8487
print(p.current);
8588
final worker = Worker(p.current, WorkerOptions(workerData: {options}));
@@ -112,7 +115,7 @@ Future<RenderResult> _renderAsync(RenderOptions options) async {
112115
} else {
113116
throw ArgumentError("Either options.data or options.file must be set.");
114117
}
115-
parentPort.postMessage(result, PortOptions());
118+
parentPort.postMessage(result);
116119
}
117120

118121
return _newRenderResult(options, result, start);

lib/src/node/worker_threads.dart

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,57 +1,45 @@
11
// Copyright 2017 Google Inc. Use of this source code is governed by an
22
// MIT-style license that can be found in the LICENSE file or at
33
// https://opensource.org/licenses/MIT.
4-
@JS("worker_threads")
4+
@JS("workerThreads")
55
library worker_threads;
6+
//Import is failing here
67

78
import 'package:js/js.dart';
8-
import 'package:js/js_util.dart';
9-
10-
typedef _WorkerThreads = void Function() Function(
11-
String Function(String), String Function(String));
12-
13-
@JS('require')
14-
external Object _requireWorkerThreads(String name);
15-
16-
final _worker = _requireWorkerThreads("worker_threads");
179

1810
@JS()
19-
external Object get workerData;
11+
external WorkerThreads get workerThreads;
12+
13+
bool isMainThread = workerThreads.isMainThread;
14+
ParentPort parentPort = workerThreads.parentPort;
2015

2116
@JS()
22-
external bool get isMainThread;
17+
abstract class WorkerThreads {
18+
@JS('Worker')
19+
external Worker get worker;
20+
external bool get workerData;
21+
external bool get isMainThread;
22+
external ParentPort get parentPort;
23+
external const factory WorkerThreads();
24+
}
2325

2426
@JS()
2527
@anonymous
2628
class WorkerOptions {
2729
external factory WorkerOptions(
28-
{List<Object> argv,
29-
Object env,
30-
bool eval,
31-
List<String> execArgv,
32-
Object workerData});
30+
{Object env, bool eval, List<String> execArgv, Object workerData});
3331
}
3432

3533
@JS()
3634
class Worker {
3735
external void on(String message, Function callback);
3836

39-
external const factory Worker(fileName, WorkerOptions options);
37+
external const factory Worker(String fileName, WorkerOptions options);
4038
}
4139

42-
@JS()
43-
@anonymous
44-
class PortOptions {
45-
external List get transferList;
46-
external factory PortOptions({List<Object> transferList = const []});
47-
}
48-
49-
@JS()
50-
external ParentPort get parentPort;
51-
5240
@JS("parentPort")
5341
@anonymous
5442
abstract class ParentPort {
55-
external factory ParentPort({Function postMessage});
56-
external void postMessage(Object message, PortOptions options);
43+
external factory ParentPort();
44+
external void postMessage(Object message);
5745
}

package/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
"url": "https://github.com/nex3"
1515
},
1616
"engines": {
17-
"node": ">=8.9.0"
17+
"node": ">=12.14.1"
1818
},
1919
"dependencies": {
2020
"chokidar": ">=2.0.0 <4.0.0"

tool/grind/npm.dart

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
// Copyright 2018 Google Inc. Use of this source code is governed by an
2+
// MIT-style license that can be found in the LICENSE file or at
3+
// https://opensource.org/licenses/MIT.
4+
5+
import 'dart:convert';
6+
import 'dart:io';
7+
8+
import 'package:charcode/charcode.dart';
9+
import 'package:grinder/grinder.dart';
10+
import 'package:meta/meta.dart';
11+
import 'package:node_preamble/preamble.dart' as preamble;
12+
import 'package:path/path.dart' as p;
13+
import 'package:source_span/source_span.dart';
14+
15+
import 'utils.dart';
16+
17+
@Task('Compile to JS in dev mode.')
18+
void js() => _js(release: false);
19+
20+
@Task('Compile to JS in release mode.')
21+
void jsRelease() => _js(release: true);
22+
23+
/// Compiles Sass to JS.
24+
///
25+
/// If [release] is `true`, this compiles minified with
26+
/// --trust-type-annotations. Otherwise, it compiles unminified with pessimistic
27+
/// type checks.
28+
void _js({@required bool release}) {
29+
ensureBuild();
30+
var destination = File('build/sass.dart.js');
31+
32+
Dart2js.compile(File('bin/sass.dart'), outFile: destination, extraArgs: [
33+
'--categories=Server',
34+
'-Dnode=true',
35+
'-Dversion=$version',
36+
'-Ddart-version=$dartVersion',
37+
// We use O4 because:
38+
//
39+
// * We don't care about the string representation of types.
40+
// * We expect our test coverage to ensure that nothing throws subtypes of
41+
// Error.
42+
// * We thoroughly test edge cases in user input.
43+
//
44+
// We don't minify because download size isn't especially important
45+
// server-side and it's nice to get readable stack traces from bug reports.
46+
if (release) ...["-O4", "--no-minify", "--fast-startup"]
47+
]);
48+
var text = destination
49+
.readAsStringSync()
50+
// Some dependencies dynamically invoke `require()`, which makes Webpack
51+
// complain. We replace those with direct references to the modules, which
52+
// we load explicitly after the preamble.
53+
.replaceAllMapped(RegExp(r'self\.require\("([a-zA-Z0-9_-]+)"\)'),
54+
(match) => "self.${match[1]}");
55+
56+
if (release) {
57+
// We don't ship the source map, so remove the source map comment.
58+
text =
59+
text.replaceFirst(RegExp(r"\n*//# sourceMappingURL=[^\n]+\n*$"), "\n");
60+
}
61+
62+
// Reassigning require() makes Webpack complain.
63+
var preambleText =
64+
preamble.getPreamble().replaceFirst("self.require = require;\n", "");
65+
66+
destination.writeAsStringSync("""
67+
$preambleText
68+
self.fs = require("fs");
69+
self.chokidar = require("chokidar");
70+
self.readline = require("readline");
71+
self.workerThreads = require("worker_threads");
72+
$text""");
73+
}
74+
75+
@Task('Build a pure-JS dev-mode npm package.')
76+
@Depends(js)
77+
void npmPackage() => _npm(release: false);
78+
79+
@Task('Build a pure-JS release-mode npm package.')
80+
@Depends(jsRelease)
81+
void npmReleasePackage() => _npm(release: true);
82+
83+
/// Builds a pure-JS npm package.
84+
///
85+
/// If [release] is `true`, this compiles minified with
86+
/// --trust-type-annotations. Otherwise, it compiles unminified with pessimistic
87+
/// type checks.
88+
void _npm({@required bool release}) {
89+
var json = {
90+
...(jsonDecode(File('package/package.json').readAsStringSync())
91+
as Map<String, Object>),
92+
"version": version
93+
};
94+
95+
_writeNpmPackage('build/npm', json);
96+
if (release) {
97+
_writeNpmPackage('build/npm-old', {...json, "name": "dart-sass"});
98+
}
99+
}
100+
101+
/// Writes a Dart Sass NPM package to the directory at [destination].
102+
///
103+
/// The [json] will be used as the package's package.json.
104+
void _writeNpmPackage(String destination, Map<String, dynamic> json) {
105+
var dir = Directory(destination);
106+
if (dir.existsSync()) dir.deleteSync(recursive: true);
107+
dir.createSync(recursive: true);
108+
109+
log("copying package/package.json to $destination");
110+
File(p.join(destination, 'package.json')).writeAsStringSync(jsonEncode(json));
111+
112+
copy(File(p.join('package', 'sass.js')), dir);
113+
copy(File(p.join('build', 'sass.dart.js')), dir);
114+
115+
log("copying package/README.npm.md to $destination");
116+
File(p.join(destination, 'README.md'))
117+
.writeAsStringSync(_readAndResolveMarkdown('package/README.npm.md'));
118+
}
119+
120+
final _readAndResolveRegExp = RegExp(
121+
r"^<!-- +#include +([^\s]+) +"
122+
'"([^"\n]+)"'
123+
r" +-->$",
124+
multiLine: true);
125+
126+
/// Reads a Markdown file from [path] and resolves include directives.
127+
///
128+
/// Include directives have the syntax `"<!-- #include" PATH HEADER "-->"`,
129+
/// which must appear on its own line. PATH is a relative file: URL to another
130+
/// Markdown file, and HEADER is the name of a header in that file whose
131+
/// contents should be included as-is.
132+
String _readAndResolveMarkdown(String path) => File(path)
133+
.readAsStringSync()
134+
.replaceAllMapped(_readAndResolveRegExp, (match) {
135+
String included;
136+
try {
137+
included = File(p.join(p.dirname(path), p.fromUri(match[1])))
138+
.readAsStringSync();
139+
} catch (error) {
140+
_matchError(match, error.toString(), url: p.toUri(path));
141+
}
142+
143+
Match headerMatch;
144+
try {
145+
headerMatch = "# ${match[2]}\n".allMatches(included).first;
146+
} on StateError {
147+
_matchError(match, "Could not find header.", url: p.toUri(path));
148+
}
149+
150+
var headerLevel = 0;
151+
var index = headerMatch.start;
152+
while (index >= 0 && included.codeUnitAt(index) == $hash) {
153+
headerLevel++;
154+
index--;
155+
}
156+
157+
// The section goes until the next header of the same level, or the end
158+
// of the document.
159+
var sectionEnd = included.indexOf("#" * headerLevel, headerMatch.end);
160+
if (sectionEnd == -1) sectionEnd = included.length;
161+
162+
return included.substring(headerMatch.end, sectionEnd).trim();
163+
});
164+
165+
/// Throws a nice [SourceSpanException] associated with [match].
166+
void _matchError(Match match, String message, {Object url}) {
167+
var file = SourceFile.fromString(match.input, url: url);
168+
throw SourceSpanException(message, file.span(match.start, match.end));
169+
}

0 commit comments

Comments
 (0)