lodash优化前大小
webpack配置lodash单独生成一个bundle,优化前体积为3.2M。项目中用到lodash方法并不多,所以这个3.2M应该没有按需加载。
js
splitChunk: {
chunks: 'all',
cacheGroup: {
lodash: {
name: 'lodash',
test: /[\\/]node_modules[\\/]lodash/,
chunks: 'all',
priority: 18
}
}
}
写一个webpack插件,协助排查哪些地方用到了lodash。
js
class WebpackCustomPlugin {
apply(compiler) {
compiler.hooks.comilation.tap('WebpackCustomPlugin', compilation => {
compilation.hooks.succeedModule.tap('WebpackCustomPlugin', module => {
const source = module._source?.value
if (!source) return
const ast = require('@babel/parser').parse(source, {
sourceType: 'module'
})
const _this = this
const traverse = require('@babel/traverse').default
traverse(ast, {
ImportDeclaration(path) {
if (path.node.source.value.includes('lodash')) {
console.log(module.resource)
console.log('path')
}
}
})
})
})
}
}
输出结果发现:node_modules中有使用lodash,项目中使用的lodash-es, 将lodash和lodash-es分开生成bundle,lodash-es的大小为2.6M,lodash的大小为567KB,由此可知lodash-es按需加载应该存在问题。
webpack将lodash-es导入语句转换成什么样
在项目中是按照下面的方式进行导入的:
js
import { omitBy } from 'lodash-es'
webpack转换后的语句:
js
var lodash_es_WEBPCK_IMPORTED_MODULE_10 = __webpack_require__("./node_modules/lodash-es/lodash.js")
lodash_es_WEBPCK_IMPORTED_MODULE_10['omitBy']()
由此可见,lodash-es被全量导入了。
使用babel-plugin-loadsh
babel.config.js 中增加babel-plugin-babel的配置:
js
plugins: [
//...
[
'lodash', {
libraryName: 'loadsh-es',
libraryDirectory: '',
camel2DashComponentName: false
},
'lodash-es'
]
]
增加babel-plugin-loadsh配置后,再次执行发现loadsh-es的大小还是2.6M;检查项目中导入语句import { omitBy } from 'lodash-es'
已经正确转换为import omitBy from 'lodash-es/omitBy'
,那么问题出在哪里呢, 再次通过自定义webpack插件输出所有lodash-es导入语句,发现node_modules下的@antv中loadsh-es导入语句import { isEqual } from 'lodash-es'
没有正确转换。
babel-loader默认忽略node_mdouels下的文件
Vue-cli官方说明:
调试Vue-cli发现,babel-loader默认对node_modules下的js文件不处理。Vue-cli中module.rule('js').exclude的默认配置如下:
js
// module.rule('js').exclude
(filePath) => {
// alway transpile js in vue files
if (/\\.vue\\.jsx?$/.test(filePath)) return false
// exlude dynamic entries from cli-service
if (filePath.startWith(cliServicePath)) return true
// only include @babel/runtime when the @vue/babel-preset-app preset is used
if (
process.env.VUE_CLI_TRANSPILE_BABEL_RUNTIME &&
filePath.includes(path.join("@babel", "runtime"))
)
return false
// check if this is something the user explicity wants to transpile
if (transpileDepRegex && transpileDepRegex.test(filePath)) return false
// Don't transpile node_modules
return /node_modules/.test(filePath)
}
lodash完成按需加载
至此,lodash完成按需加载,优化后的大小为427KB