项目中无用export的检测方案

背景

export是js中用于导出模块的关键字,用法如export const dataexport function getData等,在项目版本迭代过程中,开发人员会出现把引用处代码给删了,但是忘记删除export const的情况。

如下图,export const没删的话,打包会把代码打进去增加代码体积。

本文提供一种方案,可以快速检测项目中无用export的情况,开发人员可以根据实际考量进行清除。

export导出的检测

js 复制代码
const { parse, Lang } = require('@ast-grep/napi')
const fg = require('fast-glob')
const path = require('node:path')
const fs = require('node:fs')

const files = fg.sync([path.join(__dirname, '/src/**/*.js')])

const data = []
const addData = (node) => {
  const keyword = node?.getMatch?.('A')?.text?.() || ''
  if (keyword) {
    data.push(keyword)
  }
}
files.forEach((file) => {
  const source = fs.readFileSync(file, 'utf-8')
  const ast = parse(Lang.JavaScript, source)
  const root = ast.root()
  let node = root.find('export const $A = $B')
  addData(node)
  node = root.find('export function $A ($B) { $C }')
  addData(node)
  node = root.find('export let $A = $B')
  addData(node)
})

fs.writeFileSync('./data.json', JSON.stringify(data, null, 2))

上述代码很简单,执行流程就是用fast-glob把所有js文件扫出来,然后借助ast-grep,把所有的export const代码找出来。

无用export的识别

第一步我们是把所有的export const都找出来了,第二步我们需要从中识别出来哪些是有用的,哪些是无用的。从性能、执行速度考虑,我们采用golang实现本步骤,而不用js。

go 复制代码
package main

import (
  "encoding/json"
  "fmt"
  "os"
  "path/filepath"
  "strings"
  "sync"
)

// 结构用于存储计数结果
type StringCount struct {
  String string
  Count  int
}

func main() {
  // 1. 读取 json 文件
  jsonData, err := os.ReadFile("data.json")
  if err != nil {
    fmt.Printf("无法读取json: %v\n", err)
    return
  }

  // 2. 解析 JSON 数据
  var data []string
  if err := json.Unmarshal(jsonData, &data); err != nil {
    fmt.Printf("解析 JSON 失败: %v\n", err)
    return
  }

  // 3. 存储结果的映射
  resultMap := make(map[string]int)
  var mutex sync.Mutex
  var wg sync.WaitGroup

  // 4. 遍历指定目录中的文件
  searchDir := "./src"
  fileCount := 0
  isJsVue := func(filePath string) bool {
    return strings.HasSuffix(filePath, ".js") || strings.HasSuffix(filePath, ".vue")
  }

  // 5. 文件处理函数
  processFile := func(filePath string) {
    defer wg.Done()
    
    if !isJsVue(filePath) {
      return
    }
    content, err := os.ReadFile(filePath)
    if err != nil {
      return
    }    
    contentStr := string(content)
        
    // 检查每个字符串在文件中的出现次数
    for _, searchStr := range data {
      count := strings.Count(contentStr, searchStr)
      if count > 0 {
        mutex.Lock()
        resultMap[searchStr] += count
        mutex.Unlock()
      }
    }
  }

  err = filepath.Walk(searchDir, func(path string, info os.FileInfo, err error) error {
    if err != nil {
      return err
    }   
    // 跳过目录
    if info.IsDir() {
      return nil
    }
    if isJsVue(path) {
      fileCount++
      wg.Add(1)
      go processFile(path)
    }
    return nil
  })

  if err != nil {
    fmt.Printf("目录遍历错误: %v\n", err)
    return
  }

  // 等待所有文件处理完成
  wg.Wait()

  results := make([]StringCount, 0, len(resultMap))
  for str, count := range resultMap {
    if count == 1 {
      results = append(results, StringCount{String: str, Count: count})
    }
  }
  // 输出结果
  for _, result := range results {
    fmt.Printf("%s: %d次\n", result.String, result.Count)
  }
}

不会golang也没关系,交给ai生成golang代码就行,上面的go代码其实我也是用ai生成的,哈哈哈。我们不必过于担忧ai会替代我们,而是拥抱ai,有ai这个强大的辅助,开发人员所要做的就是在开发过程中思考、挖掘可提升改进的点,需要自身深入业务深入项目,深入之后发挥自己的创新力。

相关推荐
Fluxart.ai11 小时前
电商商品图审核怎么自动化?规则引擎、人工复核与发布门禁
java·前端·自动化
why技术12 小时前
AI 写的文章,可能都带着手敲一遍都去不掉的“隐形水印”。
前端·人工智能·后端
愚公搬代码12 小时前
【愚公系列】《Android应用案例开发大全》016-LBS类应用掌上杭州(辅助工具类的开发)
android·前端
CodeSheep12 小时前
又一个华为天才少年,离职了!
前端·后端·程序员
kyriewen12 小时前
面试官说"打开你的AI工具"——我才发现,他考的根本不是写代码
前端·人工智能·面试
IT_陈寒13 小时前
Vue的双向绑定把我坑惨了,原来这个场景不能用
前端·人工智能·后端
hunterandroid14 小时前
[Android 从零到一] Compose LazyColumn 性能优化:key、稳定性与重组治理
android·前端
lichenyang45314 小时前
从一次团队邀请开始:用 React、NestJS 与 Socket.IO 做可靠的实时通知
前端
vtian14 小时前
一篇文章吃透 Monorepo:pnpm + Turborepo + Changesets 全流程实战(含 8 个踩坑)
前端
默_笙14 小时前
❗ 点击计数按钮,为什么"峨眉队"也跟着重新渲染?React.memo 说:我记住了
前端·javascript