diff --git a/.github/workflows/run_ci.yml b/.github/workflows/run_ci.yml index 87e7e15..586f6f2 100644 --- a/.github/workflows/run_ci.yml +++ b/.github/workflows/run_ci.yml @@ -35,5 +35,6 @@ jobs: node-version: '20' - uses: actions/checkout@v4 - run: dart --version - - run: dart pub get - - run: dart run tool/run_ci.dart + - run: dart pub global activate dev_build + - run: dart pub global run dev_build:run_ci --recursive + diff --git a/packages/firebase_build/lib/src/app_build.dart b/packages/firebase_build/lib/src/app_build.dart index f69262f..36f3d6e 100644 --- a/packages/firebase_build/lib/src/app_build.dart +++ b/packages/firebase_build/lib/src/app_build.dart @@ -41,10 +41,16 @@ Future flutterWebAppBuildAndServe(String directory, enum FlutterWebRenderer { html, canvasKit } +/// Build options. class FlutterWebAppBuildOptions { + /// Renderer FlutterWebRenderer? renderer; - FlutterWebAppBuildOptions({this.renderer}); + /// Compile as wasm + bool? wasm; + + /// Build options. + FlutterWebAppBuildOptions({this.renderer, this.wasm}); } /// Web app options @@ -92,17 +98,21 @@ class FlutterFirebaseWebAppBuilder { var shell = Shell().cd(options.path); controller?.shell = shell; var renderOptions = ''; - switch (options.buildOptions?.renderer) { - case FlutterWebRenderer.html: - renderOptions = ' --web-renderer html'; - break; - case FlutterWebRenderer.canvasKit: - renderOptions = ' --web-renderer canvaskit'; - break; - default: + var wasm = options.buildOptions?.wasm ?? false; + if (!wasm) { + // not compatible with wasm + switch (options.buildOptions?.renderer) { + case FlutterWebRenderer.html: + renderOptions = ' --web-renderer html'; + break; + case FlutterWebRenderer.canvasKit: + renderOptions = ' --web-renderer canvaskit'; + break; + default: + } } - await shell.run('flutter build web$renderOptions'); - await flutterWebAppBuild(options.path); + var wasmOptions = wasm ? ' --wasm' : ''; + await shell.run('flutter build web$renderOptions$wasmOptions'); await firebaseWebAppBuildToDeploy(options.path, deployDir: options.deployDir); } @@ -113,15 +123,12 @@ class FlutterFirebaseWebAppBuilder { Future serve({FirebaseWebAppActionController? controller}) async { await firebaseWebAppServe(options.path, options.deployOptions, - deployDir: options.deployDir, controller: controller); + controller: controller); } Future deploy({FirebaseWebAppActionController? controller}) async { - await firebaseWebAppDeploy( - options.path, - deployDir: options.deployDir, - options.deployOptions, - controller: controller); + await firebaseWebAppDeploy(options.path, options.deployOptions, + deployDir: options.deployDir, controller: controller); } Future buildAndServe( diff --git a/packages/firebase_build/lib/src/firebase_deploy.dart b/packages/firebase_build/lib/src/firebase_deploy.dart index aa0fa9a..40dc50b 100644 --- a/packages/firebase_build/lib/src/firebase_deploy.dart +++ b/packages/firebase_build/lib/src/firebase_deploy.dart @@ -3,12 +3,13 @@ import 'dart:io'; import 'package:path/path.dart'; import 'package:process_run/shell.dart'; import 'package:tekartik_deploy/fs_deploy.dart'; +import 'package:tekartik_web_publish/web_publish.dart'; var firebaseDefaultWebDeployDir = join(firebaseDefaultHostingDir, 'public'); var firebaseDefaultDeployDir = firebaseDefaultWebDeployDir; var firebaseDefaultHostingDir = join('deploy', 'firebase', 'hosting'); -class FirebaseDeployOptions { +class FirebaseDeployOptions implements WebAppDeployOptions { String projectId; /// Billable firebase project diff --git a/packages/firebase_build/pubspec.yaml b/packages/firebase_build/pubspec.yaml index ca6e574..8d1c6a5 100644 --- a/packages/firebase_build/pubspec.yaml +++ b/packages/firebase_build/pubspec.yaml @@ -20,5 +20,14 @@ dependencies: url: https://github.com/tekartik/android_utils.dart ref: dart3a version: '>=0.6.1' + tekartik_web_publish: + git: + url: https://github.com/tekartik/app_build.dart + ref: dart3a + path: packages/web_publish dev_dependencies: test: '>=1.14.4' + +dependency_overrides: + tekartik_web_publish: + path: ../web_publish \ No newline at end of file diff --git a/packages/firebase_build_menu_flutter/pubspec.yaml b/packages/firebase_build_menu_flutter/pubspec.yaml index fbac3a3..a1fbcfe 100644 --- a/packages/firebase_build_menu_flutter/pubspec.yaml +++ b/packages/firebase_build_menu_flutter/pubspec.yaml @@ -54,5 +54,7 @@ dev_dependencies: dependency_overrides: tekartik_firebase_build: path: ../firebase_build + tekartik_web_publish: + path: ../web_publish executables: fbm: fbm diff --git a/packages/web_publish/.gitignore b/packages/web_publish/.gitignore new file mode 100644 index 0000000..3cceda5 --- /dev/null +++ b/packages/web_publish/.gitignore @@ -0,0 +1,7 @@ +# https://dart.dev/guides/libraries/private-files +# Created by `dart pub` +.dart_tool/ + +# Avoid committing pubspec.lock for library packages; see +# https://dart.dev/guides/libraries/private-files#pubspeclock. +pubspec.lock diff --git a/packages/web_publish/README.md b/packages/web_publish/README.md new file mode 100644 index 0000000..03f4ce5 --- /dev/null +++ b/packages/web_publish/README.md @@ -0,0 +1,14 @@ +# tekartik_web_publish + +Web publish helper. + +## Setup + +```yaml +dependencies: + tekartik_web_publish: + git: + url: https://github.com/tekartik/app_build.dart + ref: dart3a + path: packages/web_publish +``` \ No newline at end of file diff --git a/packages/web_publish/analysis_options.yaml b/packages/web_publish/analysis_options.yaml new file mode 100644 index 0000000..cc6d73a --- /dev/null +++ b/packages/web_publish/analysis_options.yaml @@ -0,0 +1,6 @@ +# tekartik analysis_options extension +include: package:tekartik_lints/strict.yaml + +linter: + rules: + - public_member_api_docs \ No newline at end of file diff --git a/packages/web_publish/lib/src/build_to_deploy.dart b/packages/web_publish/lib/src/build_to_deploy.dart new file mode 100644 index 0000000..7e32e49 --- /dev/null +++ b/packages/web_publish/lib/src/build_to_deploy.dart @@ -0,0 +1,34 @@ +import 'dart:io'; + +import 'package:path/path.dart'; +import 'package:tekartik_deploy/fs_deploy.dart'; + +String _fixFolder(String path, String folder) { + if (isAbsolute(folder)) { + return normalize(folder); + } + return normalize(absolute(join(path, folder))); +} + +/// Copy to deploy using deploy.yaml +Future webAppBuildToDeploy(String path, + { + /// deploy dir from path + required String deployDir, + + /// Build folder from path + required String buildDir}) async { + buildDir = _fixFolder(path, buildDir); + deployDir = _fixFolder(path, deployDir); + + var deployFile = File(join(buildDir, 'deploy.yaml')); + // ignore: avoid_slow_async_io + if (!await deployFile.exists()) { + throw StateError('Missing deploy.yaml file ($deployFile)'); + } + await fsDeploy( + options: FsDeployOptions()..noSymLink = true, + yaml: deployFile, + src: Directory(buildDir), + dst: Directory(deployDir)); +} diff --git a/packages/web_publish/lib/src/deploy_common.dart b/packages/web_publish/lib/src/deploy_common.dart new file mode 100644 index 0000000..7b879f5 --- /dev/null +++ b/packages/web_publish/lib/src/deploy_common.dart @@ -0,0 +1,19 @@ +import 'package:path/path.dart'; + +/// Web deploy options. +abstract class WebAppDeployOptions {} + +/// Surge web app deployment. +final surgeWebAppDeployDirDefault = join('deploy', 'surge'); + +/// Firebase web app deployment. +final firebaseWebAppDeployDirDefault = join('deploy', 'firebase'); + +/// Surge web app deployment. +class SurgeWebAppDeployOptions implements WebAppDeployOptions { + /// Domain (domain.surge.sh). + final String domain; + + /// Constructor. + SurgeWebAppDeployOptions({required this.domain}); +} diff --git a/packages/web_publish/lib/src/surge_deploy.dart b/packages/web_publish/lib/src/surge_deploy.dart new file mode 100644 index 0000000..61bb62b --- /dev/null +++ b/packages/web_publish/lib/src/surge_deploy.dart @@ -0,0 +1,22 @@ +import 'dart:io'; + +import 'package:process_run/shell.dart'; +import 'package:tekartik_web_publish/src/deploy_common.dart'; + +/// Surge deployer +class SurgeWebAppDeployer { + /// The deploy path + final String path; + + /// The deploy options. + final SurgeWebAppDeployOptions options; + + /// Constructor. + SurgeWebAppDeployer({required this.path, required this.options}); + + /// Deploy. + Future deploy() async { + await Shell().cd(path).run('surge . --domain ${options.domain}'); + stdout.writeln('Deployed to https://${options.domain}'); + } +} diff --git a/packages/web_publish/lib/surge_web_publish.dart b/packages/web_publish/lib/surge_web_publish.dart new file mode 100644 index 0000000..6118f33 --- /dev/null +++ b/packages/web_publish/lib/surge_web_publish.dart @@ -0,0 +1,6 @@ +export 'src/deploy_common.dart' + show + SurgeWebAppDeployOptions, + surgeWebAppDeployDirDefault, + firebaseWebAppDeployDirDefault; +export 'src/surge_deploy.dart' show SurgeWebAppDeployer; diff --git a/packages/web_publish/lib/web_publish.dart b/packages/web_publish/lib/web_publish.dart new file mode 100644 index 0000000..0cb898b --- /dev/null +++ b/packages/web_publish/lib/web_publish.dart @@ -0,0 +1,2 @@ +export 'src/build_to_deploy.dart' show webAppBuildToDeploy; +export 'src/deploy_common.dart' show WebAppDeployOptions; diff --git a/packages/web_publish/pubspec.yaml b/packages/web_publish/pubspec.yaml new file mode 100644 index 0000000..638849c --- /dev/null +++ b/packages/web_publish/pubspec.yaml @@ -0,0 +1,26 @@ +name: tekartik_web_publish +description: Web publishing helpers +version: 1.0.0 +publish_to: none + +environment: + sdk: ^3.4.0 + +# Add regular dependencies here. +dependencies: + path: '>=1.8.0' + process_run: + tekartik_deploy: + git: + url: https://github.com/tekartik/deploy.dart + ref: dart3a + version: '>=0.6.2' +dev_dependencies: + lints: '>=3.0.0' + tekartik_lints: + git: + url: https://github.com/tekartik/common.dart + ref: dart3a + path: packages/lints + + test: '>=1.24.0'