Skip to content
Open
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
2 changes: 1 addition & 1 deletion AUTHORS
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ Rishabh Singh (cybertheory), UC Berkeley/Pagefelt - Contributor
Wahab Alshahin (walsha2) - Contributor
Lucas Goldner (lucas-goldner) - Contributor
Ahmed Fwela (ahmednfwela) - Contributor
Shubham LaV (shubhamvg) - Contributor
Shubham LaV (shubhamlav) - Contributor
Simon Lightfoot (slightfoot) - Contributor
Matej Bačo (Meldiron) - Contributor
Simon Binder (simolus3) - Contributor
Expand Down
6 changes: 3 additions & 3 deletions apps/dart_quotes/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,10 @@ environment:
resolution: workspace

dependencies:
cloud_firestore: ^5.4.1
cloud_firestore: ^6.4.0
dart_firebase_admin: ^0.4.1
firebase_auth: ^5.2.1
firebase_core: ^3.4.1
firebase_auth: ^6.5.0
firebase_core: ^4.8.0
jaspr: ^0.23.0
jaspr_router: ^0.8.0

Expand Down
2 changes: 1 addition & 1 deletion examples/backend_serverpod/example_client/pubspec.lock
Original file line number Diff line number Diff line change
Expand Up @@ -162,4 +162,4 @@ packages:
source: hosted
version: "3.1.2"
sdks:
dart: ">=3.6.0 <4.0.0"
dart: ">=3.8.0 <4.0.0"
1 change: 1 addition & 0 deletions examples/flutter_embedding/lib/main.server.options.dart
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ import 'package:flutter_embedding_demo/components/app.dart' as _app;
ServerOptions get defaultServerOptions => ServerOptions(
clientId: 'main.client.dart.js',
clients: {_app.App: ClientTarget<_app.App>('app')},
styles: () => [],
);
2 changes: 1 addition & 1 deletion examples/flutter_embedding/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ environment:
resolution: workspace

dependencies:
firebase_core: ^3.4.1
firebase_core: ^4.8.0
flutter:
sdk: flutter
flutter_riverpod: ^3.0.0
Expand Down
6 changes: 3 additions & 3 deletions examples/flutter_plugin_interop/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ environment:
resolution: workspace

dependencies:
cloud_firestore: ^5.4.1
firebase_auth: ^5.2.1
firebase_core: ^3.4.1
cloud_firestore: ^6.4.0
firebase_auth: ^6.5.0
firebase_core: ^4.8.0
jaspr: ^0.23.0
shared_preferences: ^2.3.2

Expand Down
9 changes: 9 additions & 0 deletions packages/jaspr/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,12 @@
## Unreleased breaking

- Added hot-reload support.

- Added `basePath` property to `AppBinding` to support hosting applications under a sub-path.
- Exposed `basePath` parameter in `testComponents` and `handlerPath` in `ServerTester.request` to support testing under custom base paths.
- Support `analyzer` `^12.1.0`.
- Added a `--port` option to `jaspr build` for configuring the server port used during static generation.

## 0.23.1

- Fixed expression compilation when debugging a client-side application with an AOT installed CLI.
Expand Down
22 changes: 20 additions & 2 deletions packages/jaspr/lib/src/client/client_binding.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'dart:async';
import 'dart:developer';

import 'package:universal_web/js_interop.dart';
import 'package:universal_web/web.dart' as web;
Expand All @@ -13,11 +14,28 @@ class ClientAppBinding extends AppBinding with ComponentsBinding {
@override
bool get isClient => true;

ClientAppBinding() {
assert(() {
registerExtension('ext.jaspr.reassemble', (method, parameters) async {
// ignore: invalid_use_of_protected_member
rootElement?.visitChildren((element) => element.reassemble());
return ServiceExtensionResponse.result('{}');
});
return true;
}());
}

static final String _baseOrigin = () {
final base = web.document.querySelector('head>base') as web.HTMLBaseElement?;
return base?.href ?? web.window.location.origin;
final hasBase = web.document.querySelector('head>base') != null;
return hasBase ? web.document.baseURI : web.window.location.origin;
}();

@override
String get basePath {
final path = Uri.parse(_baseOrigin).path;
return path.isEmpty ? '/' : path;
}

@override
String get currentUrl {
if (_baseOrigin.length > web.window.location.href.length) {
Expand Down
3 changes: 3 additions & 0 deletions packages/jaspr/lib/src/foundation/binding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ abstract class AppBinding with SchedulerBinding {
/// On the client, this is the currently visited url in the browser.
String get currentUrl;

/// The base path of the application.
String get basePath => '/';

/// The [Element] that is at the root of the hierarchy.
///
/// This is initialized when `runApp` is called.
Expand Down
15 changes: 15 additions & 0 deletions packages/jaspr/lib/src/framework/framework.dart
Original file line number Diff line number Diff line change
Expand Up @@ -747,6 +747,21 @@ abstract class Element implements BuildContext {
}
}

/// Called whenever the application is reassembled during debugging, for
/// example during hot reload.
///
/// This method should rerun any initialization logic that depends on global
/// state, for example, image loading from asset bundles (since the asset
/// bundle may have changed).
@mustCallSuper
@protected
void reassemble() {
markNeedsBuild();
visitChildren((Element child) {
child.reassemble();
});
}

void _updateDepth(int parentDepth) {
final int expectedDepth = parentDepth + 1;
if (depth < expectedDepth) {
Expand Down
23 changes: 23 additions & 0 deletions packages/jaspr/lib/src/framework/stateful_component.dart
Original file line number Diff line number Diff line change
Expand Up @@ -578,6 +578,23 @@ abstract class State<T extends StatefulComponent> {
@protected
@mustCallSuper
void didChangeDependencies() {}

/// Called whenever the application is reassembled during debugging, for
/// example during hot reload.
///
/// This method should rerun any initialization logic that depends on global
/// state, for example, image loading from asset bundles (since the asset
/// bundle may have changed).
///
/// This function will only be called during development. In release builds,
/// the `ext.jaspr.reassemble` hook is not available, and so this code will
/// never execute.
///
/// Implementations of this method should end with a call to the inherited
/// method, as in `super.reassemble()`.
@protected
@mustCallSuper
void reassemble() {}
}

/// Mixin on [State] that preloads state on the server
Expand Down Expand Up @@ -727,6 +744,12 @@ class StatefulElement extends BuildableElement {
super.deactivate();
}

@override
void reassemble() {
state.reassemble();
super.reassemble();
}

@override
void unmount() {
super.unmount();
Expand Down
8 changes: 6 additions & 2 deletions packages/jaspr/lib/src/server/render_functions.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import 'run_app.dart';
import 'server_app.dart';
import 'server_binding.dart';

typedef RequestLike = ({String url, Headers headers});
typedef RequestLike = ({String url, String basePath, Headers headers});

/// Performs the rendering process and provides the created [AppBinding] to [setup].
///
Expand All @@ -24,7 +24,11 @@ Future<ResponseLike> render(SetupFunction setup, Request request, FileLoader loa
url = '/$url';
}

final RequestLike r = (url: url, headers: Headers.from(request.headersAll));
final RequestLike r = (
url: url,
basePath: request.handlerPath,
headers: Headers.from(request.headersAll),
);

if (!Jaspr.useIsolates) {
final binding = ServerAppBinding(r, loadFile: loadFile);
Expand Down
3 changes: 3 additions & 0 deletions packages/jaspr/lib/src/server/server_binding.dart
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,9 @@ class ServerAppBinding extends AppBinding with ComponentsBinding {
@override
bool get isClient => false;

@override
String get basePath => request.basePath;

@override
String get currentUrl => request.url;

Expand Down
22 changes: 18 additions & 4 deletions packages/jaspr/lib/src/server/server_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import 'dart:convert';
import 'dart:io';

import 'package:http/http.dart' as http;
import 'package:http/retry.dart' as retry;
import 'package:path/path.dart';
import 'package:shelf/shelf.dart';
import 'package:shelf_gzip/shelf_gzip.dart';
Expand Down Expand Up @@ -80,7 +81,12 @@ Handler createHandler(
var isAllowedPath = false;
final segment = request.url.pathSegments.lastOrNull ?? '';
if (!segment.contains('.')) {
isAllowedPath = true;
if (kDebugMode) {
isAllowedPath =
!request.url.path.contains('dwds') && !request.url.path.startsWith(r'$') && request.url.path != 'null';
} else {
isAllowedPath = true;
}
} else {
final suffix = segment.split('.').last;
if (Jaspr.allowedPathSuffixes.contains(suffix)) {
Expand Down Expand Up @@ -117,9 +123,17 @@ Future<String?> Function(String) proxyFileLoader(Request req, Handler proxyHandl
}

Handler createProxyHandler(http.Client? client) {
final handler = proxyHandler('http://localhost:$jasprProxyPort/', client: client);
// Determine and pass the base path to the proxy handler so it can rewrite DWDS handler paths correctly.
return (req) => handler(req.change(headers: {'jaspr_base_path': req.handlerPath}));
final c = retry.RetryClient(client ?? http.Client(), whenError: (e, _) => e is http.ClientException);
final handler = proxyHandler('http://localhost:$jasprProxyPort/', client: c);
return (req) async {
try {
return await handler(req);
} on http.ClientException {
return Response(503, headers: {'Retry-After': '1'});
} on SocketException {
return Response(503, headers: {'Retry-After': '1'});
}
};
}

// coverage:ignore-start
Expand Down
6 changes: 5 additions & 1 deletion packages/jaspr/test/server/child_list_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,11 @@ import 'package:shelf/src/headers.dart';
void main() {
group('child list', () {
Future<RenderObjectElement> renderServerApp(Component app) async {
final binding = ServerAppBinding((url: '/', headers: Headers.empty()), loadFile: (_) async => null);
final binding = ServerAppBinding((
url: '/',
basePath: '/',
headers: Headers.empty(),
), loadFile: (_) async => null);
binding.initializeOptions(ServerOptions());
binding.attachRootComponent(app);

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ class ClientOptionsBuilder implements Builder {
}
}

bool _triedRunningFlutter = false;

Future<List<Plugin>> loadWebPlugins(BuildStep buildStep) async {
final pluginsDependenciesId = AssetId(buildStep.inputId.package, '.flutter-plugins-dependencies');

Expand All @@ -136,7 +138,8 @@ Future<List<Plugin>> loadWebPlugins(BuildStep buildStep) async {

var content = await readPluginsDependencies();

if (content == null) {
if (content == null && !_triedRunningFlutter) {
_triedRunningFlutter = true;
try {
final result = await Process.run('flutter', ['packages', 'get']);
if (result.exitCode != 0) {
Expand Down
2 changes: 1 addition & 1 deletion packages/jaspr_builder/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ topics:
- build-runner

dependencies:
analyzer: ^10.0.0
analyzer: ^12.1.0
build: ^4.0.0
collection: ^1.15.0
dart_style: ^3.0.0
Expand Down
9 changes: 8 additions & 1 deletion packages/jaspr_cli/lib/src/commands/build_command.dart
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,13 @@ class BuildCommand extends BaseCommand with ProxyHelper, FlutterHelper {
help: 'Compile to a specific target architecture (only in server mode)',
allowed: ['arm', 'arm64', 'riscv64', 'x64'],
);
argParser.addOption(
'port',
abbr: 'p',
help:
'Specify a port to run the server on during static generation. '
'Defaults to {jaspr.port} from pubspec.yaml or "$defaultServePort".',
);
argParser.addFlag('experimental-wasm', help: 'Compile to wasm', negatable: false);
argParser.addMultiOption(
'extra-js-compiler-option',
Expand Down Expand Up @@ -223,7 +230,7 @@ class BuildCommand extends BaseCommand with ProxyHelper, FlutterHelper {
final List<String> queuedRoutes = [];

final serverStartedCompleter = Completer<void>();
final serverPort = project.port ?? defaultServePort;
final serverPort = argResults!.option('port') ?? project.port ?? defaultServePort;

await startProxy(
serverProxyPort,
Expand Down
Loading
Loading