This project was bootstrapped with Create React App.
Shoutouts to revosw for creating this small guide, without that I would have never figured this out flutter/flutter#123940. Created this demo app, to have one example available so others can see it implemented. Also, because even with the explanation it was a bit confusing for me.
Steps load your Flutter app into any React app:
- Run this command in your Flutter app to create a web version:
$ flutter build web --profile --dart-define=Dart2jsOptimization=O0
This will not produce the minified javascript version, since some adjustments need to be made in build output. That of course means, that the client will have to download a bigger bundle.
- Copy the folder
web
from/build/web/
to yourpublic
folder in your React app. In this project I renamed the file toflutter
.
That means all of our flutter files are hosted atYOUR_HOST/flutter/
.
Head over topublic/flutter/main.dart.js
In the next step replace the t1 path with your foldername.\
// what you will need to find
getAssetUrl$1(asset) {
var t1, fallbackBaseUrl, t2;
if (A.Uri_parse(asset).get$hasScheme())
return A._Uri__uriEncode(B.List_5Q7, asset, B.C_Utf8Codec, false);
t1 = this._assetBase;
}
// replaced
getAssetUrl$1(asset) {
var t1;
if (A.Uri_parse(asset, 0, null).get$hasScheme())
return A._Uri__uriEncode(B.List_5Q7, asset, B.C_Utf8Codec, false);
t1 = "/flutter/";
}
- Edit
flutter.js
// Search for this
function getBaseURI() {
const base = document.querySelector("base");
return (base && base.getAttribute("href")) || "";
}
// Use the same path as before
function getBaseURI() {
return "/flutter/";
}
- Create a flutter_init.js file inside your public folder and paste the following content it:
window._stateSet = function () {};
window.addEventListener("load", function (ev) {
let target = document.querySelector("#flutter_target");
_flutter.loader.loadEntrypoint({
onEntrypointLoaded: async function (engineInitializer) {
let appRunner = await engineInitializer.initializeEngine({
hostElement: target,
});
await appRunner.runApp();
},
});
});
- Install
react-helmet-async
so we can run our flutter_init script
$ yarn add react-helmet-async
- Setup is done now head back to your React app:
You need to wrapp your React App with a HelmetProvider and provide an helmetContext (can be empty).\
import React from 'react'
import ReactDOM from 'react-dom/client'
import App from './App'
import { HelmetProvider } from "react-helmet-async"
import './index.css'
const helmetContext = {};
ReactDOM.createRoot(document.getElementById('root') as HTMLElement).render(
<React.StrictMode>
<HelmetProvider context={helmetContext}>
<App />
</HelmetProvider>
</React.StrictMode>,
)
Now that is taken care of add a Helmet component and add our flutter_init.js
+ flutter.js
.
This will load the Flutter app and that was it!
import { Helmet } from "react-helmet-async";
function App() {
return (
<>
<Helmet>
<script src="/flutter/flutter.js" defer></script>
<script src="/flutter_init.js" defer></script>
</Helmet>
<div
style={{ aspectRatio: 9 / 19.5 }}
id="flutter_target"
className="h-full"
></div>
</>
);
}