小程序中识别并处理冗余组件引用

102 阅读3分钟

在微信小程序开发中,合理管理组件引用对优化项目体积和性能至关重要。随着代码库的扩大,未使用的组件引用可能会增加打包后的应用体积,进而影响加载速度和用户体验。本文将详细讲解如何使用自动化脚本识别并处理微信小程序中的冗余组件引用。

一、为什么要识别冗余组件引用?

在微信小程序中,每个页面或组件都会通过 json 文件声明使用的组件。然而,由于各种原因,一些组件可能被声明引用了但从未在对应的 wxml 文件中使用。识别这些冗余组件引用有以下好处:

  • 减少应用体积:未使用的组件不再被打包,从而减小应用的总体大小。
  • 提高加载速度:减少不必要的资源加载,提高用户访问速度。
  • 优化代码结构:清理不必要的引用,保持代码清晰易维护。

二、实现自动化识别冗余引用的步骤

以下是一个基于 Node.js 的自动化脚本,能够扫描项目中未使用的组件引用,并在构建或提交代码时提示开发者。

  1. 扫描 JSON 文件:首先,使用 fast-glob 扫描项目中所有的 .json 文件,排除掉主配置文件 app.json

    const jsonPathList = fg.sync('app/**/*.json', {
      ignore: ['app/app.json'],
    });
    
  2. 解析 JSON 文件:读取每个 .json 文件,检查 usingComponents 属性,获取声明的组件列表。如果不存在组件声明,跳过该文件。

    const json = JSON.parse(fs.readFileSync(jsonPath, 'utf-8'));
    if (!json.usingComponents) return;
    
  3. 查找对应的 WXML 文件:将 .json 文件路径转换为 .wxml 文件路径,解析文件内容,查找实际使用的组件标签。

    const wxmlPath = jsonPath.replace(/\.json$/, '.wxml');
    const declareButNotUseComponents = getDeclareButNotUseComponents(json.usingComponents, wxmlPath, json.componentPlaceholder);
    
  4. 识别未使用的组件:通过对比声明的组件列表和实际使用的组件标签,识别出未使用的组件。以下是详细的实现过程:

    • 解析 WXML 文件:读取 .wxml 文件内容,并使用 WXMLParser 解析文件。解析过程中,我们关注以下几种标签:

      • 组件标签:例如 <componentName /><componentName></componentName>
      • 导入标签:例如 <import src="./templates/head-layer/index.wxml"></import>
      • 抽象节点:例如 <selectable-group generic:selectable="custom-radio" />
      • 包含标签:例如 <include src="path/to/another.wxml" />,不支持动态路径。
    • 解析组件引用

      const getWxmlUsingTag = wxmlPath => {
        const wxml = fs.readFileSync(wxmlPath, 'utf-8');
        if (!wxml) return [];
      
        const usingTagList = [];
        const importTemplateSrcList = [];
      
        const parser = new WXMLParser({
          onopentag(tagName, attrs) {
            if (usingTagList.indexOf(tagName) === -1) {
              usingTagList.push(tagName);
            }
            if (tagName === 'import' || tagName === 'include') {
              const src = attrs.find(attr => attr.key === 'src')?.value;
              if (src) {
                importTemplateSrcList.push(src);
              }
            }
            attrs.forEach(attr => {
              if (typeof attr !== 'string' && attr.key.startsWith('generic:') && usingTagList.indexOf(attr.value) === -1) {
                usingTagList.push(attr.value);
              }
            });
          },
        });
        parser.write(wxml);
      
        importTemplateSrcList.forEach(src => {
          if (!src.endsWith('.wxml')) {
            src += '.wxml';
          }
          const importTemplatePath = src.startsWith('/') ? path.join('app', src) : path.resolve(path.dirname(wxmlPath), src);
          try {
            const importTemplateUsingTagList = getWxmlUsingTag(importTemplatePath);
            usingTagList.push(...importTemplateUsingTagList);
          } catch (error) {
            console.log('\x1b[31m', 'SCAN UNUSING COMPONENT ERROR:', src, importTemplatePath, error);
          }
        });
      
        return usingTagList;
      };
      
    • 比较组件列表

      const getDeclareButNotUseComponents = (declareComponents, wxmlPath, componentPlaceholder) => {
        const declareComponentNameList = Object.keys(declareComponents);
        const usingComponentNameList = getWxmlUsingTag(wxmlPath);
      
        if (componentPlaceholder) {
          usingComponentNameList.forEach(componentName => {
            if (componentPlaceholder[componentName]) {
              usingComponentNameList.push(componentPlaceholder[componentName]);
            }
          });
        }
      
        return declareComponentNameList.filter(component => !usingComponentNameList.includes(component));
      };
      
  5. 获取提交者信息:使用 getCommitterByPath 方法获取文件路径的提交者信息,以便在报告中包括相关开发者的信息。这对于追踪冗余组件的来源和通知相应开发者很有帮助。

    • 获取提交者信息
      const getCommitterByPath = async path => {
        const authorStr = await execSync(`cd ${path} && git log -10 --pretty=format:"%ae" ./`);
        return authorStr.stdout.split('\n')[0]
      };
      
  6. 记录并报告结果:将识别到的未使用组件信息记录到一个列表中,并通过接口发送到前端平台或使用消息系统通知相关开发者。如果需要,根据环境配置,可以选择终止构建过程。

    unUsingComponentResultList.push({
      path: jsonPath.replace('app/', ''),
      type: json.component ? 'component' : 'page',
      committer,
      declareButNotUseComponents,
    });
    
    sendUnUsingComponentToFePlatform(unUsingComponentResultList);
    
  7. 发送消息提醒:根据配置,通过企业微信等渠道发送通知,提醒开发者修复未使用的组件问题。

    sendMessage(`Warning: 存在引入但未使用的组件,请相关同学及时修改。`);
    

三、如何处理冗余组件引用?

一旦检测到冗余组件引用,开发者应采取以下措施:

  • 删除未使用的组件引用:从 json 文件中移除不再使用的组件,减少打包体积。
  • 重构代码:如果发现某些组件确实应该使用但未使用,检查代码逻辑,确保组件被正确调用。
  • 定期扫描:将上述自动化脚本集成到 CI/CD 流程中,确保在每次代码提交或构建时都能进行扫描检测。

四、总结

通过自动化脚本识别和处理微信小程序中的冗余组件引用,开发者可以有效减少应用体积,提高加载速度,并保持代码整洁。这不仅提升了用户体验,还为项目的长期维护打下了坚实的基础。