is it possible to lazily use JS libs with Dart?

感情迁移 提交于 2019-12-22 11:29:04

问题


I am using chartjs (with the dart interface https://pub.dartlang.org/packages/chartjs) and trying to make it deferred by injecting a <script src="chartjs.js"></script> into the head section and awaiting it's load event to then use the lib.
I am getting this exception: Cannot read property 'Chart' of undefined.

It does not happen when the script is within the head of the html before dart.

So, is it possible to load a JS lib after Dart loaded?


回答1:


this is a problem in DDC. It addeds require.js to the HTML and conflicts with other libs.
https://github.com/dart-lang/sdk/issues/33979

The solution I've found is to manually remove the header section that uses requirejs from the third-party lib you want to use.

For example, take chartjs: https://cdn.jsdelivr.net/npm/chart.js@2.8.0/dist/Chart.js

You remove this two lines:

typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(function() { try { return require('moment'); } catch(e) { } }()) :
typeof define === 'function' && define.amd ? define(['require'], function(require) { return factory(function() { try { return require('moment'); } catch(e) { } }()); }) :

Then the file can be lazily added to the DOM without conflicts.

This is my code to lazily fetch scripts:

class ClientUtils {
    static final _scriptFetched = <String, Future<bool>>{};

    static ScriptElement _scr(String url) => new ScriptElement()
      ..async = true
      ..type = 'text/javascript'
      ..src = url;

    static Future<bool> fetchScript(String url,
            {String contextCheck}) async {
        bool shouldCheck = contextCheck?.isNotEmpty == true;

        hasContext() => js.context.hasProperty(contextCheck) &&
                    js.context[contextCheck] != null;

        if (shouldCheck && hasContext())
            return true;

        if (!_scriptFetched.containsKey(url)) {
            Completer<bool> c = new Completer<bool>();

            if (!shouldCheck) {
                ScriptElement s = _scr(url)
                    ..onLoad.forEach((Event e) {
                        c.complete(true);
                    });

                document.body.children.add(s);
            } else {
                Timer.periodic(Duration(milliseconds: 300), (t) {
                    if (hasContext()) {
                        t.cancel();
                    }
                    c.complete(true);
                });

                document.body.children.add(_scr(url));
            }

            _scriptFetched[url] = c.future;
        }
        return _scriptFetched[url];
    }
}




回答2:


found a better way!

lets remove the define variable after dart loads, then any third-party lib works when added async :D

add this to your main():

import 'dart:js';

void main() {
  context.callMethod('fixRequireJs');
}

and in your index.html:

    <script type="text/javascript">
      window.fixRequireJs = function()
      {
        console.log('define is ', typeof define);
        if (typeof define == 'function') {
          console.log('removing define...');
          delete define;
          window.define = null;
        }
      }
    </script>



回答3:


You can try the deferred as syntax:

import 'package:chartjs/chartjs.dart' deferred as chartjs;

void main() {
    chartjs.loadLibrary().then(() { ... });
}


来源:https://stackoverflow.com/questions/55113108/is-it-possible-to-lazily-use-js-libs-with-dart

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!