Mithril.js + webpack + mitts で ファイル分割、動的ロード。 code splitting!
SPA (Single Page Application) では ページ数が増えると 最終的なファイルサイズもどんどん増えていきます。
出来上がった アプリケーションを最初にロードさせるときにファイルサイズが大きくて、使う人たちが イライラするのはよろしくありません。
Mithril.js + webpack + mitts を使って必要なときに必要なぺージを動的に読み込むようにしてみましょう。
以下の例は、Page/Page1
は静的に読み込むページですが Page/Page2
は実際に必要になった時に動的に読み込まれます。
import m from 'mithril';
import stream from 'mithril/stream';
import mitts from "mitts";
import Page_Index from "Page/Index";
import Page_Page1 from 'Page/Page1'; // 静的にロードされるページ
// ロード開始~完了までの間に一時的に表示されるページ
const Loading = {
view(vnode) {
const { error, retry, pastDelay } = vnode.attrs;
if (error) {
return <div>Error! <button onclick={ retry }>Retry</button></div>
} else if (pastDelay) {
return <div>Loading...</div>;
} else {
return null;
}
}
};
// 動的にロードされるページ
const Loadable_Page2 = mitts({
loader: async ()=>{
const module = await import(/* webpackChunkName: "Page2" */ 'Page/Page2'); // !!!
return new module.default();
},
loading: Page_Loading,
m : m,
stream : stream,
});
m.route(document.body, '/', {
'/' : { render: ()=>{ return <Page_Index />; } } ,
'/page1' : { render: ()=>{ return <Page_Page1 />; } } ,
'/page2' : { render: ()=>{ return <Loadable_Page2 />; } } ,
}
Webpack の webpackChunkName のコツ
import(/* webpackChunkName: "Page2" */ 'Page/Page2')
の部分ですが、import() での引数のファイルパスは Webpack でのトランスパイル後のファイルパスではなりません。
そもそも、Webpack で1つのファイルにまとめられてしまえば意味が無い。だから分割 code splitting する。
仮に code splitting で分割できたとしてもトランスパイル後の実際のファイル名は分からない。
この悩みを解決するために webpackChunkName を利用しています。
こうすれば Webpack で 1つのファイルにまとめられずに、 Page/Page2
だけは単体で Webpack され dist/Page2.bundle.js
のように出力されます。
同時に パスは /* webpackChunkName: "Page2" */ 'Page/Page2'
の部分は 実際のパス dist/Page2.bundle.js
等に Webpack により置換されます。
tsconfig.json では removeComments : false を忘れずに
TypeScript を使用しているときに tsconfig.json
では "removeComments" : false
にしておく必要が有ります。
そうしないと /* webpackChunkName: ... */
などのパラメータが TypeScript が除去してしまい、Webpack に渡らないから、それを防ぐ必要があります。
{
"compilerOptions": {
"removeComments" : false,
}
}
環境
- "mithril": "2.0.4"
- "webpack": "4.26.0"
- "typescript": "4.26.0"