UNPKG

vite-plugin-deadcodes

Version:

Vite plugin to detect unused files. JS, TS, React, Vue projects are supported.

189 lines (171 loc) 5.34 kB
import path from 'path'; import fs from 'fs'; import glob from 'glob'; // @ts-ignore import uniq from 'lodash.uniq'; import { minimatch } from 'minimatch'; const getProjectFiles = (dir: string) => { const parttern = path.join(dir, '**/*'); const files = glob.sync(parttern, { nodir: true, }); return files; }; // remove query and uniq const formatAndUniqLoadedFiles = (files: string[]) => { const formattedFiles = files.map(item => { const segments = item.split('?'); return segments[0]; }); const result = uniq(formattedFiles); return result; }; // TODO src/style/*.less 文件会被忽略,因为无法解析less中的@import? type GetUnusedFiles = (options: { allFiles: string[]; loadedFiles: string[]; excludes: string[]; }) => { rawUnusedFiles: string[]; unusedFiles: string[]; }; const getUnusedFiles: GetUnusedFiles = ({ allFiles, loadedFiles, excludes }) => { const rawUnusedFiles = allFiles.filter((item) => !loadedFiles.some((loadedFile) => loadedFile.includes(item))); const unusedFiles = excludes.length ? rawUnusedFiles.filter((item) => !excludes.some((exclude) => minimatch(item, exclude))) : rawUnusedFiles; return { rawUnusedFiles, unusedFiles }; }; // const getTimestamp = () => new Date().valueOf(); interface PluginRawOptions { src?: string; emit?: boolean | string; excludes?: string[]; console?: boolean; } interface PluginOptions { sourceDir: string; emit?: boolean | string; excludes: string[]; console: boolean; } const generatePluginConfig = (rawOptions: PluginRawOptions = {}): PluginOptions => { const excludes = Array.isArray(rawOptions.excludes) ? rawOptions.excludes : []; const emit = rawOptions.emit === false ? false : (typeof rawOptions.emit === 'string' ? rawOptions.emit : undefined); return { sourceDir: rawOptions.src || path.join(process.cwd(), 'src'), console: rawOptions.console || false, emit, // type: false or string; default: deadcodes-{timestamp}.json excludes, }; }; interface OutputResult { unusedFiles: { total: number; files: string[]; }; // loadedFiles: { // total: number; // files: string[]; // }; allFiles: { total: number; files: string[]; }; } export default function vitePluginDeadcodes(rawOptions: PluginRawOptions = {}) { const pluginOptions = generatePluginConfig(rawOptions); const loadedFiles: string[] = []; const filesInLoadHook: string[] = []; const filesInLoadTransform: string[] = []; return { name: 'vite-plugin-deadcodes', apply(config: any, { command }: any) { return command === 'build'; }, // config() { // }, // https://rollupjs.org/plugin-development/#load load(id: string) { if (id.includes(pluginOptions.sourceDir)) { filesInLoadHook.push(id); } }, // transform: { // order: 'pre', // handler(code, id) { // if (id.includes('config.sku-id')) { // console.log('transform', id, code); // } // if (id.includes(pluginOptions.sourceDir)) { // filesInLoadTransform.push(id); // } // }, // }, transform(code: string, id: string) { if (id.includes(pluginOptions.sourceDir)) { filesInLoadTransform.push(id); } }, moduleParsed(moduleInfo: any) { const id = moduleInfo.id; if (id.includes(pluginOptions.sourceDir)) { loadedFiles.push(id); } }, writeBundle(options: any, bundle: any) { // console.log('vite-plugin-deadcodes writeBundle', options); const formattedLoadedFiles = formatAndUniqLoadedFiles(loadedFiles); const allFiles = getProjectFiles(pluginOptions.sourceDir); const { // rawUnusedFiles, unusedFiles } = getUnusedFiles({ allFiles: allFiles, loadedFiles: formattedLoadedFiles, excludes: pluginOptions.excludes, }); // const formattedFilesInLoadHook = formatAndUniqLoadedFiles(filesInLoadHook); // const formattedFilesInLoadTransform = formatAndUniqLoadedFiles(filesInLoadTransform); const result: OutputResult = { unusedFiles: { total: unusedFiles.length, files: unusedFiles, }, // rawUnusedFiles: { // total: rawUnusedFiles.length, // files: rawUnusedFiles, // }, // loadedFiles: { // total: formattedLoadedFiles.length, // files: formattedLoadedFiles, // }, // filesInLoadHook: { // total: formattedFilesInLoadHook.length, // files: formattedFilesInLoadHook, // }, // filesInLoadTransform: { // total: formattedFilesInLoadTransform.length, // files: formattedFilesInLoadTransform, // }, allFiles: { total: allFiles.length, files: allFiles, }, }; if (pluginOptions.console) { console.log('vite-plugin-deadcodes', result); } if (pluginOptions.emit !== false) { const emitFileName = typeof pluginOptions.emit === 'string' ? pluginOptions.emit : path.join(process.cwd(), 'deadcodes.json'); fs.writeFileSync( emitFileName, JSON.stringify(result), { encoding: 'utf-8' }, ); } }, }; }