route(root, defaultRoute, routes)
- コア
- オプショナル
- ツール
説明
アプリケーション内の「ページ」間のナビゲーションを行います。
var Home = {
view: function() {
return "ようこそ"
}
}
m.route(document.body, "/home", {
"/home": Home, // `http://localhost/#!/home` の定義
})
アプリケーションごとに1回だけm.route
呼び出しが行えます。
シグニチャ
m.route(root, defaultRoute, routes)
引数 | 型 | 必須 | 説明 |
---|---|---|---|
root |
Element |
Yes | サブツリーの親ノードとなるDOM要素 |
defaultRoute |
String |
Yes | 現在のURLが、定義されたどのラウトにもマッチしなかった時にリダイレクトされる先のラウト |
routes |
Object |
Yes | キーがラウトのURL、値がコンポーネントかラウトリゾルバーが格納されているオブジェクト |
返り値 | undefined を返す |
静的メンバー
m.route.set
マッチするラウト、もしくはマッチするラウトがなければデフォルトのラウトにリダイレクトします。
m.route.set(path, data, options)
引数 | 型 | 必須 | 説明 |
---|---|---|---|
path |
String |
Yes | 移行先のラウト。ただしプリフィックスは含まない。パスにはラウとのパラメータを含めることができます。 |
data |
Object |
No | ラウトのパラメータもしpath はラウとのパラメータスロットを持っている時は、このオブジェクトのプロパティがパス文字列のパラメータ部として利用されます。 |
options.replace |
Boolean |
No | 新しい履歴のエントリーを追加するか、今のエントリーを置き換えるか。デフォルトはfalseです。 |
options.state |
Object |
No | state オブジェクトは、内部で呼び出されるhistory.pushState / history.replaceState に渡されます。このstateオブジェクトはhistory.state プロパティを通じてアクセスできます。プロパティはラウトパラメータオブジェクトにマージされます。このオプションはpushState APIを使っているときにのみ利用できます。pushState APIが利用できないときは、ラウターはハッシュ変更モードにフォールバックしますがこの時は無視されます。 |
options.title |
String |
No | title 文字列は、内部で呼び出されるhistory.pushState / history.replaceState に渡されます。 |
返り値 | undefined を返す |
m.route.get
最後に解決されたラウトのパスをプリフィックスなしで返します。非同期で解決が遅延されている時は、ブラウザのロケーションバーに表示されているパスと異なることがあります。
path = m.route.get()
引数 | 型 | 必須 | 説明 |
---|---|---|---|
返り値 | String | 最後に解決されたラウトのパス |
m.route.prefix
ラウターのプリフィックスを定義します。ラウタープリフィックはラウターが使用する戦略を決定する文字列です。
m.route.prefix(prefix)
引数 | 型 | 必須 | 説明 |
---|---|---|---|
prefix |
String |
Yes | プリフィックスはMithrilが内部で使用するラウト戦略を制御します。 |
返り値 | undefined を返す |
m.route.link
この関数はおそらくm("a")
vnodeのoncreate
(とonupdate
)フック内で使用されます:
m("a[href=/]", {oncreate: m.route.link})`.
m.route.link
をoncreate
フックとして使用すると、ラウター用のリンクとして動作するようになります。href
はラウトに特化したナビゲーションリンクなります。現在のページから他のページへジャンプしてブラウザの内容がリセットされるのではなく、href
で指定されたラウトへの内部ジャンプになります。
href
属性が静的なものでなければ、onupdate
フックも設定しなければなりません。
m("a", {href: someVariable, oncreate: m.route.link, onupdate: m.route.link})`
m.route.link(vnode)
引数 | 型 | 必須 | 説明 |
---|---|---|---|
vnode |
Vnode |
Yes | このメソッドは<a> タグとvnodeのoncreate とonupdate フックを結びつけるときに使います。 |
返り値 | undefined を返す |
m.route.param
ラウトパラメータの取得ラウとパラメータはキー・バリューのペアです。ラウトパラメータはいくつかの場所から収集されます:
- ラウトへの挿入。
/users/:id
というラウトが設定され、/users/1
というラウトを解決すると、ラウとパラメータはid
というキーが作られ、その値には"1"
が設定されます。 - ラウターのクエリー文字列。パスが
/users?page=1
の時は、ラウトパラメータにはpage
というキーができ、"1"
が設定されます。 history.state
。history.stateが{foo: "bar"}
に設定されると、ラウとパラメータにはfoo
というキーができ、"bar"
が設定されます。
value = m.route.param(key)
引数 | 型 | 必須 | 説明 |
---|---|---|---|
key |
String |
No | ラウトパラメータ名(例えば、/users/:id というラウトであればid 、/users/1?page=3 というパスならpage 、あるいはhistory.state のキー) |
返り値 | String|Object |
指定されたキーの値を返します。もしキーが指定されなければ、すべての挿入されたキーを含むオブジェクトを返します。 |
ラウトリゾルバ
ラウとリゾルバはonmatch
メソッドとrender
メソッドの両方、あるいはどちらかを持つオブジェクトです。メソッドはどちらもオプションですが、どちらか一方は必要です。ラウトリゾルバはコンポーネントではありません。そのため、ライフサイクルメソッドも持ちません。一般的な使い方は、ラウトリゾルバはm.route
呼び出しと同じファイルに入れ、コンポーネントはそれぞれ別のファイルに入れる方法です。
routeResolver = {onmatch, render}
routeResolver.onmatch
onmatch
フックはレンダリングするコンポーネントを探すときに呼ばれます。これはラウターのパスが一回変更されるたびに呼ばれます。ただし、同じパスに対して再帰的に子要素が呼び出されて行われる再描画では呼びされません。これはコンポーネントの初期化前位にロジックを実行することができます。例えば認証ロジックはデータのプリロード、リダイレクト分析とかです。
このメソッドを使うと、どのコンポーネントをレンダリングすべきかを非同期に決めることができます。コードを分割して非同期のモジュールのロードを行うときに使えます。コンポーネントのレンダリングを非同期に行う時は、解決時にコンポーネントが格納されるPromiseを返します。
onmatch
の詳細は、応用的なコンポーネントの解決のセクションを参照してください。
routeResolver.onmatch(args, requestedPath)
引数 | 型 | 説明 |
---|---|---|
args |
Object |
ラウトパラメータ |
requestedPath |
String |
最後にラウト操作を行った時のラウターパスです。ラウターパラメータ値は入りますが、プリフィックスは含まれません。onmatch が呼ばれると、パスの解決は延期され、m.route.get() が返すパスも解決されて変更される前のままとなります。 |
返り値 | Component|Promise |
コンポーネントまたは、解決時にコンポーネントが格納されるPromiseを返します。 |
もしonmatch
がコンポーネント、あるいはコンポーネントを解決するPromiseを返すと、このコンポーネントはラウトリゾルバーの render
メソッドの最初の引数のvnode.tag
として渡されます。返さない時はvnode.tag
には"div"
が設定されます。同様に、onmatch
メソッドが省略されると、vnode.tag
が"div"
になります。
onmatch
がPromiseを返し、それがrジジェクとされたら、ラウターのラウトはdefaultRoute
に戻ります。この動作を回避するには、Promiseのチェーンを返す前に.catch
を呼び出して動作を変更してください。
routeResolver.render
render
はラウトがマッチしたときの再描画時に毎回呼ばれます。これはコンポーネントのview
メソッドに似ていますが、コンポーネント合成をシンプルにおこなうために存在しています。
vnode = routeResolve.render(vnode)
引数 | 型 | 説明 |
---|---|---|
vnode |
Object |
vnodeですが、このオブジェクトの属性は、ラウトパラメータを含んでいます。もしonmatchがコンポーネントも、コンポーネントを返すPromiseも返さなかった時は、tag フィールドは"div" となります。 |
vnode.attrs |
Object |
URLパラメータ値のマップ |
返り値 | Array<Vnode>|Vnode |
レンダリング対象のvnode |
どのように動作するのか
ラウティング(Routing = アメリカ英語読みはルーティングよりもラウティングが近い)は、シングルページアプリケーション(SPA)を作るための仕組みです。他のページに行く時に、フルにブラウザをリフレッシュしなくても済むアプリケーションを実現することができます。
この機能を使うと、各ページをブックマークしたり、ブラウザの履歴の機能はそのままに、シームレスなナビゲーションが可能になります。
ページリフレッシュをしないラウティングの一部はhistory.pushState()
APIによって実現されています。このAPIを使うと、ページがロードされた後に、プログラムによって新たなリロードを行わずに、ブラウザに表示されるURLを変更できます。しかし、プログラマはそのURLがそのままコピーされて、新しいタブなどの新しい状態で使用されたときにも、適切なマークアップが表示されることを保証しなければなりません。
ラウト戦略
ラウと戦略は、ライブラリがどのようにラウトを取り扱うのかを決定します。SPAのラウティングシステムを実装するのに使える戦略は、一般的に3種類あります。それぞれ違った特性を持っています。
- URLのフラグメント識別子(別名:ハッシュ)部分を使う。この戦略を使った時のURLは一般的には
http://localhost/#!/page1
のような形式になります。 - クエリー文字列の使用この戦略を使ったURLは
http://localhost/?/page1
のような形式になります。 - パス名の使用この戦略を使ったURLは
http://localhost/page1
のような形式になります。
ハッシュ戦略を使うと、history.pushState
をサポートしていないブラウザ(名前を挙げるとならInternet Explorer 9)でもonhashchange
にフォールバックするため使用することができます。もしIE9をサポートしたいのであればこの戦略を使用してください。
クエリー文字列戦略も技術的にはIE9で動作しますが、ページのリロードが発生してしまいます。この戦略はアンカーを使ったリンクを使用したいが、サーバー側の都合でパス名戦略が使用できないときに使います。
パス名戦略はもっともクリーンなURLを生成しますが、IE9をサポートしません。なおかつアプリケーションのラウターで取りうるすべてのURLでシングルページアプリケーションのコードを返すようにサーバーを設定する必要があります。この戦略はIE9のサポートが必要でなく、なおかつURLの見た目をきれいにしたいときに使います。
ハッシュ戦略を使うシングルページアプリケーションは、ハッシュの後に感嘆符(!)を付けてアンカーへのリンクではなく、ハッシュをラウティングメカニズムとして使用することを明示することがよくあります。#!
文字列はハッシュバングとして知られています。
デフォルトの戦略はハッシュバングです。
一般的な使用法
通常は、ラウトにマッピングするコンポーネントをいくつか作成します:
var Home = {
view: function() {
return [
m(Menu),
m("h1", "ホーム")
]
}
}
var Page1 = {
view: function() {
return [
m(Menu),
m("h1", "ページ 1")
]
}
}
このサンプルには、Home
とPage1
の2つのコンポーネントが含まれています。それぞれのコンポーネントはメニューとテキストを持っています。コードの重複を避けるためにメニューそのものもコンポーネントとなっています:
var Menu = {
view: function() {
return m("nav", [
m("a[href=/]", {oncreate: m.route.link}, "ホーム"),
m("a[href=/page1]", {oncreate: m.route.link}, "ページ 1"),
])
}
}
コンポーネントがそろったら、コンポーネントとラウトを対応付けます:
m.route(document.body, "/", {
"/": Home,
"/page1": Page1,
})
このコードでは2つのラウト、/
、/page1
を定義しています。ユーザーがそれぞれのURLを訪れたら、それぞれ適切なコンポーネントをレンダリングします。デフォルトでは、SPAのラウターは#!
をプリフィックスとして使用します。
異なるラウトへのナビゲーション
上記のサンプルではMenu
コンポーネントは2つリンクを持っていました。href
にはラウターURLを指定できます。{oncreate: m.route.link}
を付与すると、通常のリンクではなく、現在のページから指定ページに遷移するナビゲーションになります。
これ以外の方法では、m.route.set(route)
を使うとソースコードを使ってページの遷移を行わせられます。m.route.set("/page1")
のように使用します。
ラウトにナビゲートする時はラウタープリフィックスを指定する必要はありません。むしろ、m.route.link
やリダイレクトを行う時には、#!
をラウトパスの前に追加してはいけません。
ラウトのパラメータ
ラウトの中に、ID変数などのデータ表現を追加したいことがあります。もちろん、可能性のあるIDをすべて個別のラウトとして明示したくはありません。この機能を実現するために、Mithrilはパラメータ化したラウトをサポートしています。
var Edit = {
view: function(vnode) {
return [
m(Menu),
m("h1", vnode.attrs.id + "を編集中")
]
}
}
m.route(document.body, "/edit/1", {
"/edit/:id": Edit,
})
このサンプルでは/edit/:id
というラウトを定義しています。この記法を使うと、/edit/
から始まり、何らかのデータがその後に続く動的なラウトを定義できます。例えば、/edit/1
, edit/234
といったパスにマッチします。id
値は、vnode.attrs.id
のように、コンポーネントのvnodeコンポーネントの属性にマップされます。
/edit/:projectID/:userID
のように、複数の引数をラウトに持たせることができます。これらの引数も、コンポーネントのvnode属性オブジェクトのprojectID
、userID
プロパティになります。
Keyパラメーター
もし、ユーザーがパラメータ付きのラウトから、同じラウト定義(/page/:id
)のパラメータ違いのラウト(/page/1
から/page/2
)に遷移しようとした時は、1.0からは同じコンポーネントでラウトの解決が行われるため、コンポーネントの破棄と再作成は行われません。フルスクラッチではなく、その場のdiffによる高速な仮想DOMの更新が行われます。これの副作用として、このケースではoninit
/oncreate
のフックは呼ばれず、onupdate
フックだけが呼び出されます。しかし、0.2.Xのように、ラウト変更イベントに対して、同期的なコンポーネントの再生成を行って欲しいという需要も、開発者の中では比較的一般的です。
これらの両方のニーズを満たすために、ラウトのパラメータ化と仮想DOMのkey称号機能を使います。
m.route(document.body, "/edit/1", {
"/edit/:key": Edit,
})
このコードは、ルートのコンポーネントが、ラウトパラメータオブジェクトとしてkey
属性を持つことを意味します。ラウとパラメータはvnodeのattrs
プロパティとなります。この時、あるページから他のページに遷移すると、key
が変更されます。この属性の違いから、仮想DOMエンジンは、既存のコンポーネントと新しいコンポーネントの内容がまったく異なると判断し、既存のコンポーネントを破棄して新コンポーネントを再作成します。
この機能を使うと、リロード時に完全に再作成されるコンポーネントを作ることができます。
m.route.set(m.route.get(), {key: Date.now()})
あるいは、ヒストリー状態
の機能を使うと、URLを変更せずにリロード可能なコンポーネントを作ることができます。
m.route.set(m.route.get(), null, {state: {key: Date.now()}})
可変個引数のラウト
可変個引数をもったラウトを作ることもできます。例えば、スラッシュを含むURLのパス名を引数に取るラウトなどを実現することができます:
m.route(document.body, "/edit/pictures/image.jpg", {
"/files/:file...": Edit,
})
ヒストリー状態
ユーザのナビゲーションの使いやすさを向上させるために、裏で動作しているhistory.pushState
APIのすべての機能を使いこなせるようになっています。例えば、ユーザーがナビゲーションに従って別のページに遷移した時に、巨大な入力フォームの状態をアプリケーションに覚えさせておくこともできます。この機能を使うと、ユーザーがブラウザの「戻る」ボタンを押したときにフォームの状態を入力時の状態に維持しておくことができます。
次のようなフォームを作ることができます:
var state = {
term: "",
search: function() {
// 現在のラウトの状態を保持しておく
// これは`history.replaceState({term: state.term}, null, location.href)`と同じ
m.route.set(m.route.get(), null, {replace: true, state: {term: state.term}})
// 別のページに遷移
location.href = "https://google.com/?q=" + state.term
}
}
var Form = {
oninit: function(vnode) {
state.term = vnode.attrs.term || "" // ユーザーが戻るボタンを操作したときは`history.state`プロパティを復元
},
view: function() {
return m("form", [
m("input[placeholder='Search']", {oninput: m.withAttr("value", function(v) {state.term = v}), value: state.term}),
m("button", {onclick: state.search}, "検索")
])
}
}
m.route(document.body, "/", {
"/": Form,
})
この方法を使うと、ユーザーが検索したあとに戻るボタンを押してアプリケーションに戻ってきたときに検索用語が表示されたままになります。このテクニックはユーザー体験を大きく改善することができます。ユーザーが入力した内容を消去してしまうアプリケーションはユーザーに面倒さを与えてしまいます。
ラウタープリフィックスの変更
ラウタープリフィックはラウターが使用する戦略を決定する文字列です。
// パス名戦略を使用
m.route.prefix("")
// クエリー文字列戦略を使用
m.route.prefix("?")
// 感嘆符なしのハッシュを使用
m.route.prefix("#")
// URLのルートで稼働しないパス名戦略を使うアプリケーションの設定
// 他のページがhttp://localhostにあり、アプリケーションがhttp://localhost/my-app以下にある場合
m.route.prefix("/my-app")
高度なコンポーネントの解決
コンポーネントをラウトにマッピングする代わりに、ラウトリゾルバーオブジェクトを使うことができます。ラウトリゾルバーオブジェクトにははonmatch
メソッドとrender
メソッドの両方、あるいはどちらかが含まれます。メソッドはどちらもオプションですが、どちらか一方は必要です。
m.route(document.body, "/", {
"/": {
onmatch: function(args, requestedPath) {
return Home
},
render: function(vnode) {
return vnode // m(Home)と同じ
},
}
})
ラウトリゾルバーは、さまざまな高度なルーティングのユースケースを実装するのに便利です。
レイアウトコンポーネントのラッピング
ラウトで選択されるコンポーネントであっても、レイアウトと呼ばれる再利用可能な枠組みでラップして使われることがよくあります。まずさまざまなコンポーネントをラップする、共通のマークアップを含むコンポーネントを作成します。
var Layout = {
view: function(vnode) {
return m(".layout", vnode.children)
}
}
上記の例ではレイアウトの構成要素は、引数で渡された子供のコンポーネントをラップする<div class="layout">
しかありませんが、現実世界ではより複雑なコードになります。
レイアウトでラップする方法の1つは、ラウトの定義のマップの中で無名コンポーネントを定義する方法です:
// 例 1
m.route(document.body, "/", {
"/": {
view: function() {
return m(Layout, m(Home))
},
},
"/form": {
view: function() {
return m(Layout, m(Form))
},
}
})
しかし、トップレベルコンポーネントが無名コンポーネントだと、/
から/form
などのラウトに遷移した時に、無名コンポーネント一度破棄されて、ゼロから再生成されます。もしレイアウトコンポーネントがライフサイクルメソッドを持っていたとすると、ラウトの変更のたびにoninit
とoncreate
フックが呼び出されます。アプリケーションによりますが、この動作が望ましくないこともあるでしょう。
Layoutコンポーネントをゼロから再作成するのではなく、そのままの状態で差分更新を有効にしたい場合は、代わりにラウトリゾルバーをルートオブジェクトとして使用します:
// 例 2
m.route(document.body, "/", {
"/": {
render: function() {
return m(Layout, m(Home))
},
},
"/form": {
render: function() {
return m(Layout, m(Form))
},
}
})
この場合、すべてのラウトで同じレイアウトが使われていると判断されるため、レイアウトコンポーネントのoninit
、oncreate
のライフサイクルメソッドは最初のラウトの遷移では呼ばれなくなります。
これらのサンプルの違いを明確にするために、例 1と同じコードを作成してみます。
//例 1と機能的に同じ
var Anon1 = {
view: function() {
return m(Layout, m(Home))
},
}
var Anon2 = {
view: function() {
return m(Layout, m(Form))
},
}
m.route(document.body, "/", {
"/": {
render: function() {
return m(Anon1)
}
},
"/form": {
render: function() {
return m(Anon2)
}
},
})
Anon1
とAnon2
は異なるコンポーネントなので、Layout
を含むこれらのサブツリーはすべて、移行時に全部破棄されてから再作成されます。これは、ラウトリゾルバーを使わず、コンポーネントを直接使っていても起きます。
例2では、どちらのラウトでもLayout
がトップレベルコンポーネントでした。そのため、Layout
コンポーネントでは完全再作成ではなく、差分検知が行われ、変更がない部分はそのまま残り、DOMの子要素のHome
からForm
への再作成だけが行われます。
認証
ラウトリゾルバーのonmatch
フックはラウトのトップレベルコンポーネントが初期化される前になんらかのロジックを実行するときに使えます。次のサンプルは、ログインスクリーンを作成し、ログインしていないユーザーに/secret
ページを見せないようにするサンプルです。
var isLoggedIn = false
var Login = {
view: function() {
return m("form", [
m("button[type=button]", {
onclick: function() {
isLoggedIn = true
m.route.set("/secret")
}
}, "ログイン")
])
}
}
m.route(document.body, "/secret", {
"/secret": {
onmatch: function() {
if (!isLoggedIn) m.route.set("/login")
else return Home
}
},
"/login": Login
})
アプリケーションがロードされると、onmatch
が呼ばれ、isLoggedIn
がfalseになり、/login
にリダイレクトされます。ユーザーがログインすると、isLoggedIn
がtrueに設定され、アプリケーションは/secret
にリダイレクトします。onmatch
が再度実行されたときにisLoggedIn
がtrueであれば、Home
コンポーネントがレンダリングされます。
サンプルコードを短くするためにユーザーのログイン状態はグローバル変数を使って保持しています。このフラグはユーザーががログインボタンを押すと単純に入れ替わる手抜き実装になっています。実際のアプリケーションでは、ユーザーは適切なログインクレデンシャルを持つ必要があるでしょう。ログインボタンを押すとサーバーにユーザーの認証リクエストを送る実装になるでしょう。
var Auth = {
username: "",
password: "",
setUsername: function(value) {
Auth.username = value
},
setPassword: function(value) {
Auth.password = value
},
login: function() {
m.request({
url: "/api/v1/auth",
data: {username: Auth.username, password: Auth.password}
}).then(function(data) {
localStorage.setItem("auth-token": data.token)
m.route.set("/secret")
})
}
}
var Login = {
view: function() {
return m("form", [
m("input[type=text]", {oninput: m.withAttr("value", Auth.setUsername), value: Auth.username}),
m("input[type=password]", {oninput: m.withAttr("value", Auth.setPassword), value: Auth.password}),
m("button[type=button]", {onclick: Auth.login, "ログイン")
])
}
}
m.route(document.body, "/secret", {
"/secret": {
onmatch: function() {
if (!localStorage.getItem("auth-token")) m.route.set("/login")
else return Home
}
},
"/login": Login
})
データのプリロード
通常はコンポーネントの初期化時にデータをロードします。この方法でロードすると、コンポーネントはラウティング時と、リクエスト完了時の二回レンダリングされます。
var state = {
users: [],
loadUsers: function() {
return m.request("/api/v1/users").then(function(users) {
state.users = users
})
}
}
m.route(document.body, "/user/list", {
"/user/list": {
oninit: state.loadUsers,
view: function() {
return state.users.length > 0 ?state.users.map(function(user) {
return m("div", user.id)
}) : "ロード中"
}
},
})
上記のサンプルは、最初のレンダリングではstate.users
が空配列なので、リクエストが完了するまでは"ロード中"
と表示されます。データが利用可能にあると、UIが再描画され、ユーザーIDのリストが表示されます。
ラウトリゾルバーを使って、UIのフリッカーを回避するためにコンポーネントのレンダリング前にデータのプリロードを行い、代わりにロード中のインジケーターを表示することができます。
var state = {
users: [],
loadUsers: function() {
return m.request("/api/v1/users").then(function(users) {
state.users = users
})
}
}
m.route(document.body, "/user/list", {
"/user/list": {
onmatch: state.loadUsers,
render: function() {
return state.users.map(function(user) {
return m("div", user.id)
})
}
},
})
上記のrender
はリクエストが完了したときにのみ実行されます。
コード分割
巨大なアプリケーションでは、事前に全部のプログラムをダウンロードするのではなく、ラウトごとにオンデマンドでコードをダウンロードするほうが望ましいことがあります。このようなコードベースの分割は、コード分割、あるいは遅延ダウンロードと呼ばれます。Mithrilではonmatch
フックでPromiseを返すことで簡単に実現できます。
もっとも基本的な形式は次のようになります:
// Home.js
module.export = {
view: function() {
return [
m(Menu),
m("h1", "ホーム")
]
}
}
// index.js
function load(file) {
return m.request({
method: "GET",
url: file,
extract: function(xhr) {
return new Function("var module = {};" + xhr.responseText + ";return module.exports;")
}
})
}
m.route(document.body, "/", {
"/": {
onmatch: function() {
return load("Home.js")
},
},
})
しかし、現実的にこの手法をプロダクションレベルで実現するにはHome.js
に必要なモジュールを、サーバーから返されるファイルにすべてバンドルする必要があります。
幸い、遅延ダウンロードを実現するためにモジュールをバンドルする機能を持ったツールはいくつもあります。ここでは、WebPackのコード分割システムを使ってみましょう:
m.route(document.body, "/", {
"/": {
onmatch: function() {
// WebPackの非同期コード分割を使用
return new Promise(function(resolve) {
require(['./Home.js'], resolve)
})
},
},
})
License: MIT. © Leo Horie.