| title | Web Platform Support |
|---|---|
| sidebar_position | 12 |
| id | web-platform-support |
| license | Licensed to the Apache Software Foundation (ASF) under one or more contributor license agreements. See the NOTICE file distributed with this work for additional information regarding copyright ownership. The ASF licenses this file to You under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. |
Fory Dart supports Dart VM/AOT, Flutter, browser, and Flutter web builds
through generated serializers and platform-specific implementations.
The public API and registration flow are the same across these platforms, but
web builds have stricter integer precision rules because Dart int is
represented by JavaScript numbers.
Fory Dart supports:
- Dart VM/JIT applications.
- Dart AOT/native applications.
- Flutter mobile and desktop applications.
- Dart applications compiled to JavaScript for browsers.
- Flutter web applications.
- Generated
@ForyStructserializers and manually registered serializers on all supported targets. - Ordinary generated inheritance, including typed cross-library private-field companions.
- External structural serializers generated with
@ForyStruct(target: ...).
Fory Dart uses explicit registration instead of runtime reflection. For annotated structs, run code generation and register the generated serializer before serializing or deserializing values:
import 'package:fory/fory.dart';
part 'account.fory.dart';
@ForyStruct()
class Account {
Account();
String name = '';
Int64 sequence = Int64(0);
}
void main() {
final fory = Fory();
AccountForyModule.register(
fory,
Account,
name: 'example.Account',
);
final bytes = fory.serialize(Account()..name = 'web');
final account = fory.deserialize<Account>(bytes);
print(account.name);
}Generate the companion file before building or testing:
cd dart/packages/fory
dart run build_runner buildThe registration call is the same on VM/AOT, Flutter, and web. Custom
serializers use registerSerializer(...); generated structs use the generated
register wrapper.
Included inherited fields use the same statically generated code on every
platform. ignoreInheritedPrivateFields is applied during generation and adds
no runtime branch. See Struct Inheritance for cross-library
provider setup.
Dart VM int values are signed 64-bit values. Dart web int values are backed
by JavaScript numbers and are precise only in the JS-safe integer range:
-9007199254740991 <= value <= 9007199254740991
Use this rule when choosing field types:
| Logical value | Recommended Dart field type on web | Notes |
|---|---|---|
| Signed 64-bit value within JS-safe range | int |
Works with default int64 mapping and @ForyField(type: Int64Type(...)) encodings. |
| Full signed 64-bit range | Int64 |
Preserves values outside the JS-safe range. |
| Unsigned 64-bit value | Uint64 |
Required for values that do not fit in signed or JS-safe Dart int. |
| 8/16/32-bit integer | int + @ForyField(type: ...) |
Use explicit field metadata to match peer languages exactly. |
@ForyField(type: Int64Type(...)) controls the wire encoding of a Dart int
field:
@ForyStruct()
class SafeCounter {
SafeCounter();
@ForyField(type: Int64Type(encoding: Encoding.tagged))
int count = 0; // keep web values inside the JS-safe range
}It does not make Dart int capable of storing every 64-bit value on web. For
full-range signed values, use Int64:
@ForyStruct()
class FullRangeCounter {
FullRangeCounter();
Int64 count = Int64(0);
}For unsigned values, use Uint64:
@ForyStruct()
class StorageExtent {
StorageExtent();
Uint64 byteOffset = Uint64(0);
}Custom serializers can use the same Buffer, WriteContext, and ReadContext
APIs on VM/AOT, Flutter, and web. For 64-bit values:
- Use
buffer.writeInt64(Int64(...))andbuffer.readInt64()for full-range signed 64-bit values. - Use
buffer.writeUint64(Uint64(...))andbuffer.readUint64()for full-range unsigned 64-bit values. - Use
writeInt64FromInt,writeVarInt64FromInt, and matchingAsIntreads only when the value is intended to be a Dartintand therefore must stay JS-safe on web.
Example:
final class OffsetSerializer extends Serializer<StorageExtent> {
const OffsetSerializer();
@override
void write(WriteContext context, StorageExtent value) {
context.buffer.writeUint64(value.byteOffset);
}
@override
StorageExtent read(ReadContext context) {
return StorageExtent()..byteOffset = context.buffer.readUint64();
}
}List, Set, Map, Uint8List, numeric typed arrays, Int64List, and
Uint64List are supported on web. The Int64List and Uint64List
implementations preserve 64-bit values without depending on JavaScript integer
precision. Use the Fory wrapper list types when the schema is array<int64>
or array<uint64>.
Run the package tests in both VM and Chrome when changing code that must work on web:
cd dart/packages/fory
dart run build_runner build
dart test
dart test -p chromeFor an application smoke test, also compile and execute the actual generated entry point:
dart compile js --fatal-warnings bin/app.dart -o build/app.js
node build/app.jsUse a model with the same hierarchy and imports as the production application when validating cross-library private fields. Compilation alone does not prove that registration and round-trip execution work.
If Chrome tests fail with a stale generated file or missing part file, rerun
build_runner and then retry the test command from dart/packages/fory.
The serializer is trying to write a Dart int as a signed 64-bit value on web,
but the value is outside the range that JavaScript numbers can represent
exactly. Change the field type to Int64, or keep the value inside the JS-safe
range.
The deserializer read a full-range Int64, but the target field or custom
serializer asked for a Dart int. Change the field type to Int64, or decode
with readInt64() instead of an AsInt helper.
The code is converting a Uint64 to Dart int on web. Keep the value as
Uint64 unless the application has already validated that it is in the
JS-safe non-negative range.