Sdk: Exception Using package:js in Deferred Loaded Library

Created on 14 Jun 2016  路  6Comments  路  Source: dart-lang/sdk

It appears you cannot use package:js for interop in a deferred-loaded library. At least not in Dartium. In other browsers, that use the compiled JS assets, it works just fine.

I've put together a simple web app that demonstrates the issue. In it I created a file called interoping.dart that will get deferred loaded by the main routine. This is what the contents are:

/// File: interoping.dart
@JS('JSON')
library interoping;

import 'package:js/js.dart';

@JS()
external String stringify(obj);

Then I created a main.dart file that imports interoping.dart in a deferred manner:

/// File: main.dart
import 'dart:async';

import 'interoping.dart' deferred as interoping;

Future main() async {
  await interoping.loadLibrary();
  var val = interoping.stringify({});
  print('Here is a stringified object: $val');
}

When I run the web app and hit it from Dartium, I get this error in the browser console:

image

As I said at the start, this is only an issue in Dartium but that makes for a slow dev cycle since we can't use Dartium. When I open this in Chrome, using the compiled JS output, it successfully calls the JSON.stringify method and I see this in the browser console:

image

If I change main.dart so that it doesn't deferred load the library, the interop works just fine in Dartium too. Here's the updated main.dart:

/// File: main.dart
import 'dart:async';

import 'interoping.dart' /*deferred*/ as interoping;

Future main() async {
//  await interoping.loadLibrary();
  var val = interoping.stringify({});
  print('Here is a stringified object: $val');
}

Running this version in Dartium I get the expected output in the browser console:

image

Note that I've tried this in dart version 1.15.0 and 1.17.1 and this behavior is exhibited in both.

library-js web-js-interop

Most helpful comment

@jacob314 Thanks for the response. The example I sent might be a little misleading; it was just intended to demonstrate the problem as simply as possible.

I'm working on a team that is building a very large single page app. In order to get the application up on screen as quickly as possible we are deferred loading large parts of the application. Only when those features are used do we load those parts. In some small corner of those application parts that get deferred loaded we need to do JS interop. But what you are saying is that we can't deferred load those parts of the application that do interop using package:js.

This seems like it would be a fairly common pattern (deferred loading features) and a fairly common problem (trying to do JS interop from deferred loaded features) for folks building single page apps. Not being able to run those apps on Dartium really hamstrings the dev cycle.

All 6 comments

@todbachman-wf thanks for filing this issue.
@a-siva
Looks like the use of deferred loading, js interop, and Dartium in combination causes the issue to show itself.

You need to import
@JS libraries without using deferred for now.
Note: @JS libraries should have a small code size impact as their contents are mainly compiled out in dart2js.
Supporting deferred
@JS libraries in dartium would be very hard and supporting it fully would require the additional language feature of being able to intercept is checks. Specifically, type checks against @JS classes in checked mode would be very hard to get right.

@jacob314 Thanks for the response. The example I sent might be a little misleading; it was just intended to demonstrate the problem as simply as possible.

I'm working on a team that is building a very large single page app. In order to get the application up on screen as quickly as possible we are deferred loading large parts of the application. Only when those features are used do we load those parts. In some small corner of those application parts that get deferred loaded we need to do JS interop. But what you are saying is that we can't deferred load those parts of the application that do interop using package:js.

This seems like it would be a fairly common pattern (deferred loading features) and a fairly common problem (trying to do JS interop from deferred loaded features) for folks building single page apps. Not being able to run those apps on Dartium really hamstrings the dev cycle.

@jacob314 Is anyone attempting to resolve this issue? Or are you telling us that we just can't expect deferred loading with @JS in Dartium for quite some time / ever?

As @todbachman-wf said, we're building a large single page app ecosystem that relies on deferred loading of feature sets, several of which rely on @JS to interop with transpiled Go code (among other smaller JS assets). It really hampers the dev process if we can't use Dartium for rapid iteration.

I don't expect we will fix this issue in Dartium. It would require significant changes to the DartVM that would not be useful elsewhere. The Dart Dev Compiler will support this case more cleanly and is the path for productive Dart debugging on the client going forward.

I would suggest running dartium after setting
export DART_FLAGS=--load_deferred_eagerly
which I believe should solve your issue without you having to modify the underlying code.

@jacob314 looks like load_deferred_eagerly does indeed solve our issues. Thx

Was this page helpful?
0 / 5 - 0 ratings