flutter / flutter

Flutter makes it easy and fast to build beautiful apps for mobile and beyond
https://flutter.dev
BSD 3-Clause "New" or "Revised" License
165.09k stars 27.21k forks source link

Integrate Flutter with Webpack #121417

Open leighajarett opened 1 year ago

leighajarett commented 1 year ago

Some tools allow you to create different plugins or extensions that contain UI written in HTML. However, many of these tools have restrictions like only allowing a single HTML file.

For example, if you want to create a Figma plugin, all your JS, HTML and CSS needs to be in a single file or accessible via a network call. This isn't a big issue for developers because of tools like Webpack, where you can specify an entry point and it loads all the dependencies into a single file.

It would be great if we could specify a dart file as the entry point for Webpack, which would then spit out a single HTML build asset. This way you can create UIs for plugins and extensions with Flutter. An example might be having a Figma plugin that gives you a catalog of the Flutter widgets available in the design system, or allowing you to preview your Figma design in an embedded Flutter app.

kevmoo commented 1 year ago

CC @yjbanov @ditman – interesting to ponder. Especially with element embedding, we have a chance to at least make it easy to package a flutter "widget"? "element"? "component"? that's easy to integrate somewhere else.

yjbanov commented 1 year ago

I'm not sure how far we can go with supporting bespoke technical constraints of environments like Figma. We want to take advantage of things modern browsers provide. Can you bundle wasm into HTML? Fonts? Would it mean that we can't defer load anything? How do we test it? Lots of interesting questions to ponder.

However, making it easy to embed Flutter into an existing page is something we can optimize for.

ditman commented 1 year ago

I'm working on a proposal for this. Part of the integration with webpack (or any bundler, really), is probably to make flutter.js play ball with ESModules, so people can import from it, in a way that webpack understands.

A bigger issue I see is integrating the flutter build process in a way that feels natural to webpack users. I guess we could have a flutter directory somewhere, and have a bundler plugin that knows how to call flutter build, then move our output around (or making flutter build have a configurable output location, most likely), but I don't know if that'd be enough to make the integration easier than it currently is, or just... different.

ditman commented 1 year ago

I've written a small doc to address how Flutter Web could integrate (a little bit better) with modern packers and ES Modules.

I'm not sure if all the parts are in pieces, but we definitely need to some more work in the engine to make it a reality!

ditman commented 1 year ago

The Angular demo looks like an starting point for this, at least flutter.js got minified and handled by angular as if it were any other 3p script (main.dart.js is another story :))

jehuamanna commented 11 months ago

Looking forward to having this feature, as we need to integrate multiple Flutter apps as a separate micro-frontend. The problem with my PoC is that assets of Flutter apps get loaded from the host domain, even though I am able to load flutter.js and main.dart.js from CDN.

ditman commented 11 months ago

The problem with my PoC is that assets of Flutter apps get loaded from the host domain, even though I am able to load flutter.js and main.dart.js from CDN.

@jehuamanna maybe the assetBase init option can help? docs.

jehuamanna commented 11 months ago

This worked. Thanks @ditman

Blutchie commented 7 months ago

Hi @jehuamanna and @ditman, I am making a Flutter app that is designed to be embedded in any JS front-end which can be installed as an NPM module. It's currently just in a PoC phase, but I ran into the same issues and tried to solve it with the assetBase init option. This worked almost fine, besides some small issue. I fixed that by patching it after transpiling to JS, but was digging into the issues here to see if it was reported already. That's why I found this issue and your comments.

The problem is that assetBase only seem to work for your own assets, but not for thid party dependencies. For example, I am using the "video_player_media_kit" package, which depends on "media_kit_video" which depends again on "wakelock_plus". I found out that loading the required "no_sleep.js" ignored the assetBase, so this resulted in a 404.

I solved that for now, by editing the generated main.dart.js. If you search for "./assets/packages/" and then inject the assetsBase. This is not ideal of course, but if you would run into similar issues later, this is how you could solve it.

ditman commented 7 months ago

The problem is that assetBase only seem to work for your own assets, but not for thid party dependencies. For example ... "wakelock_plus". I found out that loading the required "no_sleep.js" ignored the assetBase, so this resulted in a 404.

I'd say that's a bug in wakelock_plus, because I think they should be using the getAssetUrl API to fetch the assets, but they seem to be hard-coding URLs:

https://github.com/fluttercommunity/wakelock_plus/blob/91c531e1253e798ccb3a18497ce71e4b80065120/wakelock_plus/lib/src/web_impl/import_js_library.dart#L17-L27

(There might be a bug in the getAssetUrl method too, so let's not discard that!).

In any case @Blutchie, please start by creating a bug in wakelock_plus, and have them create one in flutter in case we need to fix our API!

Blutchie commented 7 months ago

The problem is that assetBase only seem to work for your own assets, but not for thid party dependencies. For example ... "wakelock_plus". I found out that loading the required "no_sleep.js" ignored the assetBase, so this resulted in a 404.

I'd say that's a bug in wakelock_plus, because I think they should be using the getAssetUrl API to fetch the assets, but they seem to be hard-coding URLs:

https://github.com/fluttercommunity/wakelock_plus/blob/91c531e1253e798ccb3a18497ce71e4b80065120/wakelock_plus/lib/src/web_impl/import_js_library.dart#L17-L27

(There might be a bug in the getAssetUrl method too, so let's not discard that!).

In any case @Blutchie, please start by creating a bug in wakelock_plus, and have them create one in flutter in case we need to fix our API!

Great find @ditman! When I was trying to solve this issue, I made a --profile build to analyze the main.dart.js, and this shared link contains exactly the function names that I fixed locally. I assumed those functions were part of Flutter, but they are from wakelock_plus. I will report the bug there!

diegotori commented 7 months ago

The problem is that assetBase only seem to work for your own assets, but not for thid party dependencies. For example ... "wakelock_plus". I found out that loading the required "no_sleep.js" ignored the assetBase, so this resulted in a 404.

I'd say that's a bug in wakelock_plus, because I think they should be using the getAssetUrl API to fetch the assets, but they seem to be hard-coding URLs:

https://github.com/fluttercommunity/wakelock_plus/blob/91c531e1253e798ccb3a18497ce71e4b80065120/wakelock_plus/lib/src/web_impl/import_js_library.dart#L17-L27

(There might be a bug in the getAssetUrl method too, so let's not discard that!).

In any case @Blutchie, please start by creating a bug in wakelock_plus, and have them create one in flutter in case we need to fix our API!

Hi @ditman, I currently maintain wakelock_plus. Just curious where the change needs to be in the method in question:

String _libraryUrl(String url, String pluginName) {
  if (url.startsWith('./')) {
    url = url.replaceFirst('./', '');
    return './assets/packages/$pluginName/$url';
  }
  if (url.startsWith('assets/')) {
    return './assets/packages/$pluginName/$url';
  } else {
    return url;
  }
}

Should it merely swap out the hard-coded parts, assets/packages, with getAssetUrl?

String _libraryUrl(String url, String pluginName) {
  if (url.startsWith('./')) {
    url = url.replaceFirst('./', '');
    return ui.assetManager().getAssetUrl("$pluginName/$url");
  }
  if (url.startsWith('assets/')) {
    return ui.assetManager().getAssetUrl("$pluginName/$url");
  } else {
    return url;
  }
}
diegotori commented 7 months ago

@ditman and @Blutchie, looks like I got it to work using getAssetUrl:

import 'dart:ui_web' as ui_web;

//...

String _libraryUrl(String url, String pluginName) {
  if (url.startsWith('./')) {
    url = url.replaceFirst('./', '');
    return ui_web.assetManager.getAssetUrl('packages/$pluginName/$url');
  }
  if (url.startsWith('assets/')) {
    return ui_web.assetManager.getAssetUrl('packages/$pluginName/$url');
  } else {
    return url;
  }
}

I'll start creating a PR and release for this.

ditman commented 7 months ago

@diegotori thanks for taking care of this! Remember to try your changes in a target app outside of your repo to see if assets/$pluginName/$url is enough to locate assets from separate packages!

diegotori commented 7 months ago

@diegotori thanks for taking care of this! Remember to try your changes in a target app outside of your repo to see if assets/$pluginName/$url is enough to locate assets from separate packages!

I'm trying to think of another package that uses this, which I maintain. chewie comes to mind, but so far, after setting breakpoints in wakelock_plus's example app, it did resolve the asset paths properly based on how the web app is built.

Nevertheless, debugging a web-based Flutter Integration Test from Android Studio, let alone debugging it in the IDE, is next to impossible, so it's rather difficult for me to verify that the changes work. Not to mention that I can't think of any way to automate this via Github Action.

wakelock_plus is a continuation of the original wakelock package, and as such, it was a near 1:1 port of what existed there nearly nine months ago. As a result, whatever web based bugs existed there and in this package, are now starting to bubble up.

If there was a way to automate Web based integration testing, with the ability to step through the code in Android Studio, that would help give me certainty in my changes.

ditman commented 7 months ago

@diegotori We have several examples of web integration tests in the flutter/plugins repo (almost all _web packages there have integration tests inside their example directory), that you may be able to use. We can discuss in a wakelock_plus issue if you want, to keep this one related to webpack :)