如何在您的 Next.js 應用程式中實現懶加載模組
能夠視覺化分析捆包很棒,因為我們可以輕鬆優化我們的應用程式。
假設我們需要在我們的部落格文章中加載 Moment 庫。運行:
npm install moment
以將其包含在專案中。
現在讓我們模擬在/blog
和/blog/[id]
這兩個不同路由中需要使用Moment的情況。
我們在pages/blog/[id].js
中導入它:
import moment from 'moment'
...
const Post = props => {
return (
<div>
<h1>{props.post.title}</h1>
<p>發布於 {moment().format('dddd D MMMM YYYY')}</p>
<p>{props.post.content}</p>
</div>
)
}
這只是作為示例添加了今天的日期。
這將導致 Moment.js 包含在部落格文章頁面的捆包中,您可以通過運行npm run analyze
來看到:
看到現在在/blog/[id]
中有一個紅色條目,這是我們添加Moment.js後的路由!
這導致檔案從1kB變為350kB,十分驚人。原因是Moment.js本身的大小為349kB。
客戶端束縛視覺化現在顯示的是更大的捆包是內容頁面,以前只是非常小。且它的99%是Moment.js。
每次載入部落格文章時,我們都需要將所有這些程式碼傳輸到客戶端,這並不理想。
修復的一種方法是尋找一個尺寸較小的庫,因為Moment.js因並不以輕量級聞名(尤其是在默認情況下包含了所有的locales),但為了範例的完整性,讓我們假設我們必須使用它。
相反,我們可以將所有Moment庫程式碼分離到單獨的捆包中。
如何實現呢?我們不再在組件層級上導入Moment,而是在getInitialProps
中執行一個異步導入操作,然後計算要發送給組件的值。
請記住,我們無法在 getInitialProps()
回傳的對象中返回複雜對象,所以我們在其中計算了日期:
import posts from '../../posts.json'
const Post = props => {
return (
<div>
<h1>{props.post.title}</h1>
<p>發布於 {props.date}</p>
<p>{props.post.content}</p>
</div>
)
}
Post.getInitialProps = async ({ query }) => {
const moment = (await import('moment')).default()
return {
date: moment.format('dddd D MMMM YYYY'),
post: posts[query.id]
}
}
export default Post
看到await import
後面的.default()
特殊調用了嗎?這是為了在動態導入中引用默認導出來的。
現在如果我們再次運行npm run analyze
,我們可以看到這個結果:
我們的/blog/[id]
捆包大小再次很小,因為Moment已被移至它自己的捆包檔中,由瀏覽器單獨加載。