component-scanner

Cross-framework and simple web system component scanner, support vue
(html
, pug
template), react
, jsx
, tsx
, help counting component usage.
Usage
pnpm add component-scanner
import { scanComponents } from 'component-scanner';
const result = await scanComponents();
const result = await scanComponents({
namingStyle: 'kebab-case',
verbose: true,
cwd: process.cwd(),
files: [],
ignore: [
'**/node_modules/**',
'**/dist/**',
'**/output/**',
],
libraryNames: [
'antd',
'antd-design-vue',
'my-component-lib',
],
visitors: {
onTag: tagName => {},
onImport: importInfo => {},
},
alias: {
'a-button': 'custom-button',
'a-button': [
'custom-button',
'wrapped-button'
],
}
})
And then, you'll get Result[]
:
interface Result {
filename: string;
component: string[];
usage: Record<string, number>;
}
const result: Result = {
filename: 'src/modules/list/pages/tag/TagGroup.vue',
components: [
'byted-link',
'template',
'icon',
'byted-button',
'oplog-drawer',
'page-layout',
'audit-form',
'add-form'
],
usage: {
'byted-link': 1,
template: 2,
icon: 1,
'byted-button': 1,
'oplog-drawer': 1,
'page-layout': 1,
'audit-form': 1,
'add-form': 1
}
}
Some Utilities
This tool export some utilities used inside from zx and change-case, which may help you customize your logic conveniently.
export { chalk, fs, globby, os, path } from 'zx';
export { camelCase, pascalCase, paramCase as kebabCase } from 'change-case';
Example
There's a vue file like:
<template lang="pug">
AButton(@click="onClick")
a-icon
empty-box
</template>
<script setup lang="tsx">
import { message } from 'ant-design-vue';
import { MyEmptyBox as EmptyBox } from 'my-component-lib'
import { h, defineComponent } from 'vue';
const MyComponent = defineComponent({});
const MyButton = defineComponent({});
function onClick() {
message.success({
content: h('span', [
h(MyButton),
this.$createElement('div'),
<MyComponent>
<EmptyBox />
</MyComponent>
]);
})
}
</script>
This file is only for example, we can get message
, my-empty-box
, empty-box
, my-component
, my-button
, span
, div
a-button
, a-icon
from the file by component analysis. And then, you can manually handle the results.
Options
interface Visitor {
onTag(name: string): void;
onImport(value: ImportParam): void;
}
export interface ScanOptions {
visitors?: Visitor;
files?: string[];
cwd?: string;
ignore?: string[];
libraryNames?: string[];
namingStyle?: NamingStyle;
verbose?: boolean;
alias?: Record<string, string>
}
Motivation
This tool helps you refactor you inner business component library in company working.
Generally speaking, we work in multiple projects and they may use same components. You probably extract the components into a inner business component library, and introduce them from it.
Someday you want to refactor whether lib building process or component logic, but you don't know where're the components used in projects, which is not good for our regression tests, especially when the lib is introduced by lots of large projects.
In this case, this tool makes significant sense. This is the main problem this tool is designed to solve. As for the other usage, you can freely play it.
How it works
By AST analysis we can almost do whatever we want, this is one of things we can do.
In the most of situations we think of html
, pug
's tag name, JSXElement
's tag name as a component name, and extract them as statistical results.
But there are still some special cases that:
h
is a name convention that means render function in vue.this.$createElement
expression means the same in vue.
The first argument of these two function represents a component in common, especially when it is a string literal.
Sometimes we also consider the named imports as a component name. If you provide library names, it will extract the named imports from the lib as a component.
For example:
import { a as b, c } from 'my-component-lib';
In the case above, a
and c
will be accepted, b
is only an alias of a
, which will be abandoned.
Issue
We made some compatibility about vue, the detailed reasons is above. Sometimes it impacts accuracy, probably appears some unexpected components.
But we consider that it should extract component names as much as possible. Redundant component names can be ignored by some ways, but it probably cause some exceptions if we missed some component name in regression tests.
If you have an edge case, welcome to PR or file an issue.
License
MIT License © 2023 秦旭洋