优化背景
根据微信提示的优化项:
组件/页面的usingComponents会影响启动速度,应避免将多余的组件声明usingComponents中
随着开发迭代的深入,很多页面中删除了对应的组件使用,却会习惯性的忘记删除对应的注册,根据优化提示,需要删除在usingComponents注册了,但没有在wxml真实使用的组件
实现细节
1. 获取入口小程序页面路由注册app.json文件
// 小程序注册入口文件
const entry = require(`${rootDir}/src/app.json`)
2. 根据入口文件获取分析pages,subPackages入口,找到每个页面的引用组件
Object.keys(entry).forEach((i) => {
if (i === 'pages') {
entry[i] &&
entry[i].length > 0 &&
entry[i].forEach((j) => {
inflateEntries(entries, currentDirname, j)
})
}
if (i === 'subPackages') {
entry[i].forEach((j) => {
if (j && j.pages && j.pages.length > 0) {
j.pages.forEach((k) => {
inflateEntries(entries, currentDirname, `${j.root}/${k}`)
})
}
})
}
})
3. 动态的遍历入口文件下所有子引用
通过每个入口文件找到引用到的每一个组件,将他们以文件绝对路径的形式存入数组,todo: 这里可以用weakmap优化性能
function _inflateEntries(entries = [], dirname, entry) {
const configFile = replaceExt(entry, '.json')
const content = fs.readFileSync(configFile, 'utf8')
const config = JSON.parse(content)
const { pages, usingComponents, subPackages } = config
pages && pages.forEach((item) => inflateEntries(entries, dirname, item))
usingComponents && Object.values(usingComponents).forEach((item) => inflateEntries(entries, dirname, item))
subPackages &&
subPackages.forEach((subpackage) => {
if (!subpackage.pages) {
return
}
return subpackage.pages.forEach((item) => inflateEntries(entries, dirname + `/${subpackage.root}`, item))
})
}
function inflateEntries(entries, dirname, entry) {
if (/plugin:\/\//.test(entry)) {
console.log(`发现插件 ${entry}`)
return
}
if (typeof entry !== 'string') {
throw new Error('入口文件位置获取有误')
}
entry = path.resolve(dirname, entry)
if (entry != null && !entries.includes(entry)) {
entries.push(entry)
_inflateEntries(entries, path.dirname(entry), entry)
}
}
4. 查找当前页面内未使用的组件并记录
遍历项目内所有已经在被使用的页面和组件,将当前页面/组件json和xml进行对比。把json里的usingComponents逐个遍历,通过<tagName 的形式判断是否在xml的文本里出现过。如果没有则记录可以删除的noUseTags内
const findNoUseComponents = (i, json, wxml) => {
const currentJSONComponents = []
const noUseTags = []
if (json.usingComponents) {
Object.keys(json.usingComponents).forEach((i) => {
currentJSONComponents.push(i)
})
} else {
console.log('there is no use components', i, json)
}
if (currentJSONComponents.length > 0) {
currentJSONComponents.forEach((i) => {
const tagsName = `<${i}`
if (wxml.indexOf(tagsName) < 0) {
noUseTags.push(i)
}
})
}
if (noUseTags.length > 0) {
noUseTagsNumsPages += 1
noUseTagPagesMap[i] = noUseTags
}
}
entries.forEach((i) => {
const jsonFile = path.resolve(`${i}.json`)
const xmlFile = path.resolve(`${i}.wxml`)
const jsonContent = fs.readFileSync(jsonFile, 'utf8')
const wxmlInfo = fs.readFileSync(xmlFile, 'utf8')
const jsonInfo = JSON.parse(jsonContent, 'utf8')
findNoUseComponents(i, jsonInfo, wxmlInfo)
})
5. 根据配置选择是否删除json里面的未使用的tag
if (isAutoDelete) {
Object.keys(noUseTagPagesMap).forEach((i) => {
const filePath = path.resolve(`${i}.json`)
const fileContent = fs.readFileSync(filePath)
const json = JSON.parse(fileContent, 'utf8')
const { usingComponents } = json
const noUseTagArr = noUseTagPagesMap[i]
Object.keys(usingComponents).forEach((j) => {
if (noUseTagArr.includes(j)) {
delete usingComponents[j]
}
})
const jsonContent = JSON.stringify(json)
fs.writeFile(filePath, jsonContent, 'utf8', function (err) {
if (err) {
console.log('An error occured while writing JSON Object to File.')
return console.log(err)
}
console.log('JSON file has been saved.')
})
})
}