Skip to content

Commit 564250e

Browse files
authored
Fix relative imports in wasm loader (#3752)
Currently, the loader script emitted by `build_web_compilers` resolves URLs against the base-URL of the active document. This breaks when the entrypoint script is not in the same directory as the page, e.g. in ``` web/ index.html src/ app.dart ``` To fix this, this PR changes the logic to resolve URLs against the loader script (which would be `/src/app.dart.js` in the example, properly resolving the other dart2wasm/dart2js components). I've also added an integration test using a `<script>` tag pointing to a subdirectory to make sure that this is working now. Closes #3751
1 parent 16da6fb commit 564250e

File tree

12 files changed

+86
-13
lines changed

12 files changed

+86
-13
lines changed

_test/build.both.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ targets:
1818
- test/hello_world_deferred_test.dart.browser_test.dart
1919
- test/hello_world_custom_html_test.dart
2020
- test/hello_world_custom_html_test.dart.browser_test.dart
21+
- test/subdir_source_test.dart
22+
- test/subdir_source_test.dart.browser_test.dart
2123
- test/other_test.dart.browser_test.dart
24+
- test/sub-dir/subdir_source.dart
2225
- test/sub-dir/subdir_test.dart
2326
- test/sub-dir/subdir_test.dart.browser_test.dart

_test/build.dart2js.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,9 @@ targets:
1717
- test/hello_world_deferred_test.dart.browser_test.dart
1818
- test/hello_world_custom_html_test.dart
1919
- test/hello_world_custom_html_test.dart.browser_test.dart
20+
- test/subdir_source_test.dart
21+
- test/subdir_source_test.dart.browser_test.dart
2022
- test/other_test.dart.browser_test.dart
23+
- test/sub-dir/subdir_source.dart
2124
- test/sub-dir/subdir_test.dart
2225
- test/sub-dir/subdir_test.dart.browser_test.dart

_test/build.dart2wasm.yaml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ targets:
2323
- test/hello_world_deferred_test.dart.browser_test.dart
2424
- test/hello_world_custom_html_test.dart
2525
- test/hello_world_custom_html_test.dart.browser_test.dart
26+
- test/subdir_source_test.dart
27+
- test/subdir_source_test.dart.browser_test.dart
2628
- test/other_test.dart.browser_test.dart
29+
- test/sub-dir/subdir_source.dart
2730
- test/sub-dir/subdir_test.dart
2831
- test/sub-dir/subdir_test.dart.browser_test.dart

_test/build.yaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,4 +10,6 @@ targets:
1010
- test/hello_world_deferred_test.dart.browser_test.dart
1111
- test/hello_world_custom_html_test.dart.browser_test.dart
1212
- test/other_test.dart.browser_test.dart
13+
- test/subdir_source_test.dart.browser_test.dart
14+
- test/sub-dir/subdir_source.dart
1315
- test/sub-dir/subdir_test.dart.browser_test.dart

_test/dart_test.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@ timeout: 16x
44
concurrency: 1
55

66
tags:
7-
integration:
87
# This tag is used for integration tests - we don't need special options at the
98
# moment, but want to avoid warnings from the test runner about using undefined
109
# targets.
10+
integration:
1111

1212
define_platforms:
1313
chrome_without_wasm:

_test/mono_pkg.yaml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ stages:
1111
os: linux
1212
- unit_test:
1313
- command: dart run build_runner test -- -p chrome --test-randomize-ordering-seed=random
14-
# TODO(https://github.com/dart-lang/build/issues/3423): restore this on windows
14+
# TODO(https://github.com/dart-lang/build/issues/3423): restore this on windows
1515
- command: dart run build_runner test -- -p vm test/configurable_uri_test.dart --test-randomize-ordering-seed=random
1616
os: linux
1717
- e2e_test:
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
5+
import 'dart:js_interop';
6+
import 'dart:js_interop_unsafe';
7+
8+
void main() {
9+
globalContext['otherScriptLoaded'] = true.toJS;
10+
}

_test/test/subdir_source_test.dart

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
// Copyright (c) 2024, the Dart project authors. Please see the AUTHORS file
2+
// for details. All rights reserved. Use of this source code is governed by a
3+
// BSD-style license that can be found in the LICENSE file.
4+
@TestOn('browser')
5+
library;
6+
7+
import 'dart:js_interop';
8+
import 'dart:js_interop_unsafe';
9+
10+
import 'package:test/test.dart';
11+
import 'package:web/web.dart';
12+
13+
void main() {
14+
final wasCompiledWithDdc = globalContext.has('define');
15+
16+
test(
17+
'did load script from a subdirectory',
18+
() async {
19+
final scriptTag = document.createElement('script') as HTMLScriptElement;
20+
scriptTag
21+
..type = 'application/javascript'
22+
..src = 'sub-dir/subdir_source.dart.js';
23+
document.head!.append(scriptTag);
24+
25+
await Future.any([
26+
scriptTag.onLoad.first,
27+
scriptTag.onError.first
28+
.then((_) => fail('Script from sub directory failed to load'))
29+
]);
30+
31+
await pumpEventQueue();
32+
33+
// `sub-dir/subdir_source.dart.js` should have set the `otherScriptLoader`
34+
// propery.
35+
expect(globalContext.has('otherScriptLoaded'), isTrue);
36+
},
37+
skip: wasCompiledWithDdc
38+
? 'This requires multiple Dart entrypoints, which appears to break DDC'
39+
: null,
40+
);
41+
}

build_web_compilers/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 4.1.0-wip
2+
3+
- Fix loading compiled modules from subdirectories.
4+
15
## 4.1.0-beta.0
26

37
- Support compiling to WebAssembly by using `dart2wasm` as a value for the

build_web_compilers/lib/src/web_entrypoint_builder.dart

Lines changed: 14 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -334,7 +334,15 @@ class WebEntrypointBuilder implements Builder {
334334
var jsCompiler = options.optionsFor(WebCompiler.Dart2Js) ??
335335
options.optionsFor(WebCompiler.DartDevc);
336336

337-
var loaderResult = StringBuffer('''(async () => {
337+
var loaderResult = StringBuffer('''
338+
(async () => {
339+
const thisScript = document.currentScript;
340+
341+
function relativeURL(ref) {
342+
const base = thisScript?.src ?? document.baseURI;
343+
return new URL(ref, base).toString();
344+
}
345+
338346
''');
339347

340348
// If we're compiling to JS, start a feature detection to prefer wasm but
@@ -355,19 +363,19 @@ if (supportsWasmGC()) {
355363
}
356364

357365
loaderResult.writeln('''
358-
let { instantiate, invoke } = await import("./$basename${wasmCompiler.extension}");
366+
let { compileStreaming } = await import("./$basename${wasmCompiler.extension}");
359367
360-
let modulePromise = WebAssembly.compileStreaming(fetch("$basename.wasm"));
361-
let instantiated = await instantiate(modulePromise, {});
362-
invoke(instantiated, []);
368+
let app = await compileStreaming(fetch(relativeURL("$basename.wasm")));
369+
let module = await app.instantiate({});
370+
module.invokeMain();
363371
''');
364372

365373
if (jsCompiler != null) {
366374
loaderResult.writeln('''
367375
} else {
368376
const scriptTag = document.createElement("script");
369377
scriptTag.type = "application/javascript";
370-
scriptTag.src = new URL("./$basename${jsCompiler.extension}", document.baseURI).toString();
378+
scriptTag.src = relativeURL("./$basename${jsCompiler.extension}");
371379
document.head.append(scriptTag);
372380
}
373381
''');

0 commit comments

Comments
 (0)