dart-lang / build

A build system for Dart written in Dart
https://pub.dev/packages/build
BSD 3-Clause "New" or "Revised" License
792 stars 208 forks source link

BuildWebCompilers can't serve several dart apps on one page, compiled via DartDevC #2023

Open yury-yufimov opened 5 years ago

yury-yufimov commented 5 years ago

We've tried this one not on latest libs, but I doubt it's already fixed. Current versions:

DartSDK: 2.0.0 build: 1.0.0 build_runner: 1.0.0 build_runner_core: 1.0.1 build_web_compilers: 0.4.4

Also, we're still not using build.yaml files, but custom configured builder set. Anyway, here's the situation.

We are trying to separate our application into several dart entry points. At first we include into page some host-app.dart.js, then it decides to include another some-app.dart.js When apps are compiled via dart2js, everything's ok: both main functions are started. But DDC uses require.js, and here's the problem: 1) host-app.dart.js includes into page script <script defer src="packages/$sdk/dev_compiler/amd/require.js" data-main="https://localhost/host-app.dart.bootstrap"></script> 2) requirejs is loaded, then it starts to load it's "data-main" script, which contains compiled main function from host-app.dart 3) Our logic in it includes into page some-app.dart.js 4) It adds to page <script defer src="packages/$sdk/dev_compiler/amd/require.js" data-main="https://localhost/some-app.dart.bootstrap"></script> 5) Second requirejs script doesn't start main function from some-app.dart !

To answer possible questions:

jakemac53 commented 5 years ago

This is a known limitation right now - there are several issues here that would have to be resolved to make it feasible.

(just off the top of my head, I am sure there are more issues)

jakemac53 commented 5 years ago

Fwiw, one common internal strategy is to only serve one app with DDC during development, and serve the others with dart2js (they will run/load faster too).

yury-yufimov commented 5 years ago

@jakemac53 , thanks, we'll take it into consideration. But compilation time in case of dart2js is inapplicable for simultaneous development of host-app and some-app - we'll need different build configs for every app. By the way, I've been able to make this work with such hack: 1) Load host-app as usual 2) Load some-app.dart.bootstrap.js manually 3) call require('some-app.dart.bootstrap');

And so far this solution seems working. But I understand, that this not an stable solution, and it closes opportunity to use diffrent versions of same lib in host-app and some-app

UnikZ commented 5 years ago

@jakemac53, I patched the build_web_compilers/lib/src/dev_compiler_bootstrap.dart to add context for require.config() call, like this:

require.config({
    baseUrl: baseUrl,
    waitSeconds: 0,
    paths: customModulePaths,
    context: document.currentScript.dataset.requirecontext
});

Then I use requirejs with specific context option to load *.dart.bootstrap.js file. Requirejs creates script with correct data-requirecontext attribute. This allows me to load app specific packages to separated requirejs context (https://requirejs.org/docs/api.html#multiversion) and they are not interfered. Synthetic multi-host app works fine for me, but I don't know, what exactly stored at $dart global namespace. Am I right, there are sdk files only? If so, I have restriction to use the same SDK version only.

What do you think about adding this functionality to origin builder package?

jakemac53 commented 5 years ago

@UnikZ the $dart* globals are going to be a problem, although a solvable one. That isn't the dart sdk (the sdk is a require module, dart_sdk), its some global state we keep for the app, as well as a namespace we use to hang some utilities off of. This is a solvable problem - we could namespace all that stuff per app as well, although it does get a bit tricky. Maybe we could use the same context identifier?

UnikZ commented 5 years ago

@jakemac53, sounds like a good plan!