Skip to content
Draft
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: 2 additions & 2 deletions apps/website/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ version: 0.1.8
publish_to: none

environment:
sdk: '>=3.10.0 <4.0.0'
sdk: ">=3.10.0 <4.0.0"

resolution: workspace

Expand All @@ -20,7 +20,7 @@ dependencies:

dev_dependencies:
build_runner: ^2.6.0
build_web_compilers: ^4.4.6
build_web_compilers: ^4.6.0
jaspr_builder: ^0.23.0

jaspr:
Expand Down
4 changes: 3 additions & 1 deletion docs/api/config.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,9 @@ There are currently the following configuration options available:
It is optional and defaults to `inline` for **static** and **server** mode and `standalone` for **client** mode.

<Warning>
When using `standalone`, all libraries containing `@css` definitions are executed during the build process using the Dart VM. Importing web-only libraries like `dart:js_interop` or `package:web` will lead to build errors. See [Using Platform Libraries](/dev/server#using-platform-libraries) for ways to avoid this.
When using `inline`, all libraries containing `@css` definitions are executed during the pre-rendering process on the server. Therefore, importing web-only libraries like `dart:js_interop` or `package:web` will lead to compilation errors. See [Using Platform Libraries](/dev/server#using-platform-libraries) for ways to avoid this.

When using `standalone`, the CSS is generated during the serve/build step in a custom VM environment that also supports importing web-only libraries. During development, styles are automatically hot-reloaded when the source files are changed.
</Warning>
</Property>

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

- Added hot-reload support.
- Added hot-reloading of generated stylesheets in `standalone` mode.
- Style generation in `standalone` mode now also works when importing web libraries like `package:web` or `dart:js_interop`.

- 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.
Expand Down
4 changes: 4 additions & 0 deletions packages/jaspr/analysis_options.yaml
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
include: package:jaspr_repo/core.yaml

analyzer:
exclude:
- lib/src/stub/web/**

linter:
rules:
comment_references: true
46 changes: 46 additions & 0 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:convert';
import 'dart:developer';

import 'package:universal_web/js_interop.dart';
Expand All @@ -21,6 +22,51 @@ class ClientAppBinding extends AppBinding with ComponentsBinding {
rootElement?.visitChildren((element) => element.reassemble());
return ServiceExtensionResponse.result('{}');
});
registerExtension('ext.jaspr.reload_stylesheets', (method, parameters) async {
final urls = (jsonDecode(parameters['urls']!) as List).cast<String>();

void reloadStylesheet(web.Element oldLink, String url, {int retries = 5}) {
final newLink = web.document.createElement('link') as web.HTMLLinkElement;
newLink.rel = 'stylesheet';
newLink.href = '$url?v=${DateTime.now().millisecondsSinceEpoch}';

StreamSubscription<void>? loadSub;
StreamSubscription<void>? errorSub;

void cleanup() {
loadSub?.cancel();
errorSub?.cancel();
}

loadSub = web.EventStreamProvider<web.Event>('load').forElement(newLink).listen((_) {
cleanup();
oldLink.remove();
});

errorSub = web.EventStreamProvider<web.Event>('error').forElement(newLink).listen((_) {
cleanup();
newLink.remove();
if (retries > 0) {
Future.delayed(const Duration(milliseconds: 500), () {
reloadStylesheet(oldLink, url, retries: retries - 1);
});
} else {
print('Failed to reload stylesheet $url after 5 retries.');
}
});

oldLink.parentNode?.insertBefore(newLink, oldLink.nextSibling);
}

// Reload all stylesheet <link> tags.
for (final url in urls) {
final link = web.document.querySelector('link[rel="stylesheet"][href^="$url"]');
if (link != null) {
reloadStylesheet(link, url);
}
}
return ServiceExtensionResponse.result('{}');
});
return true;
}());
}
Expand Down
5 changes: 4 additions & 1 deletion packages/jaspr/lib/src/server/server_handler.dart
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,10 @@ Future<String?> Function(String) proxyFileLoader(Request req, Handler proxyHandl
}

Handler createProxyHandler(http.Client? client) {
final c = retry.RetryClient(client ?? http.Client(), whenError: (e, _) => e is http.ClientException);
final c = retry.RetryClient(
client ?? http.Client(),
whenError: (e, _) => e is http.ClientException || e is SocketException,
);
final handler = proxyHandler('http://localhost:$jasprProxyPort/', client: c);
return (req) async {
try {
Expand Down
Loading