Last active
February 27, 2023 08:52
-
-
Save zs-dima/5e7de75991fc707353afda970686dbba to your computer and use it in GitHub Desktop.
Runtime environment variables for Flutter Web + Update Flutter Web app JS as soon as app version updated
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
FROM dart:stable AS build_dart | |
WORKDIR /app | |
COPY ./tool/ ./tool/ | |
RUN dart compile exe tool/web_env.dart -o tool/web-env | |
FROM plugfox/flutter:stable-web AS build_web | |
WORKDIR /home | |
# Copy app source code and compile it | |
COPY --chown=101:101 . . | |
# Ensure packages are still up-to-date if anything has changed | |
RUN flutter pub get | |
RUN flutter pub run build_runner build --delete-conflicting-outputs --release | |
RUN flutter pub global run intl_utils:generate | |
RUN flutter build web --release --no-source-maps \ | |
--pwa-strategy offline-first \ | |
--web-renderer canvaskit --dart-define=FLUTTER_WEB_USE_SKIA=true | |
FROM nginx:alpine as production | |
COPY --from=build_dart /runtime/ / | |
COPY --from=build_dart /app/tool/web-env /app/bin/ | |
COPY --from=build_dart /app/tool/entrypoint.sh /app/bin/ | |
COPY --from=build_web --chown=101:101 /home/build/web /usr/share/nginx/html | |
COPY deploy/nginx/mime.types /etc/nginx/mime.types | |
COPY deploy/nginx/nginx.conf /etc/nginx/nginx.conf | |
RUN chmod +x /app/bin/entrypoint.sh | |
# Add lables | |
LABEL name="..." \ | |
vcs-url="https://github.com/..." \ | |
github="https://github.com/..." \ | |
maintainer="..." \ | |
authors="..." \ | |
family="" | |
# Start server | |
EXPOSE 80/tcp | |
ENTRYPOINT ["/app/bin/entrypoint.sh"] | |
CMD ["nginx", "-g", "daemon off;"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/sh | |
/app/bin/web-env environment=$APP_ENVIRONMENT version=$APP_VERSION api_host=$APP_API_HOST api_port=$APP_API_PORT api_ssl=$APP_API_SSL | |
# This will exec the CMD from your Dockerfile | |
exec "$@" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import 'dart:collection' show ListBase; | |
import 'dart:convert'; | |
import 'dart:io'; | |
import 'dart:typed_data'; | |
void main(List<String> arguments) async { | |
const versionVarName = 'app_version'; | |
const webRoot = '/usr/share/nginx/html'; | |
const envFileName = 'environment.json'; | |
const envJsonPath = '$webRoot/assets/asset/$envFileName'; | |
const indexHtmlPath = '$webRoot/index.html'; | |
const flutterJsPath = '$webRoot/flutter.js'; | |
const workerJsPath = '$webRoot/flutter_service_worker.js'; | |
const versionJsonPath = '$webRoot/version.json'; | |
var appVersion = ''; | |
final envJson = <String, Object>{}; | |
for (final argument in arguments) { | |
if (argument.contains('=')) { | |
final split = argument.split('='); | |
final arg = split.first.toLowerCase(); | |
final value = split.last; | |
if (arg.isEmpty || value.isEmpty) { | |
continue; | |
} | |
if (int.tryParse(value) != null) { | |
envJson[arg] = int.parse(value); | |
} else if (double.tryParse(value) != null) { | |
envJson[arg] = double.parse(value); | |
} else if (value.toLowerCase() == 'true') { | |
envJson[arg] = true; | |
} else if (value.toLowerCase() == 'false') { | |
envJson[arg] = false; | |
} else { | |
envJson[arg] = value; | |
} | |
if (arg == versionVarName) { | |
appVersion = value; | |
} | |
} | |
} | |
if (appVersion.isEmpty) { | |
final versionJsonFile = File(versionJsonPath); | |
final versionJson = jsonDecode(await versionJsonFile.readAsString()); | |
appVersion = '${versionJson['version']}+${versionJson['build_number']}'.trim(); | |
} | |
final envFile = File(envJsonPath); | |
final envFileContent = const JsonEncoder.withIndent(' ').convert(envJson); | |
final envFileMd5 = md5.convert(utf8.encode(envFileContent)).toString(); | |
await envFile.writeAsString(envFileContent); | |
final flutterJsFile = File(flutterJsPath); | |
final flutterJsContent = await flutterJsFile.readAsString(); | |
final flutterJsReplaced = flutterJsContent | |
.replaceAll('"main.dart.js"', '"main.dart.js?$appVersion"') | |
.replaceAll('"flutter_service_worker.js?v=', '"flutter_service_worker.js?v=$appVersion'); | |
if (flutterJsContent != flutterJsReplaced) { | |
await flutterJsFile.writeAsString(flutterJsReplaced); | |
} | |
final indexHtmlFile = File(indexHtmlPath); | |
final indexHtml = await indexHtmlFile.readAsString(); | |
final indexHtmlReplaced = indexHtml.replaceAll('"flutter.js"', '"flutter.js?$appVersion"'); | |
if (indexHtml != indexHtmlReplaced) { | |
await indexHtmlFile.writeAsString(indexHtmlReplaced); | |
} | |
final workerJsFile = File(workerJsPath); | |
final workerJsContent = await workerJsFile.readAsString(); | |
final workerJsReplaced = workerJsContent.replaceAll( | |
RegExp('"assets/asset/$envFileName": "[0-9a-f]{32}"'), | |
'"assets/asset/$envFileName": "$envFileMd5"', | |
); | |
if (workerJsContent != workerJsReplaced) { | |
await workerJsFile.writeAsString(workerJsReplaced); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment