Panache という Lorem Ipsum Dummy Text Generator の Flutter DevTools Extension を作ったので、それまでのいきさつを書く。
panache | Flutter package
https://pub.dev
去年の FlutterKaigi 2024 で Flutter DevTools Extension を作るセッションを参加した。まず作れるんだと感心したので、何か自分で作ってみたいと感じたのが大きかった。セッションでは、Riverpod で保持されているローディング状態をトグルするものだったので、セッションを聞いた当初は自分もアプリと連携するものを作りたいと考えた。しかし、ライブラリとして公開するため、アプリの特性や使用ライブラリに依存しないのと、最初は難易度を下げたいと考えたので、連携を必要としないものを作ることを目標した。
初めて OSS ライブラリを公開したのもあり、今回は DevTools Extension を一般公開するまでのことをまとめた。
Flutter DevTools Extension を開発するにあたって、Extension には Standalone Extension と Companion Exntension の 2 種類がある。Standalone Extension は Extension だけ配布されたものとなり、反対に Companion Extension は Extension が既存のパッケージの一部として配布されるものになる。具体的には、Companion Extension ではログを取る処理とそれを Extension に表示する機能を両方提供している。その処理をアプリ側で呼び出し、ログを Extension 側で見るといったものとなる。
今回は Extension のみを提供するなので、Standalone Extension を開発するものとする。
どちらの Extension を作るかを選んだあとは、ディレクトリ構成を決めていく。
まずは devtools_extensions の README.md の Step 1: Setup your package hierarchy と Step 2: Configure your extension を熟読することをおすすめする。
lib
ディレクトリに Devtools Extensions を構成するコードを置くことは普段 Flutter で開発していれば馴染みがあるが、今回大事なのは extension
ディレクトリであり、ここに配布用の Extension 関連のコードやアセット、設定ファイルなどをまとめる。配布用にビルドしたアセットたちを extension/devtools
ディレクトリに置き、設定ファイルは config.yaml
として保存する。
my_new_tool
extension/
devtools/
build/
... # pre-compiled output of the Flutter web app under lib/
config.yaml
lib/ # source code for your extension Flutter web app
src/
...
name: some_pkg
issueTracker: <link_to_your_issue_tracker.com>
version: 0.0.1
materialIconCodePoint: '0xe0b1'
requiresConnection: true # optional field - defaults to true
panache のディレクトリ構成と config.yaml
は最終的にこうした。
panache
extension/
devtools/
build/
... # lib コードをビルドし、
config.yaml
lib/ # ここに devtools extension を構成するコードを置く。
src/
...
name: panache
issueTracker: https://github.com/offich/panache/issues
version: 0.0.2
materialIconCodePoint: '0xe651'
requiresConnection: false
DevTools Extension は Flutter Web で作られるので、下のコマンドを実行して、プロジェクト作成する。基本的には README.md の Step 3 に従う。
flutter create --template app --platforms web panache
flutter pub add devtools_extensions devtools_app_shared
DevToolsExtension
ウィジェットでラップすれば、最初のセットアップは完了。
import 'package:devtools_extensions/devtools_extensions.dart';
import 'package:flutter/material.dart';
import 'package:panache/panache.dart';
void main() {
runApp(DevToolsExtension(child: const Panache()));
}
最後は DevTools Extension を起動して、表示される。
flutter run -d chrome --dart-define=use_simulated_environment=true
概要を説明したあとは作るもの自体の説明をするが、タイトルにある通り、ダミーテキストを簡単に生成する Extension を作ることをゴールにした。
ちなみに完成したものはこちら ↓
どうやって決めたかというと、セッションの登壇者が web 開発で使われている Google Chrome Extension を参考にするとよいとアドバイスを残していたのを思い出した。なので、早速 Google Chrome Extension のおすすめ一覧やランキングを眺めていると、Lorem Ipsum のダミーテキスト生成の Extension がちらほらあるのに気づいた。はじめて開発するのも相まって、アプリへの依存度もないことから難易度も上がらないだろうと予測を立て、開発することに決めた。
左のサイドバーで、段落、文章、単語数を自由に決めて、ランダムに生成されたテキストが右側に表示されるというものになる。
左のサイドバーでは、それぞれの数は最初 input で入力してもらうことを想定していたが、数字ではなく文字列が変に入力されていないか、もしく入力された数が最大最小の範囲に留まっているかを確認するバリデーションを実装するのは少し骨が折れるので、スライダーを採用した。スライダーについては、Flutter から提供されただ範囲の中でも、その中であらかじめ計算された値にしか更新できず、不便に感じたので、今回は妥協して下のスライダーを使うことにした。
syncfusion_flutter_sliders | Flutter package
https://pub.dev
右のスペースは FadeTransition
と SliderTransition
を利用して、テキストが生成されるたびに、下からフェードインされるようにした。複数のアニメーションを組み合わせるときは、このようにラップする。
SlideTransition(
position: offsetAnimation.value!,
child: FadeTransition(
opacity: opacityAnimation.value!,
child: SelectableText(text, style: PanacheTextStyle.medium),
),
);
知見となったことしては、テキストが生成されたら同じアニメーションを開始するにはどうしたらいいかを調べたところ、AnimationController#forward
の from
に 0.0
に渡せばいいとのこと。最初は reverse
してとも考えたので、勉強になった。
useEffect(() {
animationController.forward(from: 0.0);
return;
}, [text]);
少し余談になるが、パッケージの名前は panache という名前にした。命名の理由は多くあるが、なにかお酒やカクテルの名前にしたかったのが一番になる。
細かい理由に分解していくと、1 つは「Lorem Ipsum Dummy Text Generator」というシンプルな名前を使用するのを避けたかった。長いし、この記事のように紹介するときに、他のダミーテキストパッケージに紛れて pub dev のサイト内の検索でヒットしないことを避けたかった。
あとは過去の現場で、プロジェクトの名前を使用技術や所属している部署やチームなど関わりがあるものを由来にしないという命名規則にインスパイアされたのもある。名前を流動的に変化があるものにし、プロジェクトの名前が他サービスから参照されていると、名前の変更時に多くの追従作業が発生してしまう。そのため、具体的には何も関係性がない、果物の名前を採用していた。
この命名規則を自分のプロジェクトへ当てはめたときに、最初から変化の機会が多くあるものを由来する予定はなかったが、好きなカクテルから決めるのは割と好感を持てた。なので、自分が開発するライブラリたちにはすべてカクテルの名前を振ることにした。(強いていうなら、一番わかりやすい「Lorem Ipsum DevTools Extensions」という名前が候補にあったが、万が一 DevTools Extensions から別の名前になった場合を考慮して、やはりカクテルの名前を使用することに。)
panache(パナシェ) はフランス生まれのカクテルで、フランス語でまざりあったという意味がある。もともとはビールとレモネードを同量(1 対 1)で割ったカクテルのこと。ただし、現在ではビールとレモネードの組み合わせだけでなく、ビールと透明な炭酸飲料を混ぜ合わせたもの全般を幅広く「パナシェ」と呼ぶみたい。生成されるダミーテキストはローマ語のランダムな言葉たちなので、まさに混ざり合ったものが最終的なアウトプットになるという意味も含んでの panache
にした。
Extension が完成したあとは、一般公開するまでのことをまとめる。
まずは pub dev にパブリッシャーを登録する必要がある。公式には、個人の Google アカウントより、検証済みパブリッシャーとしてパッケージを公開することが推奨されている。ただ注意しないといけないのが、何か自分のドメインを用意していないとパブリッシャー登録できない。自分はたまたまこのブログを運用し、Google Search Console でドメイン登録しているので、幸いなことに条件を満たしていた。最後リリースする前の大事な作業になるので、注意が必要になる。
配布するものが完成したなら、最後に pub dev への公開を自動化する。自動化の手段は GitHub Actions
からか Google Cloud Service account
からかを選択できる。
今回は GitHub Actions を選択し、それに必要な設定を Admin ページで入力していく。設定していくものは、Publishing packages using GitHub Actions を参考にすると良い。
設定が終わったら、workflow を用意するが、DevTool Extension をリリーするときはドキュメントに書いてあるものより少し手を加えないといけないので、注意が必要になる。ドキュメントでは、workflow が dart-lang/setup-dart@v1
の一行のみだが、それはシンプルな dart のスクリプトだけで構成されたパッケージの場合のものとなる。
しかし、DevTool Extension をアップロードするので、Flutter 自体をインストールしないといけない。その workflow だけで使用しているパッケージたちをインストールするのか、認証やアップロードしてくれるのかと悩んだ。調査すると、どうやら dart-lang/setup-dart@v1
の中に内包されているみたいだった。それだけだと Flutter 自体をインストールできないので、workflow の中で Flutter を使えるようにする Action も一緒に使うことで解決させる。
最終的な workflow の中身はこちら。
name: Publish
jobs:
publish:
steps:
# checkout
# ...
- uses: dart-lang/setup-dart@v1
with:
sdk: 3.6.0
- uses: kuhnroyal/flutter-fvm-config-action@v3
id: fvm-config-action
- uses: subosito/[email protected]
with:
channel: ${{ steps.fvm-config-action.outputs.FLUTTER_CHANNEL }}
flutter-version: ${{ steps.fvm-config-action.outputs.FLUTTER_VERSION }}
- name: install dependencies
run: flutter pub get
- name: Validate
run: dart run devtools_extensions validate --package=.
- name: Build and Copy
run: dart run devtools_extensions build_and_copy --source=. --dest=./extension/devtools
- name: Publish
run: dart pub publish --force
いろいろな pub パッケージのページを見てきたが、その score タブは中身を見たことをなかった。今回初めてみたが、この得点が満点に近いものだと安全性や信頼を得られ、多くの開発者からダウンロードしてもらえると考えると、最初リリースするときから満点にしたい。
panache の例だと、Follow Dart files conventions
と Provide Documentation
が不十分なので、今後対応する。
リリースすることでリソースがいっぱいでありテストを書けなかったので、知見が溜まり次第、ここのセクションに書いていく。Golden Image Test を移動して、リグレッションテストも書いていきたい。
現在知見を探しているのだが、DevTools Extension がボタンなどの UI パーツでタブキーでの移動ができないのに困っている。DevTools Extension は Flutter web app で開発するものなので、せっかくならアクセシビリティを考慮しようと考えた。ボタンやスライダーの生成する文章や段落数をキーボードだけで操作できるようにした。(このあたりは別の記事で知見をまとめたい)
しかし、実際の Flutter プロジェクトで確認したところ、開発時には初期表示後でタブキーのキーイベントにフックして移動していたフォーカスが全く反応しなくなっていた。ブラウザでボタンの要素に向けてフォーカスさせたいが、それも難しく、これから詳しく調べていきたい。
初めて Flutter DevTools Extension を開発し、なんだかんだ初めての OSS ライブラリを公開できたので、個人的には満足度が高いものとなった。pub dev へ公開された 3 日後には 150 越えダウンロード数があり、個人的には嬉しさを感じた。数相場がどれぐらいかなのかはわからないが、どれぐらいダウンロードされているかを見られるのはテンションがあがった。よかったら、ダウンロードして、Like もクリックしてもらえると非常に幸いだ。なるべく難易度を下げることでリリースするまでのゴールを達成したので、次は何かアプリ側と連携する DevTools Extension を開発してみたい。
GitHub - lllttt06/flutter_devtools_extension_sample
https://github.com
[Flutter] Devtools Extensions で独自の Devtool を開発する
https://zenn.dev