Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -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()`
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ lib/
│ ├── database.dart
│ ├── logging.dart
│ ├── network.dart
│ ├── routing.dart
│ └── view.dart
├── app/
│ ├── controllers/
Expand Down
10 changes: 10 additions & 0 deletions assets/stubs/install/routing_config.stub
Original file line number Diff line number Diff line change
@@ -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<String, dynamic> get routingConfig => {
'routing': {
'url_strategy': null, // 'path' for clean URLs on web, null for default hash strategy
},
};
12 changes: 11 additions & 1 deletion lib/src/commands/install_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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'),
Expand Down Expand Up @@ -364,10 +369,15 @@ class InstallCommand extends Command {

final configImports = <String>[
"import 'config/app.dart';",
"import 'config/routing.dart';",
"import 'config/view.dart';",
];

final configFactories = <String>['() => appConfig', '() => viewConfig'];
final configFactories = <String>[
'() => appConfig',
'() => routingConfig',
'() => viewConfig',
];

if (!withoutAuth) {
configImports.add("import 'config/auth.dart';");
Expand Down
8 changes: 8 additions & 0 deletions lib/src/stubs/install_stubs.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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
// ---------------------------------------------------------------------------
Expand Down
12 changes: 7 additions & 5 deletions test/commands/install_command_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand Down Expand Up @@ -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();

Expand All @@ -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'",
Expand Down Expand Up @@ -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<File>().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)',
);
});
});
Expand Down