diff --git a/CHANGELOG.md b/CHANGELOG.md index 1b29a40..828c3a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,10 @@ This project follows [Semantic Versioning 2.0.0](https://semver.org/spec/v2.0.0. ## [Unreleased] +### ✨ New Features + +- **Routing Config**: Generate `config/routing.dart` with URL strategy setting during `magic install` — enables clean web URLs via `url_strategy: 'path'` + --- ## [0.0.1-alpha.4] - 2026-04-06 diff --git a/CLAUDE.md b/CLAUDE.md index d118ad0..adf8433 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -31,7 +31,7 @@ lib/src/ │ └── install_stubs.dart # Install-specific stub utilities └── helpers/ # Static utilities: file I/O, YAML, console styling, config editing -assets/stubs/ # .stub templates (14 generator + 30 install stubs) +assets/stubs/ # .stub templates (17 generator + 19 install stubs) ``` **Lifecycle**: `bin/magic.dart` → `Kernel.handle(args)` → lookup command by `args[0]` → `command.configure(parser)` → parse args → `command.handle()` diff --git a/README.md b/README.md index 840248e..9ef9e08 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,7 @@ lib/ │ ├── database.dart │ ├── logging.dart │ ├── network.dart +│ ├── routing.dart │ └── view.dart ├── app/ │ ├── controllers/ diff --git a/assets/stubs/install/routing_config.stub b/assets/stubs/install/routing_config.stub new file mode 100644 index 0000000..3b10dd3 --- /dev/null +++ b/assets/stubs/install/routing_config.stub @@ -0,0 +1,10 @@ +/// Routing Configuration. +/// +/// Controls URL strategy and other routing behavior. +/// Set `'url_strategy'` to `'path'` for clean web URLs (/dashboard instead of /#/dashboard). +/// See: https://magic.fluttersdk.com/docs/basics/routing#url-strategy +Map get routingConfig => { + 'routing': { + 'url_strategy': null, // 'path' for clean URLs on web, null for default hash strategy + }, +}; diff --git a/lib/src/commands/install_command.dart b/lib/src/commands/install_command.dart index 1a41d22..bc91b90 100644 --- a/lib/src/commands/install_command.dart +++ b/lib/src/commands/install_command.dart @@ -263,6 +263,11 @@ class InstallCommand extends Command { InstallStubs.viewConfigContent(), ); + _writeIfNotExists( + path.join(root, 'lib/config/routing.dart'), + InstallStubs.routingConfigContent(), + ); + if (!withoutAuth) { _writeIfNotExists( path.join(root, 'lib/config/auth.dart'), @@ -364,10 +369,15 @@ class InstallCommand extends Command { final configImports = [ "import 'config/app.dart';", + "import 'config/routing.dart';", "import 'config/view.dart';", ]; - final configFactories = ['() => appConfig', '() => viewConfig']; + final configFactories = [ + '() => appConfig', + '() => routingConfig', + '() => viewConfig', + ]; if (!withoutAuth) { configImports.add("import 'config/auth.dart';"); diff --git a/lib/src/stubs/install_stubs.dart b/lib/src/stubs/install_stubs.dart index 09e02e6..49b0504 100644 --- a/lib/src/stubs/install_stubs.dart +++ b/lib/src/stubs/install_stubs.dart @@ -123,6 +123,14 @@ class InstallStubs { return StubLoader.load('install/broadcasting_config'); } + /// Generates `lib/config/routing.dart` with URL strategy config. + /// + /// Default `url_strategy: null` preserves hash-based URLs. + /// Set to `'path'` for clean web URLs (`/dashboard` instead of `/#/dashboard`). + static String routingConfigContent() { + return StubLoader.load('install/routing_config'); + } + // --------------------------------------------------------------------------- // Service Providers // --------------------------------------------------------------------------- diff --git a/test/commands/install_command_test.dart b/test/commands/install_command_test.dart index 6617c38..f91125f 100644 --- a/test/commands/install_command_test.dart +++ b/test/commands/install_command_test.dart @@ -181,12 +181,13 @@ void main() { ); }); - test('creates all 8 config files', () { + test('creates all 9 config files', () { final configs = [ 'app.dart', 'auth.dart', 'database.dart', 'network.dart', + 'routing.dart', 'view.dart', 'cache.dart', 'logging.dart', @@ -370,7 +371,7 @@ void main() { ); }); - test('imports all 8 configs by default', () async { + test('imports all 9 configs by default', () async { cmd.arguments = parser.parse([]); await cmd.handle(); @@ -382,6 +383,7 @@ void main() { "import 'config/auth.dart'", "import 'config/database.dart'", "import 'config/network.dart'", + "import 'config/routing.dart'", "import 'config/view.dart'", "import 'config/cache.dart'", "import 'config/logging.dart'", @@ -790,15 +792,15 @@ void main() { expect(content, isNot(contains('DatabaseServiceProvider'))); }); - test('creates only 6 config files', () { + test('creates only 7 config files', () { final dir = Directory('${tempDir.path}/lib/config'); final files = dir.listSync().whereType().toList(); expect( files.length, - 6, + 7, reason: - 'Should create exactly 6 config files (app, network, view, cache, logging, broadcasting)', + 'Should create exactly 7 config files (app, network, routing, view, cache, logging, broadcasting)', ); }); });