Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Need a way to import libraries by name without polluting the global JS namespace. #25318

Closed
PaulAnnekov opened this issue Dec 27, 2015 · 8 comments
Assignees
Labels
web-js-interop Issues that impact all js interop

Comments

@PaulAnnekov
Copy link

Describe the issue you're seeing
I'm porting Leaflet library to Dart for my own needs.
The code in gist works fine for Chrome, but not for Dartium. In Dartium I get the following exception:

Exception: TypeError: undefined is not a function 
map package:my/leaflet/leaflet.dart_js_interop_patch.dart:35
main app.dart:4 

I tried to add @JS('L') before library ...; and remove direct names of functions in JS annotations from map, latLng and tileLayer. But when I did it, the page stopped working in both browsers %). I start to get the following exception in Chrome:

Uncaught TypeError: L.tileLayer is not a function
dart.main @ app.dart:5
(anonymous function) @ iterable.dart:275
init.currentScript @ iterable.dart:275
(anonymous function) @ iterable.dart:275
(anonymous function) @ iterable.dart:275

P.S. Porting procedure is a pain. No docs, ugly stack trace on exceptions...

Does it happen in Dartium or when compiled to JavaScript?
Only in Dartium

  • Dart SDK version:
    Dart VM version: 1.13.1 (Thu Dec 17 14:42:19 2015) on "linux_x64"
  • pkg/js version: 0.6.0

Failing code: https://gist.github.com/PaulAnnekov/df319b5d58926a196eb5

@PaulAnnekov
Copy link
Author

I think I have found why I can't use this code:

@JS('L')
library L;

import 'package:js/js.dart';

@JS()
external map(String id);

It's because dart2js creates some global variable L:

// The global objects start as so-called "slow objects". For V8, this
// means that it won't try to make map transitions as we add properties
// to these objects. Later on, we attempt to turn these objects into
// fast objects by calling "convertToFastObject" (see
// [emitConvertToFastObjectFunction]).
...
var K = map();
var L = map();
var M = map();
...

so when my generated code tries to call L.map() it fails because L is empty.

@jacob314 jacob314 self-assigned this Dec 28, 2015
@jacob314
Copy link
Member

You are correct. For now use somewhat long names for the imported JS libraries to avoid collisions with minified dart2js names. In the future we'll give Dart2JS a list of names to avoid minifying to so this isn't an issue.

@PaulAnnekov
Copy link
Author

@jacob314 I have added window.Leaflet = L; to JS code and changed JS('L') to JS('Leaflet') (my leaflet dart api). Now everything is working good in Chrome, but it still fails in Dartium:

Uncaught Unhandled exception:
TypeError: undefined is not a function
#0      JsFunction._apply (dart:js:1178)
#1      JsFunction.apply (dart:js:1176)
#2      map (package:nova_poshta_osm_sync/leaflet/leaflet.dart_js_interop_patch.dart:19:81)
#3      main.<main_async_body> (http://localhost:8080/app.dart:167:9)
#4      _RootZone.runUnary (dart:async/zone.dart:1149)
#5      _Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:502)
#6      _Future._propagateToListeners (dart:async/future_impl.dart:585)
#7      _Future._completeWithValue (dart:async/future_impl.dart:376)
#8      _Future._asyncComplete.<anonymous closure> (dart:async/future_impl.dart:430)
#9      _microtaskLoop (dart:async/schedule_microtask.dart:43)
#10     _microtaskLoopEntry (dart:async/schedule_microtask.dart:52)
#11     _ScheduleImmediateHelper._handleMutation (dart:html:49298)
#12     MutationObserver._create.<anonymous closure> (dart:html:27545)

it fails on this line:

patch map(p0, [p1=_UNDEFINED_JS_CONST]) => js_library.context['Leaflet']['map'].apply([p0,p1].takeWhile((i) => i != _UNDEFINED_JS_CONST).toList());

@jacob314
Copy link
Member

When I try to repro I get blocked running pub get. Is the pubspec not
configured correctly or do I need to create a separate leaflet pub package
in a sibling directory?

Resolving dependencies...
Could not find package leaflet at "../leaflet.dart".
Depended on by:

  • nova_poshta_osm_sync"

On Mon, Dec 28, 2015 at 11:24 AM, Paul Annekov notifications@github.com
wrote:

@jacob314 https://github.com/jacob314 I have added window.Leaflet = L;
to JS code and changed JS('L') to JS('Leaflet') (my leaflet dart api
https://github.com/PaulAnnekov/nova_poshta_osm_sync/blob/master/lib/leaflet/leaflet.dart).
Now everything is working good in Chrome, but it still fails in Dartium:

Uncaught Unhandled exception:
TypeError: undefined is not a function
#0 JsFunction._apply (dart:js:1178)
#1 JsFunction.apply (dart:js:1176)
#2 map (package:nova_poshta_osm_sync/leaflet/leaflet.dart_js_interop_patch.dart:19:81)
#3 main.<main_async_body> (http://localhost:8080/app.dart:167:9)
#4 _RootZone.runUnary (dart:async/zone.dart:1149)
#5 _Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:502)
#6 _Future._propagateToListeners (dart:async/future_impl.dart:585)
#7 _Future._completeWithValue (dart:async/future_impl.dart:376)
#8 _Future._asyncComplete. (dart:async/future_impl.dart:430)
#9 _microtaskLoop (dart:async/schedule_microtask.dart:43)
#10 _microtaskLoopEntry (dart:async/schedule_microtask.dart:52)
#11 _ScheduleImmediateHelper._handleMutation (dart:html:49298)
#12 MutationObserver._create. (dart:html:27545)

it fails on this line:

patch map(p0, [p1=_UNDEFINED_JS_CONST]) => js_library.context['Leaflet']['map'].apply([p0,p1].takeWhile((i) => i != _UNDEFINED_JS_CONST).toList());


Reply to this email directly or view it on GitHub
#25318 (comment).

@PaulAnnekov
Copy link
Author

@jacob314 I have updated the code to make it work for you. Just run pub serve web data.

@jacob314
Copy link
Member

Thanks Paul. Here's a patch that makes the code work in Dartium and Dart2js.
https://codereview.appspot.com/278650043

The issue is the Leaflet library copies
Array.isArray into a local variable and then uses that copy instead of Array.isArray
Dartium then replaces Array.isArray with a polyfill that also accepts Dart List objects to make JS interop work well for Array/List.
Changing the execution order so the Dart application is loaded before Leaflet fixes the issue.
Longer term, I need to tweak the Dartium polyfill for Array so it executes earlier before any Dart code is executed perhaps immediately on page load regardless of whether the page contains Dart scripts.

@kevmoo kevmoo added the web-js-interop Issues that impact all js interop label Dec 29, 2015
@PaulAnnekov
Copy link
Author

Thanks for workaround. Will wait for a clean fix. You can rename issue name to something more relevant.

@jacob314 jacob314 changed the title js-interop: function binding is working in Chrome, but not in Dartium Need a way to import libraries by name without polluting the global JS namespace. Jul 7, 2016
@jacob314
Copy link
Member

jacob314 commented Jul 8, 2016

Duplicate of #25059

@jacob314 jacob314 closed this as completed Jul 8, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
web-js-interop Issues that impact all js interop
Projects
None yet
Development

No branches or pull requests

3 participants