项目中无用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这个强大的辅助,开发人员所要做的就是在开发过程中思考、挖掘可提升改进的点,需要自身深入业务深入项目,深入之后发挥自己的创新力。

相关推荐
apcipot_rain2 小时前
【应用密码学】实验五 公钥密码2——ECC
前端·数据库·python
ShallowLin2 小时前
vue3学习——组合式 API:生命周期钩子
前端·javascript·vue.js
Nejosi_念旧3 小时前
Vue API 、element-plus自动导入插件
前端·javascript·vue.js
互联网搬砖老肖3 小时前
Web 架构之攻击应急方案
前端·架构
pixle03 小时前
Vue3 Echarts 3D饼图(3D环形图)实现讲解附带源码
前端·3d·echarts
麻芝汤圆4 小时前
MapReduce 入门实战:WordCount 程序
大数据·前端·javascript·ajax·spark·mapreduce
juruiyuan1116 小时前
FFmpeg3.4 libavcodec协议框架增加新的decode协议
前端
Peter 谭6 小时前
React Hooks 实现原理深度解析:从基础到源码级理解
前端·javascript·react.js·前端框架·ecmascript
LuckyLay7 小时前
React百日学习计划——Deepseek版
前端·学习·react.js
gxn_mmf7 小时前
典籍知识问答重新生成和消息修改Bug修改
前端·bug