你的小程序总共引入了多少组件?【下篇】
发布于 4 年前 作者 juan73 4406 次浏览 来自 分享

你的小程序总共引入了多少组件?【下篇】

前言

在【上篇】中,我对小程序项目中的代码文件做了一次简单的解析,将页面文件中引入的组件以对象的键值对形式输出到 csv 格式的文件中,数据结构格式如下所示:

{
  file: 'xxx.page',
  components: [
    {
	name: 'xxx',
	path: 'yyy'
    }
  ]
}

但是,我还没有对页面对应的 json 文件所引入组件列表做进一步的分析,也就是对页面的 wxml 文件是否 都全部使用到该组件列表里面的组件 做进一步的分析。

这样做的目的有以下几点:
1. 分析页面的无用组件引入,做进一步的删除代码优化,减少小程序包体积;
2. 统一项目中的组件ui样式,为后期的项目组件化打下根基(尤其是一些老旧项目的代码,错综复杂,代码过于冗余和繁琐)。

准备工作

思路

我在这里简单阐述一下这次编码过程的思路:

  1. 在【上篇】文章中我已经可以获取到了每个页面所对应的组件数组列表;
  2. 读取 wxml 文件内容字符串,将当前的字符串通过 html2json 工具库转换成 json 结构的对象;
  3. 遍历组件数组列表,然后__递归查找当前 wxml文件转化后的 json 对象__,判断是否存在组件的标签字符,存在就输出为__true__,不存在就输出为__false__。

我们可以简单看看wxml文件转化后的json对象结构,如下所示:

{
  node: 'root',
  child: [
    {
      node: 'element',
      tag: 'div',
      attr: { id: '1', class: 'foo' },
      child: [
        {
          node: 'element',
          tag: 'h2',
          child: [
            { node: 'text', text: 'sample text with ' },
            { node: 'element', tag: 'code', child: [{ node: 'text', text: 'inline tag' }] }
          ]
        },
        {
          node: 'element',
          tag: 'pre',
          attr: { id: 'demo', class: ['foo', 'bar'] },
          child: [{ node: 'text', text: 'foo' }]
        },
        {
          node: 'element',
          tag: 'pre',
          attr: { id: 'output', class: 'goo' },
          child: [{ node: 'text', text: 'goo' }]
        },
        {
          node: 'element',
          tag: 'input',
          attr: { id: 'execute', type: 'button', value: 'execute' }
        }
      ]
    }
  ]
}

安装工具包

安装 html2json 包

npm install --save-dev html2json

编码

【上篇】文章已经讲解过的逻辑就不再阐述了,有需要的老哥可以移步到这里看看,我主要针对这次主要的 __递归比对json对象的逻辑__阐述一下:

1. 比对页面json对象是否存在某标签字符

/**
 * 判断当前页面是否引入该组件标签
 * @param {*} pageJsonData 
 * @param {*} tagName 
 */
const isWxmlImportComponent = (pageJsonData, tagName) => {
  if (!pageJsonData.child) return false
  
  tagName = tagName.toLowerCase()
  for (let item of pageJsonData.child) {
    // 判断标签名是否一致
    if (item.tag === tagName) {
      return true
    }

    // 递归判断子节点的标签
    if (item.child) {
      const flag = isWxmlImportComponent(item, tagName)
      if (flag) {
        return true
      }
    }
  }
  return false
}

这是这次分享的核心代码,从 html2json 对象解析出来的对象我们可以发现,如果父标签有子标签的话,会有一个 child 的数组属性,于是我们就要对父标签进行递归操作:

    // 递归判断子节点的标签
    if (item.child) {
      const flag = isWxmlImportComponent(item, tagName)
      if (flag) {
        return true
      }
    }

并且每个标签都会有一个 tag 的属性,属性值就是标签名,于是由此得知,如果当前传入的标签名如果和当前标签一样,就可以退出当前的查找流程:

  // 判断标签名是否一致
    if (item.tag === tagName) {
      return true
    }

2. 组装拼接文件输出对象数组

我们来看看完整的脚本文件:

const path = require('path');
const { isWxmlImportComponent } = require('./tool/parseUtils');
const { getAllFiles, getFilterFiles, listComponents, getFileJsonData } = require('./tool/fileUtils');
const ObjectsToCsv = require('objects-to-csv');

(async function() {
  // 解析入口目录
  const entryDir = path.resolve(__dirname + '/../dist/pages')
  const allFiles = getAllFiles(entryDir)

  if (allFiles.length === 0) return

  const filterFiles = getFilterFiles(allFiles, ['wxml', 'json'])

  // 组装导出对象数组数据
  const pageWithComponents = filterFiles.reduce((acc, { jsonFile }) => {
    const current = path.basename(jsonFile, '.json')
    const currentDir = path.dirname(jsonFile)
    const components = listComponents(jsonFile) || []

    if (components.length == 0) {
      return [...acc, { 
        page: current, 
        directory: currentDir,
      }]
    } else {
      // 输入wxml地址,转化为json标签对象
      const fileJsonData = getFileJsonData(currentDir + `/${current}.wxml`)
      const childs = components.reduce((childAcc, { name, path }) => {
        const used = isWxmlImportComponent(fileJsonData, name)
        return [...childAcc, {
          page: current,
          directory: currentDir,
          component: name,
          componentPath: path,
          used: used ? 'true' : 'false',
        }]
      }, [])
      return [...acc, ...childs]
    }
  }, [])

  // 导出csv文件
  const csv = new ObjectsToCsv(pageWithComponents)
  await csv.toDisk(__dirname + '/component_status_stat.csv')
})()

文件导出效果

我这次对导出的数据结构做了一下优化,相比较【上篇】文章的导出格式更为直观易懂,一目了然,大家可以看看:

项目地址

项目地址:https://github.com/csonchen/wx-mall-components

脚本文件地址:https://github.com/csonchen/wx-mall-components/blob/master/shell/component-status.stat.js

脚本导出文件地址:https://github.com/csonchen/wx-mall-components/blob/master/shell/component_status_stat.csv

有需要的同学可以自行下载脚本文件,然后修改一下入口目录的路径,在本地用 node 命令执行脚本文件就可以跑起来了,这样就可以分析出你当前的小程序项目每个页面引用到的组件路径。

总结

关于本次对 如何分析小程序项目引入组件 的分享就到此结束了,这是我曾经接手一个老旧项目的时候所总结下来的一点小小经验;

当你要分析一个项目的时候,可以先通过编写脚本的方式去分析一下里面的代码逻辑,组件引入情况,这样可以避免你在不熟悉业务的前提下,对项目有一个整体的认知,为后期的项目优化提供一份资料作为参考。

欢迎大家继续关注。

回到顶部