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
3 changes: 3 additions & 0 deletions packages/google_fonts/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
## NEXT

- Adds `config`, `pendingFonts`, and `getTextTheme` to `GoogleFontsLite`.
- Decouples internal base library from the main entry point to ensure complete tree-shakability.
- Adds code samples and documentation for `GoogleFontsLite`.
- Adds the `GoogleFontsLite` class to allow tree-shaking unused font code.
- Added fonts:
- `Akt`
Expand Down
26 changes: 24 additions & 2 deletions packages/google_fonts/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,10 +115,32 @@ return MaterialApp(
```

### Lower build size
The `GoogleFontsLite` class is a replacement for the `GoogleFonts` class containing only a map of all fonts and the `getFont` function. Using *only* `GoogleFontsLite` allows the Dart compiler to tree-shake most of the package's code, yielding a significant reduction in build size.
The `GoogleFontsLite` class is an alternative entry point containing only a map of all fonts and dynamic font resolution methods. Using *only* `GoogleFontsLite` allows the Dart compiler to tree-shake all unused font methods, yielding a significant reduction in build size.

To allow the Dart compiler to tree-shake unused fonts, import `package:google_fonts/google_fonts_lite.dart` instead of `package:google_fonts/google_fonts.dart`.

Do not import `package:google_fonts/google_fonts.dart` when optimizing for bundle size, as that imports the generated static font methods.

<?code-excerpt "readme_excerpts.dart (GoogleFontsLite)"?>
```dart
Widget liteExamples(BuildContext context) {
return Column(
children: <Widget>[
// Single text style:
Text('Dynamic font with minimal bundle size', style: GoogleFontsLite.getFont('Lato')),
// Custom text theme:
Theme(
data: ThemeData(textTheme: GoogleFontsLite.getTextTheme('Lato')),
child: const Text('Themed text'),
),
],
);
}
```


### Visual font swapping
To avoid visual font swaps that occur when a font is loading, use [FutureBuilder](https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html) and [GoogleFonts.pendingFonts()](https://pub.dev/documentation/google_fonts/latest/google_fonts/GoogleFonts/pendingFonts.html).
To avoid visual font swaps that occur when a font is loading, use [FutureBuilder](https://api.flutter.dev/flutter/widgets/FutureBuilder-class.html) and [GoogleFonts.pendingFonts()](https://pub.dev/documentation/google_fonts/latest/google_fonts/GoogleFonts/pendingFonts.html) (or `GoogleFontsLite.pendingFonts()`).

See the [example app](https://pub.dev/packages/google_fonts/example).

Expand Down
16 changes: 16 additions & 0 deletions packages/google_fonts/example/lib/readme_excerpts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -126,3 +126,19 @@ void main() {
}

// #enddocregion LicenseRegistration

// #docregion GoogleFontsLite
Widget liteExamples(BuildContext context) {
return Column(
children: <Widget>[
// Single text style:
Text('Dynamic font with minimal bundle size', style: GoogleFontsLite.getFont('Lato')),
// Custom text theme:
Theme(
data: ThemeData(textTheme: GoogleFontsLite.getTextTheme('Lato')),
child: const Text('Themed text'),
),
],
);
}
// #enddocregion GoogleFontsLite
2 changes: 1 addition & 1 deletion packages/google_fonts/generator/google_fonts.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class GoogleFonts {
/// ```dart
/// GoogleFonts.config.allowRuntimeFetching = false;
/// ```
static final GoogleFontsConfig config = GoogleFontsConfig();
static final GoogleFontsConfig config = sharedGoogleFontsConfig;

/// Returns a [Future] which resolves when requested fonts have finished
/// loading and are ready to be rendered on screen.
Expand Down
95 changes: 95 additions & 0 deletions packages/google_fonts/generator/google_fonts_lite.tmpl
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'dart:ui' as ui;
import 'package:flutter/material.dart';

import 'google_fonts_base.dart';
import 'google_fonts_config.dart';
import 'google_fonts_descriptor.dart';
import 'google_fonts_variant.dart';

Expand All @@ -18,6 +19,67 @@ import 'google_fonts_variant.dart';
/// each font, [GoogleFontsLite] provides dynamic font lookup via [getFont]
/// and [fontsMap], allowing unused font methods to be tree-shaken by the compiler.
abstract final class GoogleFontsLite {
/// Configuration for the [GoogleFontsLite] library.
///
/// Use this to define custom behavior of the GoogleFonts library in your app.
/// For example, if you do not want the GoogleFonts library to make any HTTP
/// requests for fonts, add the following snippet to your app's `main` method.
///
/// ```dart
/// GoogleFontsLite.config.allowRuntimeFetching = false;
/// ```
static final GoogleFontsConfig config = sharedGoogleFontsConfig;

/// Returns a [Future] which resolves when requested fonts have finished
/// loading and are ready to be rendered on screen.
///
/// Usage:
/// ```dart
/// GoogleFontsLite.getFont('Lato');
/// GoogleFontsLite.getTextTheme('Pacifico');
/// await GoogleFontsLite.pendingFonts(); // <-- waits until Lato and Pacifico files have loaded.
/// ```
///
/// To keep things tidy, one can also pass in requested fonts as a list
/// to [pendingFonts].
///
/// ```dart
/// await GoogleFontsLite.pendingFonts(<dynamic>[
/// GoogleFontsLite.getFont('Lato'),
/// GoogleFontsLite.getTextTheme('Pacifico'),
/// ]);
/// ```
///
/// To avoid visual font swaps that occur when a font is loading,
/// consider using [FutureBuilder]. Note: This future cannot be created in
/// [build], as described in [FutureBuilder]'s documentation.
///
/// ```dart
/// late Future<List<void>> googleFontsPending;
///
/// @override
/// void initState() {
/// super.initState();
/// googleFontsPending = GoogleFontsLite.pendingFonts(<dynamic>[
/// GoogleFontsLite.getFont('Lato'),
/// ]);
/// }
///
/// @override
/// Widget build(BuildContext context) {
/// return FutureBuilder(
/// future: googleFontsPending,
/// builder: (context, snapshot) {
/// if (snapshot.connectionState != ConnectionState.done) {
/// return const SizedBox();
/// }
/// return Text('Lato text', style: GoogleFontsLite.getFont('Lato'));
/// },
/// );
/// }
/// ```
static Future<List<void>> pendingFonts([List<dynamic>? _]) => Future.wait(pendingFontFutures);

/// Map of all available Google Fonts families to their variant file descriptors.
static final Map<String, Map<GoogleFontsVariant, GoogleFontsFile>> fontsMap = {
{{#fontEntries}}
Expand Down Expand Up @@ -86,4 +148,37 @@ abstract final class GoogleFontsLite {
decorationThickness: decorationThickness,
);
}

/// Retrieve a text theme by its font family name.
///
/// Applies the given font family from Google Fonts to the given [textTheme]
/// and returns the resulting [textTheme].
///
/// Note: [fontFamily] is case-sensitive.
///
/// Parameter [fontFamily] must not be `null`. Throws an [ArgumentError] if no
/// font by name [fontFamily] exists.
static TextTheme getTextTheme(String fontFamily, [TextTheme? textTheme]) {
if (!fontsMap.containsKey(fontFamily)) {
throw ArgumentError("No font family by name '$fontFamily' was found.");
}
Comment thread
Piinks marked this conversation as resolved.
textTheme ??= ThemeData.light().textTheme;
return TextTheme(
displayLarge: getFont(fontFamily, textStyle: textTheme.displayLarge),
displayMedium: getFont(fontFamily, textStyle: textTheme.displayMedium),
displaySmall: getFont(fontFamily, textStyle: textTheme.displaySmall),
headlineLarge: getFont(fontFamily, textStyle: textTheme.headlineLarge),
headlineMedium: getFont(fontFamily, textStyle: textTheme.headlineMedium),
headlineSmall: getFont(fontFamily, textStyle: textTheme.headlineSmall),
titleLarge: getFont(fontFamily, textStyle: textTheme.titleLarge),
titleMedium: getFont(fontFamily, textStyle: textTheme.titleMedium),
titleSmall: getFont(fontFamily, textStyle: textTheme.titleSmall),
bodyLarge: getFont(fontFamily, textStyle: textTheme.bodyLarge),
bodyMedium: getFont(fontFamily, textStyle: textTheme.bodyMedium),
bodySmall: getFont(fontFamily, textStyle: textTheme.bodySmall),
labelLarge: getFont(fontFamily, textStyle: textTheme.labelLarge),
labelMedium: getFont(fontFamily, textStyle: textTheme.labelMedium),
labelSmall: getFont(fontFamily, textStyle: textTheme.labelSmall),
);
}
}
2 changes: 1 addition & 1 deletion packages/google_fonts/lib/google_fonts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,5 +3,5 @@
// found in the LICENSE file.

export 'src/google_fonts_all_parts.dart';
export 'src/google_fonts_config.dart';
export 'src/google_fonts_config.dart' show Config, GoogleFontsConfig;
export 'src/google_fonts_lite.dart';
2 changes: 1 addition & 1 deletion packages/google_fonts/lib/google_fonts_lite.dart
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,5 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

export 'src/google_fonts_config.dart';
export 'src/google_fonts_config.dart' show Config, GoogleFontsConfig;
export 'src/google_fonts_lite.dart';
2 changes: 1 addition & 1 deletion packages/google_fonts/lib/src/google_fonts_all_parts.dart
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ class GoogleFonts {
/// ```dart
/// GoogleFonts.config.allowRuntimeFetching = false;
/// ```
static final GoogleFontsConfig config = GoogleFontsConfig();
static final GoogleFontsConfig config = sharedGoogleFontsConfig;

/// Returns a [Future] which resolves when requested fonts have finished
/// loading and are ready to be rendered on screen.
Expand Down
6 changes: 3 additions & 3 deletions packages/google_fonts/lib/src/google_fonts_base.dart
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,11 @@ import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:http/http.dart' as http;

import '../google_fonts.dart';
import 'file_io.dart' // Stubbed implementation by default.
// Concrete implementation if File IO is available.
if (dart.library.io) 'file_io_desktop_and_mobile.dart'
as file_io;
import 'google_fonts_config.dart';
import 'google_fonts_descriptor.dart';
import 'google_fonts_family_with_variant.dart';
import 'google_fonts_variant.dart';
Expand Down Expand Up @@ -164,7 +164,7 @@ Future<void> loadFontIfNecessary(GoogleFontsDescriptor descriptor) async {
}

// Attempt to load this font via http, unless disallowed.
if (GoogleFonts.config.allowRuntimeFetching) {
if (sharedGoogleFontsConfig.allowRuntimeFetching) {
byteData = _httpFetchFontAndSaveToDevice(familyWithVariantString, descriptor.file);
if (await byteData != null) {
return await loadFontByteData(familyWithVariantString, byteData);
Expand Down Expand Up @@ -250,7 +250,7 @@ Future<ByteData> _httpFetchFontAndSaveToDevice(String fontName, GoogleFontsFile
}

http.Response response;
final http.Client client = GoogleFonts.config.httpClient ?? _httpClient;
final http.Client client = sharedGoogleFontsConfig.httpClient ?? _httpClient;
try {
response = await client.get(uri);
} catch (e) {
Expand Down
9 changes: 9 additions & 0 deletions packages/google_fonts/lib/src/google_fonts_config.dart
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
// found in the LICENSE file.

import 'package:http/http.dart' as http;
import 'package:meta/meta.dart';

/// A collection of properties used to specify custom behavior of the
/// GoogleFonts library.
Expand All @@ -22,3 +23,11 @@ class GoogleFontsConfig {
/// Deprecated. Use [GoogleFontsConfig] instead.
@Deprecated('Use GoogleFontsConfig instead')
typedef Config = GoogleFontsConfig;

/// Shared configuration instance for the Google Fonts library.
///
/// This instance is not exported and is not meant for public consumption.
/// Applications should configure Google Fonts using `GoogleFonts.config` or
/// `GoogleFontsLite.config`.
@internal
final GoogleFontsConfig sharedGoogleFontsConfig = GoogleFontsConfig();
95 changes: 95 additions & 0 deletions packages/google_fonts/lib/src/google_fonts_lite.dart
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import 'dart:ui' as ui;
import 'package:flutter/material.dart';

import 'google_fonts_base.dart';
import 'google_fonts_config.dart';
import 'google_fonts_descriptor.dart';
import 'google_fonts_variant.dart';

Expand All @@ -18,6 +19,67 @@ import 'google_fonts_variant.dart';
/// each font, [GoogleFontsLite] provides dynamic font lookup via [getFont]
/// and [fontsMap], allowing unused font methods to be tree-shaken by the compiler.
abstract final class GoogleFontsLite {
/// Configuration for the [GoogleFontsLite] library.
///
/// Use this to define custom behavior of the GoogleFonts library in your app.
/// For example, if you do not want the GoogleFonts library to make any HTTP
/// requests for fonts, add the following snippet to your app's `main` method.
///
/// ```dart
/// GoogleFontsLite.config.allowRuntimeFetching = false;
/// ```
static final GoogleFontsConfig config = sharedGoogleFontsConfig;

/// Returns a [Future] which resolves when requested fonts have finished
/// loading and are ready to be rendered on screen.
///
/// Usage:
/// ```dart
/// GoogleFontsLite.getFont('Lato');
/// GoogleFontsLite.getTextTheme('Pacifico');
/// await GoogleFontsLite.pendingFonts(); // <-- waits until Lato and Pacifico files have loaded.
/// ```
///
/// To keep things tidy, one can also pass in requested fonts as a list
/// to [pendingFonts].
///
/// ```dart
/// await GoogleFontsLite.pendingFonts(<dynamic>[
/// GoogleFontsLite.getFont('Lato'),
/// GoogleFontsLite.getTextTheme('Pacifico'),
/// ]);
/// ```
///
/// To avoid visual font swaps that occur when a font is loading,
/// consider using [FutureBuilder]. Note: This future cannot be created in
/// [build], as described in [FutureBuilder]'s documentation.
///
/// ```dart
/// late Future<List<void>> googleFontsPending;
///
/// @override
/// void initState() {
/// super.initState();
/// googleFontsPending = GoogleFontsLite.pendingFonts(<dynamic>[
/// GoogleFontsLite.getFont('Lato'),
/// ]);
/// }
///
/// @override
/// Widget build(BuildContext context) {
/// return FutureBuilder(
/// future: googleFontsPending,
/// builder: (context, snapshot) {
/// if (snapshot.connectionState != ConnectionState.done) {
/// return const SizedBox();
/// }
/// return Text('Lato text', style: GoogleFontsLite.getFont('Lato'));
/// },
/// );
/// }
/// ```
static Future<List<void>> pendingFonts([List<dynamic>? _]) => Future.wait(pendingFontFutures);

/// Map of all available Google Fonts families to their variant file descriptors.
static final Map<String, Map<GoogleFontsVariant, GoogleFontsFile>> fontsMap = {
'ABeeZee': {
Expand Down Expand Up @@ -57090,4 +57152,37 @@ abstract final class GoogleFontsLite {
decorationThickness: decorationThickness,
);
}

/// Retrieve a text theme by its font family name.
///
/// Applies the given font family from Google Fonts to the given [textTheme]
/// and returns the resulting [textTheme].
///
/// Note: [fontFamily] is case-sensitive.
///
/// Parameter [fontFamily] must not be `null`. Throws an [ArgumentError] if no
/// font by name [fontFamily] exists.
static TextTheme getTextTheme(String fontFamily, [TextTheme? textTheme]) {
if (!fontsMap.containsKey(fontFamily)) {
throw ArgumentError("No font family by name '$fontFamily' was found.");
}
textTheme ??= ThemeData.light().textTheme;
return TextTheme(
displayLarge: getFont(fontFamily, textStyle: textTheme.displayLarge),
displayMedium: getFont(fontFamily, textStyle: textTheme.displayMedium),
displaySmall: getFont(fontFamily, textStyle: textTheme.displaySmall),
headlineLarge: getFont(fontFamily, textStyle: textTheme.headlineLarge),
headlineMedium: getFont(fontFamily, textStyle: textTheme.headlineMedium),
headlineSmall: getFont(fontFamily, textStyle: textTheme.headlineSmall),
titleLarge: getFont(fontFamily, textStyle: textTheme.titleLarge),
titleMedium: getFont(fontFamily, textStyle: textTheme.titleMedium),
titleSmall: getFont(fontFamily, textStyle: textTheme.titleSmall),
bodyLarge: getFont(fontFamily, textStyle: textTheme.bodyLarge),
bodyMedium: getFont(fontFamily, textStyle: textTheme.bodyMedium),
bodySmall: getFont(fontFamily, textStyle: textTheme.bodySmall),
labelLarge: getFont(fontFamily, textStyle: textTheme.labelLarge),
labelMedium: getFont(fontFamily, textStyle: textTheme.labelMedium),
labelSmall: getFont(fontFamily, textStyle: textTheme.labelSmall),
);
}
}
1 change: 1 addition & 0 deletions packages/google_fonts/pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ dependencies:
flutter:
sdk: flutter
http: ^1.0.0
meta: ^1.10.0
path_provider: ^2.0.0

dev_dependencies:
Expand Down
Loading
Loading