Tech Racho エンジニアの「?」を「!」に。
  • Ruby / Rails関連

Rails: webpack(er)に乗り換える25の理由(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

webpack/Webpackerで使える有用なツールも本記事で多数紹介されています。
画像は元記事からの引用です。

Rails: webpack(er)に乗り換える25の理由(翻訳)

最近こんなことをよく聞かれます。「webpackとかWebpackerで頑張る価値ってあるの?」

よい質問だと思います。そして私の短い回答は「イエス」です。

近年JavaScriptコミュニティにおける認知度が急上昇していることで、フロントエンド開発用のツール、開発エクスペリエンス、最適化に巨大なイノベーションが続いています。

Railsはかつて最前線に躍り出ていました。登場した当時のRailsアセットパイプラインは大きな進歩でしたが、今やその方面の最前線ではありません。JavaScriptやCSSの依存関係の管理をアウトソースして、アセットをバンドルする手法は、当時としては経済的にスマートな方法でした。

本記事では、アセットパイプラインからWebpackerへの乗り換えが賢明な判断であると私が考える理由について詳しく述べたいと思います。ただしそのためには、いくつかの前提条件があります。言い換えれば、Webpackerに乗り換えずに、Railsアセットパイプラインを使い続けるかもしれない理由について最初に考えてみたいと思います。

WeboackerをRailsで使うことについて詳しくはニュースレターの購読をお願いします。

乗り換えない理由があるとすれば

あなたがRails開発者で、現在のRailsアプリでアセットパイプラインが使われているのであれば、webpackおよびWebpackerへの乗り換えがうまくいかない可能性もあります。以下でいくつか理由をご紹介します。

1. アプリケーションが乗り換えに向いてない

アプリケーションでJavaScriptがあまり使われていないのであれば、おそらく乗り換える価値はないでしょう。JavaScriptに充てている時間は、総開発時間の5〜10%を下回っていますか?その場合、そのアプリはwebpackのような実質的なツールを必要としていないかもしれません。

2. 時間がない

まず述べておきたいのは、webpackを初めて導入する場合、辛抱が求められるのは確かだということです。Sprocketsでやるのとは勝手が違いますし、新しいパラダイムを習得する時間に投資する必要も生じるでしょう。webpackやnpmの依存関係はハイペースで更新されるので、常にアップグレードを繰り返す必要があります。さらに、JavaScriptの「モジュール」のしくみについても理解する必要があるでしょう。ここでよいお知らせ: ここで学んだスキルは他でも応用が効きます。

3. 心の準備が整っていない

はい、webpackはたしかに複雑です。多くの開発者がwebpackの複雑さについて不満たらたらです。あなたがそうした開発者のひとりであれば、おそらくwebpackを導入するプロセスを楽しめない可能性もあります。ただしフラストレーションの大半は学ぶことで和らぎます。やるなら前向きな態度で取り組むことをお忘れなく。


いろいろ申し上げましたが、Webpackerに割けるささやかな時間と必要性、そして心構えがあるのであれば、きっとWebpackerへのアップグレードは成功するでしょう。Webpackerで得られるメリットのリストを以下でご紹介します。

1. WebpackerはRailsの未来の姿

Webpackerは、新しいRailsアプリでデフォルトのJavaScriptコンパイラになっています。Rails 6アプリにはCSSや画像を管理するためのSprocketsの引き続き含まれますが、JavaScriptの依存関係はWebpackerによってバンドルする前提です。Railsのデフォルト設定は、BasecampがWebアプリケーションを構築するときの設定に沿っています。「多数派に合わせる」ことでRailsの先端技術に肉薄し、より高度なツールで開発したいと考える開発者を惹きつけて採用につながれば、チームにとってメリットとなる可能性もあります。

2. Sprocketsと共存できる

Sprocketsの開発速度は近年落ちているようですが、すぐに消えることはないでしょう。Sprockets 4はRichard Schneemanの献身的な努力のおかげで最近リリースされました。デフォルトのRailsセットアップでは、Webpacker(JavaScriptのコンパイル用)とSprockets(CSSや画像用)の両方を使うことが奨励されています。

同じアプリケーションで2つのコンパイラを同時に利用できることで、チームが乗り換えるときに実際に役立ちます。段階的な移行への道が残されるので、移行リスクを軽減するうえで望ましいといえるでしょう。

3. よりよいJavaScriptの書き方が変わる

RailsがWebpackerを介してwebpackをサポートする前、私がGitHubで直接目にしたりチュートリアルやプレゼンで目にしたほとんどのRailsアプリは、以下のいずれかに分類できました。

  1. jQueryスパゲッティ
  2. 特注のモジュールを実装
  3. 1と2の組み合わせ

このアプローチのどこがまずかったのでしょうか?

  1. JavaScriptコードが何かのはずみでグローバルスコープにお漏らしする
  2. コードの共有が難しい
  3. コードをrequireする順序にがっつり依存する
  4. 暗黙の依存関係グラフの理解が極めて難しい
  5. コードを非同期に読み込むのが極めて難しい

JavaScriptソースコードをモジュールシステム内で書けば、ファイル単位のモジュールスコープを利用できるようになります。すなわち、コードがうっかりグローバルスコープにお漏らしすることもなくなり、特注のモジュールも不要になります。

4. ESモジュールのパワーの恩恵を受けられる

ESモジュール(ECMAScriptモジュール)がJavaScriptの未来であることを疑う人はほぼいないでしょう。ESモジュールは、最終的に新しいECMAScript標準として、ブラウザでもNode.jsなどのサーバーサイドランタイムでも利用できるようになります。同期importと非同期importを両方ともサポートしているので、CommonJSAMD(Asynchronous Module Definition)といった従来のモジュール仕様は最終的にことごとく消えてなくなるでしょう。

ひとつ強調しておきたいのは、ESモジュールがライブバインディングを採用している点です。つまり、exportしたモジュールで何らかの値を変更すると、モジュールをimportするときにその値が読み込まれます。この機能は、アプリケーションロジックで有用となる可能性があるのみならず、ESモジュールで循環依存をサポートできるようになります。

ESモジュールについて詳しくは、こちらの図解入り記事をどうぞ。

5. $JAVASCRIPT_FRAMEWORKは必須ではない

一般に広く信じられているのとは逆に、ReactやVueやAngularやSvelteといった人気のフレームワークを使わなくても、Webpackerが提供する機能を利用できます。Webpackerは、Vanilla JSはもちろん、jQueryベースのアプリでも問題なく利用できます。

私は、いわゆるSPA(Single Page Application)で余計な苦労を背負い込む価値があるとは思っていません。SPAはCRUD(Railsの核心)ベースのアプリの大半にとって複雑すぎます。2020年においても「JavaScript-sprinkled Rails Applications」を採用する意味は大いにありますし、webpackは利点と捉えるべきです。

6. 別のファイル構造を利用できる

webpackによって、JavaScriptのソースファイルの構造をうまくカスタマイズする方法への道が開かれました。おそらく最も人気の高いJavaScriptフレームワークであるReact.jsによってJSXというものが導入されました。JSXではHTML的なJavaScriptを書くことでコンポーネントのHTMLコードとJavaScriptコードを共存させられるので、開発者が昔ながらのテーゼである「関心の分離」にチャレンジできます。

Vue.jsはSingle File Componentsをサポートしていることでも有名です。これはHTMLとCSSとJavaScriptを、1つのファイル内の異なるセクションに分離しつつ共存させることができます(例↓)。

<template>
  <div>Hello, {{ name }}!</div>
</template>

<script>
export default {
  data() {
    return {
      name: "World"
    }
  }
}
</script>

<style scoped>
div {
  background-color: aliceblue;
  padding: 1em;
  font-size: 2em;
  text-align: center;
}
</style>

私の知る限り、このアプローチをRailsアセットパイプラインで実現するのは容易ではありません。

7. 依存関係の管理方法が改善される

Railsの「アセット系gem」は、いつも私にとって特につらくてたまらないものでした。アセット系gemは、ほとんどの場合npm(Node Package Manager)の依存関係に置き換え可能です。

npmは、オープンソースJavaScriptパッケージの主要な分散リポジトリになっています。当初の設計ではNode.jsランタイムでの利用が想定されていましたが、やがてブラウザベースのパッケージのデフォルトにもなりました。これはつまり、Node.jsで実行されるライブラリ(webpackなど)と、ブラウザ向けのライブラリ(ReactやVieなど)のどちらもnpmで配布できるということです。npmを利用すれば、主にRailsのアセットパイプライン向けのJavaScriptやアセットの共有で非常に大きなメリットが得られます。後者のアプローチにはひとつ問題点があり、それはRubyのバージョンをパッケージ化されたアセットのバージョンに合わせてメンテしないといけなくなる点です。この手法は常に面倒がつきまとうと感じられます。

ここでひとつ言及しておきたいことがあります。npmでアセットを管理しつつ、node_modulesをSprocketsの読み込みパスに追加することでRailsアセットパイプラインで利用することは引き続き可能だということです。繰り返しますが、この方法は面倒であり、対象によってはビルド時間に悪影響が生じる可能性もあります。

8. jQueryプラグインをやめられる(やめたければ)

モジュールを採用する前の時代におけるjQueryプラグインのメリットのひとつは、グローバルスコープを汚染せずに機能を追加できることです。正しいモジュールシステムを使えば、webpackに慣れ親しむに連れてjQueryインスタンスに機能をアタッチしてアプリケーション全体で参照する必要はなくなってきます。

タッチレスポンシブなカルーセルプラグインのFlickityで考えてみましょう。Railsアセットパイプラインでは以下のように使うでしょう。

//= require flickity

$(function () {
  $('.main-carousel').flickity({
    contain: true
  });
})

FlickityはjQueryなしでの利用も想定されています。つまりFlickityモジュールをwebpack環境で実装することもできるということです。

import Flickity from 'flickity'

document.addEventListener('DOMContentLoaded', () => {
  const elem = document.querySelector('.main-carousel');
  const flkty = new Flickity(elem, {
    contain: true
  });
})

jQueryはこのやりとりから丸ごと除外できます。

9. ES2015以降の構文をES5+Babelにコンパイルできる

CoffeeScriptが導入された当初は、クリーンかつRuby的な構文のおかげで人気を博しました。最近のECMAScriptには、CoffeeScriptのアイデアも多数導入されています。かつて私はCoffeeScriptで書くのが好きでしたが、ES構文でJavaScriptを書くのはさらに好きです。

ES2015以降の数々の大きな進歩を、以下の簡単なリストに抜粋してまとめました。

10. 実験的なES機能をオプトイン/オプトアウトできる

Babelインテグレーションを用いることで、次世代の実験的なECMAScript構文を利用できます。

11. 特定バージョンのブラウザを対象にできる

アプリケーションでサポートするブラウザの種類をコード化できたらどんなに素晴らしいか想像してみましょう。Webpackerならできます。

Babelインテグレーションにbrowserlistパッケージを併用することで、トランスパイルされたコードが対象とするブラウザをプロジェクトでコード化できるようになります。バージョンのリストはクエリの形で設定でき、特定バージョンのブラウザを指定することも、「最新の2バージョン」を指定して手動アップデートを回避することもできます。browserlistでは、Can I Useが提供するデータを用いて、より新しいフロントエンドAPIをサポートするブラウザを決定します。

これで、以下のように未来のJS構文で書けるようになります。

const array = [1, 2, 3];
const [first, second] = array;

BabelでEdge 16向けにコンパイルすると以下のようになります。

const array = [1, 2, 3];
const first = array[0],
      second = array[1];

12. 新しいブラウザAPIをポリフィル化できる

上の11番では、自動ポリフィルで指定する新しいJavaScript APIをより簡単に指定するために、Webpackerで@babel/preset-envを用いています。

これは、依存関係グラフのトップに以下のコードを挿入することで実現されます。

import 'core-js/stable'

chrome 71がターゲットの場合、上は以下に置き換わります。

import "core-js/modules/es.array.unscopables.flat"
import "core-js/modules/es.array.unscopables.flat-map"
import "core-js/modules/es.object.from-entries"
import "core-js/modules/web.immediate"

これで、今までブラウザサポート用にテストに追加されていた条件を削除できるようになります。

13. TypeScriptが使える

近年のTypeScript人気の高まりは著しいものがあります。

TypeScriptによって静的型付けがフロントエンド開発に導入されたことで、エラーをより効率的にキャッチできるようになり、VSCodeなどのJavaScript IDEをサポートするインテグレーションによって生産性が高まりました。TypeScriptは反復的に導入することも可能です。TypeScriptはJavaScriptのスーパーセットなので、JavaScriptとして正しいプログラムは、TypeScriptとしても正しいプログラムになります。Webpackerは、RailsプロジェクトにTypeScriptをより簡単に追加できるインストーラを提供しています。

14. 新しいパワフルなツールを利用できる

webpackによるコンパイルやビルドのプロセスで提供される多数のフックによって、振る舞いをほぼあらゆる段階で変更できます。システムのニーズに応じてwebpackを拡張する方法を以下のリストに簡単にまとめました。

  • Railsアセットパイプライン経由の単体テストでは常に火の輪くぐりのように冷や冷やさせられていましたが、MochaJestといったJavaScriptの単体テストツールを自由に選べるようになりました。
  • eslint統合によるコードのスタイルや構文の標準化・自動修正
  • バンドルのサイズや内容を分析するプラグイン(WebpackBundlerAnalyzerなど)を追加できる
  • Rails i18n yamlファイルをパースしてWebpackerのJavaScriptモジュールにJSONとして提供するローダーを追加できる
  • バンドルの「フィンガープリントなし」クローンを生成するプラグインを追加できる(non-stupid-digest-assets

webpackと馴染みのよいアドオンであるStorybookは私のお気に入りです。これはRailsサーバーと独立してコンポーネントをビルドできる新しいツールであり、開発環境を実データで汚すことなく、さまざまなステートを持つUIを表現する優れた方法のひとつです。

15. ソースコードをプログラムで変更できる

webpackは、モジュールからの出力を簡単に変更できるいくつかの設定オプションを提供しています。たとえば、jQueryのimportをソースファイルのあらゆるモジュールに「提供する」には、ProvidePluginを追加します。

これは、レガシーRailsアプリをwebpackにアップグレードするときに重要になってきます。たとえば、古いjQueryプラグインの多くはjQueryがグローバルスコープで利用できることを前提としています。ProvidePluginを以下のように設定することで、必要に応じてレガシーモジュールをrequire('jquery')ステートメントで「shimming(詰め物)」するようwebpackに指示します。

// config/webpack/environment.js

const webpack = require('webpack');

const {environment} = require('@rails/webpacker');

environment.plugins.append(
  'jquery', // arbitrary name
   new webpack.ProvidePlugin({
    $: 'jquery',
    jQuery: 'jquery',
    'window.jQuery': 'jquery'
   }),
);

module.exports = environment;

16. 引き続きrequire_treeして一部を扱える

Sprocketsには、アセットバンドルにファイルをインクルードするのに便利な方法がいくつかあります(require_treeなど)。同様に、webpackにも複数のファイルを1つのファイルにインクルードするためのrequire.contextがあります。こちらの方が退屈ではありますが、強力さにおいても上回ります。require.contextはファイルをフィルタするオプションを提供しており、たとえば.svgファイルだけをimportしたりできます。戻り値を操作することも可能です。

構文:

require.context(directory, useSubdirectories = true, regExp = /^\.\/.*$/, mode = 'sync');

例: カレントディレクトリとその下のディレクトリにあるテストファイルをすべてrequireする場合

require.context('.', true, /\.test\.js$/);

例: カレントディレクトリにあるデフォルトのexportをすべてimportし、名前付きモジュールとして再度exportする場合

const requireModule = require.context('.', false, /.js$/)

context.keys().forEach(filename => {
  const moduleConfig = requireModule(filename)

  // filenameからモジュール名をパスカルケースで取得する
  const moduleName = upperFirst(
    camelCase(
      filename.replace(/\.\//, '').replace(/\.\w+$/, '')
    )
  )

  export {[moduleName]: moduleConfig.default}
})

17. コードを自動で静的分割できる

Sprocketsでは、あらゆるベンダーコードを個別のバンドルに移動することで、バンドルサイズを削減してキャッシュが効きやすくする方法がよく使われます。

<!-- app/views/layouts.application.html.erb -->
<%= javascript_include_tag "vendor" %>
<%= javascript_include_tag "application" %>

この方法では、バンドルを頑張って手動で分割し、読み込み順序で問題を起こしたり重要な依存関係を取りこぼしたりしないよう、細心の注意を払わなければならないのが悩みのタネです。

webpackではソースコードを静的解析して依存関係グラフをビルドします。ベンダーコードやアプリケーションコードを自動的に個別のバンドルに分割生成する設定も使えます。つまり、webpackは1つのpackからベンダー用バンドルとアプリケーションバンドルを、webpack実行時に代わりに生成してくれるということです。この振る舞いを有効にするには、Webpackerヘルパーと設定を以下のように用います。

// config/webpack/environment.js

const { environment } = require('@rails/webpacker')

environment.splitChunks()

module.exports = environment
<!-- app/views/layouts/application.html.erb -->

<%= javascript_packs_with_chunks_tag "application" %>
<!--
<script src="/packs/vendor-16838bab065ae1e314.chunk.js"></script>
<script src="/packs/application~runtime-16838bab065ae1e314.chunk.js"></script>
<script src="/packs/application-1016838bab065ae1e314.chunk.js"></script>
!>

もう手動でコードを分割する必要はありません。

18. コードを自動で動的分割できる

自分のJavaScriptコードを複数のファイルに分割するオプションとしては「動的import」がさらに優れています。ただしこのアプローチでは、設定を一切変更しないことが求められます。webpackの作者がwebpackを最初に作った動機は、まさにこのためでした。

webpackがアプリケーションで以下のような動的なimport関数を検出すると、そのimport向けの独立したバンドルを作成し、コードがブラウザで実行されるときに非同期で読み込みます。

import('pdfjs/webpack').then(({default: pdfjs}) => { // async import!
  pdfjs.getDocument('https://example.com/some.pdf')  // ...
})

この手法を用いることで、初期ダウンロードサイズを削減して不要なJavaScriptコードの読み込みを回避でき、TTI(time to interactive)メトリクスの改善にもつながります。

19. 最新のCSSプロセッサを利用できる

Railsとの付き合いが長い方がこれまで採用していたSASSやSCSSなど、皆さんが好きそうなCSSプロセッサにもチャンスが与えられます。もちろん大丈夫!WebpackerではSASS/SCSSをデフォルトでサポートします。なおWebpackerにはPostCSSという新しいツールも統合されています。

PostCSSは比較的新顔のツールで、JavaScriptでCSSを変換します。PostCSSはプラグインで設定を拡張可能なので、さまざまな機能を利用できます。webpackでは、flexboxの一部のバグ修正を適用したり、(@babel/preset-envがJavaScriptで行うのと同様に)preset-envプラグインを用いて古いブラウザで新しいCSS機能をポリフィル化したりするのに、PostCSSを用いています。

PurgeCSSは私の好きなPostCSSプラグインのひとつで、自分のCSSをHTMLマークアップやテンプレートと比較することで、不要なCSSを削除します。こうしたツールは、本番コードでは使いそうにないユーティリティクラスを山ほど持ち込むTailwindCSSのようなフレームワークを採用する場合にとても重宝します。

20. 開発時にアセットのコンパイルをRailsサーバーから切り離せる

development環境のSprocketsは、Railsサーバーで扱う静的アセットのコンパイルや再コンパイルを自動で行いますが、これによってRubyプロセスの仕事が倍増してボトルネックになることがあります。webpack-dev-serverなら、アセットのコンパイルは独立したプロセスに移動するので、Railsサーバーがリクエストのレスポンスを返すのとは独立にアセットがコンパイルされます。

webpack-dev-serverはシンプルなNode.js Webサーバーであり、ソースコードディレクトリ内のファイル変更を監視して変更が生じたらwebpackをトリガし、コンパイル済みアセットをメモリ上で提供します。アセットはwebsocketリスナー経由で自動的にブラウザに挿入され、必要であればオートコンパイルの完了時に開発用ブラウザウィンドウを自動で再読み込みします。

21. 開発中にページを再読み込みせずにコードを更新できる

ブラウザ内にあるJavaScriptモジュールの実装を、ページをリロードせずに置き換えられるとしたらどうでしょう。これはHot Module Replacement(HMR)と呼ばれる機能です。コードが変更された場合にだけほぼ瞬時にページを更新できるだけでなく、アプリケーションやDOMのステートも維持されます。つまり、望みのUIステートを得るのに余分なクリックや入力を行う必要がないということです。このツールには利用上の注意点がいくつかありますが、一般に開発をスピードアップできる強力な方法のひとつです。

22. source mapオプションを利用できる

自分の書いたJavaScriptやCSSのソースコードは、開発環境や本番環境でコンパイルされるとフォーマットが変わります。source mapはこのギャップを埋めてくれます。source mapの読み込みやレンダリングは、ほとんどのメジャーなブラウザにあるdev toolsでサポートされており、ブラウザに読み込まれているコードと、ソースファイルにあるコードを橋渡しできます。source mapは、ぜひ道具箱に常備しておきたい素晴らしいツールです。

Sprocketsは、最近Railsアセットパイプラインにsource mapを導入しました。webpackではsouce mapは最初からサポートされており、しかも高度にカスタマイズ可能です。webpackでは20種類以上ものsource mapがサポートされているので、ほぼあらゆるユースケースの攻略に使えます。source mapの種類がこれほど多い理由のひとつは、自分のバンドルとは別に1個のファイルとしてsource mapを生成しなければならないためです。そのため、ビルドによるパフォーマンス上のコストが発生します。時間を節約するか、それとも正確さを優先するかはトレードオフになります。

ここでのポイントは、webpackを使えば以下のように多数の選択肢が得られることです。

23. 「パフォーマンスバジェット」を実装できる

最適化のルール第一条は「まず測定せよ」です。私がフロントエンドのパフォーマンスを最適化することになったら、いの一番にAddy Osmaniでアドバイスを探します。

フロントエンドのパフォーマンス測定における重要な戦略のひとつは「パフォーマンスを予算化する」ことであり、TTI(time-to-interactive)にも強く関連します。このように捉えることで、ユーザーによるアプリケーション操作のエクスペリエンスにおいて、TTIの値を求められるようになるでしょう。TTI値は、ユーザーのブラウザにダウンロードして実行させるJavaScriptコードの量と強く相関します。初回ダウンロードのペイロードサイズを抑えることで、TTI値を改善できるようになるでしょう。

それがwebpackと何の関係があるのでしょうか?webpackは上述したように自分のバンドルを簡単に分割できるだけでなく、パフォーマンスバジェットのサポートも組み込まれています。webpackをカスタマイズすることで、設定済みのmaxEntryPointSize値をバンドルが超えたときに警告を表示することもエラーを発生することもできます。

24. バンドルの内部を詳しく調べられる

webpackのデバッグツールの中で私のお気に入りのひとつはwebpack-bundler-analyzerです。このツールを自分のビルドに追加すれば、以下のようなインタラクティブなツリーマップにバンドル内部の相対サイズや中身がビジュアル表示されます。たとえばlodashを追加するとバンドルサイズはどれだけ増えるかを知りたければ、このツールを使いましょう。依存関係やwebpack出力にバグの疑いがあれば、このツールが原因特定の助けになるでしょう。

25. 「tree shaking」が使える

JavaScriptバンドル方面の流行りである「tree shaking」を忘れては手落ちになるところです。これは要するに、特定の条件が満たされた場合にwebpackが不要なコードをビルドから削除してくれるというものです。つまり削除の対象は基本的にESモジュールということになります。たとえばESモジュールを扱うようBabelが設定されていれば、副作用なしでそのモジュールをimportできます。

lodashはtree shakingのよいユースケースです。lodashが完全に読み込まれると、アセットバンドルに追加されるライブラリは75KBになります。

import _ from 'lodash' // または

import {map, uniq, tail} from 'lodash'

以下のように書くことで、webpackがファイルサイズを抑えてくれます。

import map from 'lodash/map'
import uniq from 'lodash/uniq'
import tail from 'lodash/tail'

まとめ

webpack(er)に乗り換える25の理由は以上でおしまいです。本記事が、皆さんのRailsアプリでwebpackを採用するうえで、webpackの可能性やユースケースのよい紹介となることを願っています。繰り返しますが、webpackの導入は、webpackの仕組みを理解するという「参入障壁」を克服しながら多数の細かなJavaScript依存関係を管理する手間とのトレードオフです。

私自身は、このトレードオフに価値があったと感じています。

Twitterでの議論もお待ちしています。

おたより発掘

関連記事

Rails 6+Webpacker開発環境をJS強者ががっつりセットアップしてみた(翻訳)


CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。