Sdk: require.js added to global namespace, when serving via dartdevc

Created on 25 Jul 2018  路  19Comments  路  Source: dart-lang/sdk

This is one for discussion, I think.

While migrating to Dart2.0 (2.0.0-dev.67.0), we faced following issue:
DDC adds <script defer="" src="/packages/$sdk/dev_compiler/amd/require.js"></script> to page, which defines global functions require and define.
That fact affects some third-party libraries, that are also imported to project.
If such library sees global define function, it defines new module, otherwise - set global variable.
Problem is, we don't use requirejs in production environment.
Of course, we can add condition: load library via requirejs in dev-environment, by script adding - in prod one.
But I think, that can be a common problem for large products.

Another possible solution: move ddc's requirejs to some namespace...

area-web dev-compiler-build web-dev-compiler

Most helpful comment

I'm hitting this issue while trying to dynamically load firebase-app.js in DDC

All 19 comments

/cc @natebosch and @jakemac53 if this should be a build issue instead.

I think DDC is the right place to track this for now. I know DDC supports other strategies than require.js and switching to one of those would be a build issue, so if we decide that's the right course of action we can move the issue over.

Thanks Nate!

I've got similar case. My Electron app loads dart webapp written in dart with node integration enabled to enable intercommunication between dart and electron apps. Obviously Node require which is defined even before page starts loading conflicts with DDCs require.

@natebosch can you elaborate more on "other strategies than require.js"? Are they user-configurable?

As of today, no, using anything other than require.js is not an option with build_web_compilers.

The dartdevc compiler does support using other strategies, but using them would require either a lot of manual work to configure how to invoke the compiler for your project, or a lot of work to integrate it with a build system to do it automatically. If we want to support other strategies we'd most likely need to do it in build_web_compilers

I wanted to lazily load third-party libs but most of them uses requirejs and didn't work because of this.
Now I found a way that is removing the window.define after Dart loads

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

@jmesserly wdyt about adding some optional argument which is a global namespace to look for require/define in? Essentially we could pass in --require-namespace or something (there is probably a better name for it) and it would just prepend that in front of all require/define calls?

There is also this FAQ https://requirejs.org/docs/faq-advanced.html#rename which says not to do this explicitly though, but the reasoning may not apply in our case.

wdyt about adding some optional argument which is a global namespace to look for require/define in? Essentially we could pass in --require-namespace or something (there is probably a better name for it) and it would just prepend that in front of all require/define calls?

That sounds quite reasonable to me.

@jakemac53 , I'd like to add couple of examples. As you can see in
https://cdnjs.cloudflare.com/ajax/libs/codemirror/5.45.0/codemirror.js
https://cdnjs.cloudflare.com/ajax/libs/jquery-migrate/3.0.1/jquery-migrate.js
https://cdnjs.cloudflare.com/ajax/libs/handlebars.js/4.1.1/handlebars.min.js
It's quite common for JS-libraries to start package with code like

if ( typeof define === "function" && define.amd ) {
    define(factory);
} else {
  window.MyModuleClass = factory();
}

This means, that right now we need to use this libraries differently in production (with no defined window.define method), and in developer environment (with requirejs from ddc, which defines window.define method).

@jmesserly wdyt about adding some optional argument which is a global namespace to look for require/define in? Essentially we could pass in --require-namespace or something (there is probably a better name for it) and it would just prepend that in front of all require/define calls?

This seems like a good solution. What also might make sense is "scoping" requirejs where only DDC-compiled programs can access it.

I'm hitting this issue while trying to dynamically load firebase-app.js in DDC

I would be one of the users that would argue for it or something equivalent (see the issue referenced above). Now that Flutter Web is here and plugins are getting web support, many of those would need to load their related JS libraries. The fact that it is readily available in debug mode (visible in Chrome console among the sources) makes us believe that this is something intentional and also that being stripped in release mode is just a bug.

If you decide on another loader, no problem, as long as it's compatible with the usual library formats like UMD and others. But don't remove or hide that capability on purpose now that Flutter Web is finally a reality.

something intentional and also that being stripped in release mode is just a bug.

It is not intentional and we don't plan on add any module loader on production mode. Trying to fit into other modular JS apps is non-goal. Our most likely resolution will be to stop using require.js at all, even in dev mode.

Note that using a format which is compatible with typical module formats is also a non-goal at this time. We just happened to use one because it was well defined and easy to use.

However, we have already hit several limitations and its likely we will do something custom in the future that allows for a better dev experience, such as reloading individual modules in the heirarchy without reloading all parents of that module.

With CanvaskKit, there is an even bigger problem:

Uncaught Error: Mismatched anonymous define() module: function() { return CanvasKitInit; }

This practically makes it impossible to use a require.js brought along with our own code to be used for our own purposes. Well, I hope not completely impossible but I'm still struggling to find a way...

Just chiming in on this one - this impacts FlutterFire development as we're unable to directly pull in the Firebase SDK programatically, instead they have to be loaded via the CDN within the <head> section.

@Ehesp As mentioned in https://github.com/flutter/flutter/issues/58428, all it would take is to add a single module ID to the JS. I haven't been able to even trigger a response so far. :-)

Was this page helpful?
0 / 5 - 0 ratings

Related issues

matanlurey picture matanlurey  路  3Comments

55555Mohit55555 picture 55555Mohit55555  路  3Comments

emilniklas picture emilniklas  路  3Comments

xster picture xster  路  3Comments

brooth picture brooth  路  3Comments