moment
庫,有沒有發現引入moment以後,項目build完的文件大小明顯大了很多,下面就來分析一下緣由, 以及如何作優化。
首先看下代碼結構react
import React from 'react'
import { render } from 'react-dom'
import moment from 'moment'
const App = () => {
const date = new Date()
return (
<div>
<h1>{date.toLocaleDateString()}</h1>
<h1>{moment().format('YYYY-MM-DD')}</h1>
</div>
)
}
render(<App/>, document.getElementById('app'))
複製代碼
上面兩張圖片分別是沒用moment和用了moment編譯的結果webpack
只有幾行代碼, 編譯出來的文件相差那麼大。網上搜了一波才知道, 打包時把全部的locale都打包進去了, 初步解決方案是用webpack.IgnorePlugin來處理。web
IgnorePlugin又是作了什麼操做?正則表達式
// webpack.config.js
...
plugins: [
new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/) // 配置忽略規則
]
複製代碼
原理:在webpack編譯階段, 若是引入的文件路徑匹配/^\.\/locale$/
,則會忽略這個文件, 也就不會被打包進去。json
moment
包編譯後的文件並未找到徹底匹配/^\.\/locale$/
這個正則的引入語句,只有aliasedRequire('./locale/' + name)
這條語句和locale相關, 卻又和正則匹配不上, 卻是在moment
的src源文件中有import ... from './locale'
。 可是在moment
的package.json
中main是指向編譯後的文件並非src文件,這就奇了怪了, 因而debug IgnorePlugin看了一下。./locale
, 眼瞎了仍是webpack的問題?按照dependencies的位置1853行查看moment編譯後的文件, 定位到了確實是 aliasedRequire('./locale/' + name)
, 怎麼回事?require('./locale/' + name)
此類表達式時,webpack 會查找目錄 './locale/'
下符合正則表達式 /^.*\.$/
的文件。因爲 name 在編譯時仍是未知的,webpack 會將每一個文件都做爲模塊引入到 bundle 中, 這就是爲何引入moment以後, 編譯完的文件爲何會那麼大的緣由。moment.locale('zh-cn')
以後, format以後的日期仍然是英文的,語言沒有切換過來。moment-locales-webpack-plugin
new MomentLocalesPlugin({
localesToKeep: ['zh-cn'],
})
複製代碼
en
,它必然會被打包進去, 若是須要配置其餘語言,能夠經過localesToKeep
來配置, 其餘沒用到的語言包也就不會被打包進去了。en
除外)...
if (localesToKeep.length > 0) {
var regExpPatterns = localesToKeep.map(function(localeName) {
return localeName + '(\\.js)?';
});
return new ContextReplacementPlugin(
/moment[\/\\]locale/,
new RegExp('(' + regExpPatterns.join('|') + ')$') // 配置webpack編譯階段的查找規則, 即指定語言包
);
} else {
return new IgnorePlugin(/^\.\/locale$/, /moment$/);
}
...
複製代碼
到此結束。bash
水平有限,文中有錯誤之處,還望大佬指正。app