🎩 You're Invited:Meet the Socket team at Black Hat in Las Vegas, August 3-6.RSVP
Sign In

count-component-webpack-plugin

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

count-component-webpack-plugin - npm Package Compare versions

Comparing version
1.0.0
to
1.2.18
+9
.editorconfig
root=true
[*]
end_of_line = lf
insert_final_newline = true
[*.{cjs,js,ts,tsx,vue}]
charset = utf-8
indent_style = tab
env:
node: true
es2021: true
extends:
- standard-with-typescript
- plugin:prettier/recommended
overrides: []
ignorePatterns:
- '**/dist/**/*.js'
- '/*.d.ts'
parser: '@typescript-eslint/parser'
parserOptions:
ecmaVersion: latest
sourceType: module
project: ./tsconfig.json
plugins:
- prettier
rules:
'@typescript-eslint/triple-slash-reference': off
'@typescript-eslint/no-misused-promises':
- error
- checksVoidReturn: false
prettier/prettier: error
semi: false
singleQuote: true
trailingComma: 'none'
useTabs: true
{
"editor.codeActionsOnSave": {
"source.fixAll": true
},
"editor.detectIndentation": false,
"editor.tokenColorCustomizations": {
"textMateRules": [
{
"scope": "meta.function-call",
"settings": {
"fontStyle": "bold"
}
}
]
},
"eslint.validate": [
"javascript",
"vue",
"typescript",
"typescriptreact",
]
}
import type { Compiler } from 'webpack';
interface CountType {
[key: string]: number;
}
interface Options {
path: string | string[] | Record<string, string[]>;
isExportExcel?: boolean;
outputDir?: string;
percentageByMime: string[];
}
export declare class CountComponentsWebpackPlugin {
options: Options;
projectFiles: string[];
trait: Record<string, {
components: CountType;
percentage: Record<string, string>;
total: number;
}>;
constructor(options: Options);
maintainKind(branch: string, identifierName: string): void;
toExcel(): void;
toLog(): void;
apply(compiler: Compiler): void;
}
export {};
'use strict';
var xlsx = require('xlsx');
var lodash = require('lodash');
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
var exportToExcel = function (self) {
var trait = self.trait;
var bookNew = xlsx.utils.book_new, bookAppendSheet = xlsx.utils.book_append_sheet, jsonToSheet = xlsx.utils.json_to_sheet;
var workbook = bookNew();
Object.keys(trait).forEach(function (key) {
var flatObj = __assign(__assign({}, trait[key].components), trait[key].percentage);
var orderedObj = {};
Object.keys(trait).forEach(function (innerKey) {
// js对象键值对是有序的,拍一下方便看
orderedObj = Object.keys(flatObj[innerKey])
.sort()
.reduce(function (acc, cur) {
acc[cur] = flatObj[cur];
return acc;
}, {});
});
bookAppendSheet(workbook,
// 这json_to_sheet的入参得是个数组
jsonToSheet([
__assign({ total: trait[key].total }, orderedObj)
]), key);
});
var outputDir = self.options.outputDir;
xlsx.writeFile(workbook, outputDir === undefined ? './dist/count.xlsx' : "./".concat(outputDir, "/count.xlsx"));
};
var calculateTraitUsage = function (self) {
if (self.options.percentageByMime === undefined)
return;
var trait = self.trait;
var dedupedProjectFileArr = lodash.uniq(self.projectFiles);
self.options.percentageByMime.forEach(function (mime) {
// 算出来项目内对应格式的文件数量
var fileCount = dedupedProjectFileArr.filter(function (fileStr) {
return fileStr.endsWith(mime);
}).length;
Object.keys(trait).forEach(function (path) {
var tp = trait[path];
// 每个组件在项目中import次数除以fileCount,得到百分比
Object.keys(tp.components).forEach(function (component) {
var decimal = tp.components[component] / fileCount;
tp.percentage[component] = "".concat((decimal * 100).toFixed(3), "%");
});
lodash.mapKeys(tp.percentage, function (_, key) { return "".concat(key, "Per"); });
});
});
};
var hookDone = function (self, compiler) {
return compiler.hooks.done.tap('count-components-webpack-plugin-done', function () {
// 维护一下百分比
calculateTraitUsage(self);
self.options.isExportExcel !== undefined && self.options.isExportExcel
? self.toExcel()
: self.toLog();
});
};
var hookNormalModuleFactory = function (self, compiler) {
return compiler.hooks.normalModuleFactory.tap('count-components-webpack-plugin', function (factory) {
var pathHolderFromObj;
var path = self.options.path;
factory.hooks.parser
.for('javascript/auto')
.tap('count-components-webpack-plugin', function (parser) {
parser.hooks.importSpecifier.tap('count-components-webpack-plugin', function (_statement, source, _exportName, identifierName) {
if (typeof path === 'string') {
if (!source.includes(path))
return;
self.maintainKind(path, identifierName);
}
else if (Array.isArray(path)) {
path.forEach(function (str) {
if (!source.includes(str))
return;
self.maintainKind(str, identifierName);
});
}
else if (lodash.isPlainObject(path)) {
if (pathHolderFromObj === undefined)
pathHolderFromObj = Object.keys(path);
pathHolderFromObj.forEach(function (key) {
path[key].forEach(function (str) {
if (!source.includes(str))
return;
self.maintainKind(key, identifierName);
});
});
}
else {
throw new Error('未适配的path类型❗️');
}
});
});
});
};
var hookResolveFactory = function (self, compiler) {
return compiler.resolverFactory.hooks.resolver
.for('normal')
.tap('name', function (resolver) {
// you can tap into resolver.hooks now
resolver.hooks.result.tap('count-components-webpack-plugin', function (result) {
// context是存在的,webpack没给标ts类型,神奇
// descriptionFileRoot context.issuer path
var issuer = result.context.issuer;
if (Boolean(issuer) && !issuer.includes('/node_modules/'))
self.projectFiles.push(issuer);
return result;
});
});
};
var logResult = function (self) {
console.log('数出来了,算出来了:', JSON.stringify(self.trait, null, 4));
};
var maintainKind = function (self, branch, identifierName) {
var realBranch = self.trait[branch];
if (realBranch === undefined) {
realBranch = {
total: 0,
components: {},
percentage: {}
};
}
realBranch.total = realBranch.total + 1;
var key = identifierName;
realBranch.components[key] !== undefined
? (realBranch.components[key] += 1)
: (realBranch.components[key] = 1);
// 上面为了干净赋了变量,中途可能改变,这里赋回去
self.trait[branch] = realBranch;
};
var CountComponentsWebpackPlugin = /** @class */ (function () {
function CountComponentsWebpackPlugin(options) {
this.options = options;
this.trait = {};
this.projectFiles = [];
}
CountComponentsWebpackPlugin.prototype.maintainKind = function (branch, identifierName) {
maintainKind(this, branch, identifierName);
};
// 生成excel文件
CountComponentsWebpackPlugin.prototype.toExcel = function () {
exportToExcel(this);
};
CountComponentsWebpackPlugin.prototype.toLog = function () {
logResult(this);
};
CountComponentsWebpackPlugin.prototype.apply = function (compiler) {
hookNormalModuleFactory(this, compiler);
hookResolveFactory(this, compiler);
hookDone(this, compiler);
};
return CountComponentsWebpackPlugin;
}());
exports.CountComponentsWebpackPlugin = CountComponentsWebpackPlugin;
import type { CountComponentsWebpackPlugin } from '../main';
export declare const calculateTraitUsage: (self: CountComponentsWebpackPlugin) => void;
import type { CountComponentsWebpackPlugin } from '../main';
export declare const exportToExcel: (self: CountComponentsWebpackPlugin) => void;
import type { Compiler } from 'webpack';
import type { CountComponentsWebpackPlugin } from '../main';
export declare const hookDone: (self: CountComponentsWebpackPlugin, compiler: Compiler) => void;
import type { Compiler } from 'webpack';
import type { CountComponentsWebpackPlugin } from '../main';
export declare const hookNormalModuleFactory: (self: CountComponentsWebpackPlugin, compiler: Compiler) => void;
import type { Compiler } from 'webpack';
import type { CountComponentsWebpackPlugin } from '../main';
export declare const hookResolveFactory: (self: CountComponentsWebpackPlugin, compiler: Compiler) => void;
import type { Compiler } from 'webpack';
import type { CountComponentsWebpackPlugin } from '../main';
export declare const hookBuildModule: (self: CountComponentsWebpackPlugin, compiler: Compiler) => void;
export * from './export-to-excel';
export * from './hook-done';
export * from './hook-normal-module-factory';
export * from './hook-resolver-factory';
export * from './log-result';
export * from './maintain-kind';
import type { CountComponentsWebpackPlugin } from '../main';
export declare const logResult: (self: CountComponentsWebpackPlugin) => void;
import type { CountComponentsWebpackPlugin } from '../main';
export declare const maintainKind: (self: CountComponentsWebpackPlugin, branch: string, identifierName: string) => void;
# Introduce
## Install
```shell
npm install count-components-webpack-plugin
```
## Use
```js
import { CountComponentsWebpackPlugin } from 'count-components-webpack-plugin'
// in webpack plugin array
new CountComponentsWebpackPlugin({
path: {
uiLib: ['vant'],
projectComponents: ['@/components']
},
percentageByMime: ['vue'],
isExportExcel: true
})
```
import { mapKeys, uniq } from 'lodash'
import type { CountComponentsWebpackPlugin } from '../main'
export const calculateTraitUsage = (
self: CountComponentsWebpackPlugin
): void => {
if (self.options.percentageByMime === undefined) return
const trait = self.trait
const dedupedProjectFileArr = uniq(self.projectFiles)
self.options.percentageByMime.forEach((mime) => {
// 算出来项目内对应格式的文件数量
const fileCount = dedupedProjectFileArr.filter((fileStr) =>
fileStr.endsWith(mime)
).length
Object.keys(trait).forEach((path) => {
const tp = trait[path]
// 每个组件在项目中import次数除以fileCount,得到百分比
Object.keys(tp.components).forEach((component) => {
const decimal = tp.components[component] / fileCount
tp.percentage[component] = `${(decimal * 100).toFixed(3)}%`
})
tp.percentage = mapKeys(tp.percentage, (_, key) => `${key}Per`)
})
})
}
import { utils, writeFile } from 'xlsx'
import type { CountComponentsWebpackPlugin } from '../main'
export const exportToExcel = (self: CountComponentsWebpackPlugin): void => {
const trait = self.trait
const {
book_new: bookNew,
book_append_sheet: bookAppendSheet,
json_to_sheet: jsonToSheet
} = utils
const workbook = bookNew()
Object.keys(trait).forEach((key) => {
const flatObj = { ...trait[key].components, ...trait[key].percentage }
let orderedObj: typeof flatObj = {}
Object.keys(flatObj).forEach((innerKey) => {
// js对象键值对是有序的,排一下方便看
orderedObj = Object.keys(flatObj)
.sort()
.reduce<typeof flatObj>((acc, cur) => {
acc[cur] = flatObj[cur]
return acc
}, {})
})
bookAppendSheet(
workbook,
// 这json_to_sheet的入参得是个数组
jsonToSheet([
{
total: trait[key].total,
...orderedObj
}
]),
key
)
})
const outputDir = self.options.outputDir
writeFile(
workbook,
outputDir === undefined ? './dist/count.xlsx' : `./${outputDir}/count.xlsx`
)
}
import { calculateTraitUsage } from './calculate-trait-usage'
import type { Compiler } from 'webpack'
import type { CountComponentsWebpackPlugin } from '../main'
export const hookDone = (
self: CountComponentsWebpackPlugin,
compiler: Compiler
): void => {
return compiler.hooks.done.tap(
'count-components-webpack-plugin-done',
(): void => {
// 维护一下百分比
calculateTraitUsage(self)
self.options.isExportExcel !== undefined && self.options.isExportExcel
? self.toExcel()
: self.toLog()
}
)
}
import { isPlainObject } from 'lodash'
import type { Compiler } from 'webpack'
import type { CountComponentsWebpackPlugin } from '../main'
export const hookNormalModuleFactory = (
self: CountComponentsWebpackPlugin,
compiler: Compiler
): void => {
return compiler.hooks.normalModuleFactory.tap(
'count-components-webpack-plugin',
(factory): void => {
let pathHolderFromObj: string[]
const path = self.options.path
factory.hooks.parser
.for('javascript/auto')
.tap('count-components-webpack-plugin', (parser) => {
parser.hooks.importSpecifier.tap(
'count-components-webpack-plugin',
(
_statement: string,
source: string,
_exportName: string,
identifierName: string
) => {
if (typeof path === 'string') {
if (!source.includes(path)) return
self.maintainKind(path, identifierName)
} else if (Array.isArray(path)) {
path.forEach((str) => {
if (!source.includes(str)) return
self.maintainKind(str, identifierName)
})
} else if (isPlainObject(path)) {
if (pathHolderFromObj === undefined)
pathHolderFromObj = Object.keys(path)
pathHolderFromObj.forEach((key) => {
path[key].forEach((str) => {
if (!source.includes(str)) return
self.maintainKind(key, identifierName)
})
})
} else {
throw new Error('未适配的path类型❗️')
}
}
)
})
}
)
}
import type { Compiler } from 'webpack'
import type { CountComponentsWebpackPlugin } from '../main'
export const hookResolveFactory = (
self: CountComponentsWebpackPlugin,
compiler: Compiler
): void => {
return compiler.resolverFactory.hooks.resolver
.for('normal')
.tap('name', (resolver) => {
// you can tap into resolver.hooks now
resolver.hooks.result.tap('count-components-webpack-plugin', (result) => {
// context是存在的,webpack没给标ts类型,神奇
// descriptionFileRoot context.issuer path
const issuer: string = (result as any).context.issuer
if (Boolean(issuer) && !issuer.includes('/node_modules/'))
self.projectFiles.push(issuer)
return result
})
})
}
export * from './export-to-excel'
export * from './hook-done'
export * from './hook-normal-module-factory'
export * from './hook-resolver-factory'
export * from './log-result'
export * from './maintain-kind'
import type { CountComponentsWebpackPlugin } from '../main'
export const logResult = (self: CountComponentsWebpackPlugin): void => {
console.log('数出来了,算出来了:', JSON.stringify(self.trait, null, 4))
}
import type { CountComponentsWebpackPlugin } from '../main'
export const maintainKind = (
self: CountComponentsWebpackPlugin,
branch: string,
identifierName: string
): void => {
let realBranch = self.trait[branch]
if (realBranch === undefined) {
realBranch = {
total: 0,
components: {},
percentage: {}
}
}
realBranch.total = realBranch.total + 1
const key = identifierName
realBranch.components[key] !== undefined
? (realBranch.components[key] += 1)
: (realBranch.components[key] = 1)
// 上面为了干净赋了变量,中途可能改变,这里赋回去
self.trait[branch] = realBranch
}
+39
-20
{
"name": "count-component-webpack-plugin",
"version": "1.0.0",
"description": "",
"main": "src/index.ts",
"scripts": {
"build": "rollup --config"
},
"keywords": [],
"author": "",
"license": "ISC",
"devDependencies": {
"@types/node": "^18.11.0",
"chalk": "^5.1.2",
"rollup-plugin-typescript2": "^0.34.1",
"tslib": "^2.4.0",
"typescript": "^4.8.4"
},
"dependencies": {
"webpack": "^5.74.0"
}
"name": "count-component-webpack-plugin",
"version": "1.2.18",
"description": "count-components",
"main": "dist/main.js",
"scripts": {
"build": "rollup --config --bundleConfigAsCjs",
"lint": "eslint --fix --ext .ts"
},
"keywords": [
"webpack-plugin",
"typescript",
"rollup-bundle"
],
"author": "",
"license": "ISC",
"devDependencies": {
"@rollup/plugin-node-resolve": "^15.0.0",
"@types/lodash": "^4.14.186",
"@types/node": "^18.11.0",
"@typescript-eslint/eslint-plugin": "^5.40.0",
"eslint": "^8.0.1",
"eslint-config-prettier": "^8.5.0",
"eslint-config-standard-with-typescript": "^23.0.0",
"eslint-plugin-import": "^2.25.2",
"eslint-plugin-n": "^15.0.0",
"eslint-plugin-prettier": "^4.2.1",
"eslint-plugin-promise": "^6.0.0",
"prettier": "^2.7.1",
"rollup": "^3.2.2",
"rollup-plugin-typescript2": "^0.34.1",
"tslib": "^2.4.0",
"typescript": "^4.8.4"
},
"dependencies": {
"chalk": "^4.1.2",
"lodash": "^4.17.21",
"webpack": "^5.74.0",
"xlsx": "^0.18.5"
}
}

@@ -1,10 +0,11 @@

import typescript from "rollup-plugin-typescript2";
import typescript from 'rollup-plugin-typescript2'
export default {
input: "./src/main.ts",
output: {
dir: "output",
format: "cjs",
},
plugins: [typescript(/*{ plugin options }*/)],
};
external: ['chalk', 'lodash', 'xlsx'],
input: './src/main.ts',
output: {
dir: 'dist',
format: 'cjs'
},
plugins: [typescript()]
}

@@ -1,102 +0,59 @@

import {} from "fs";
import chalk from "chalk";
import {
exportToExcel,
hookDone,
hookNormalModuleFactory,
hookResolveFactory,
logResult,
maintainKind
} from './util'
import type { Compiler } from "webpack";
import type { Compiler } from 'webpack'
interface CountType {
[key: string]: number;
[key: string]: number
}
interface Options {
path: string | string[] | Record<string, string[]> // 文件的路径
isExportExcel?: boolean
outputDir?: string
percentageByMime: string[]
}
export class CountComponentsWebpackPlugin {
opts: {
pathname: string; // 文件的路径
startCount: boolean; // 是否开启统计
isExportExcel: boolean;
};
total: { len: number; components: CountType };
options: Options
projectFiles: string[]
// 根据path数处的组件名称和数量
trait: Record<
string,
{
components: CountType
percentage: Record<string, string>
total: number
}
>
constructor(opts = {}) {
this.opts = {
startCount: true, // 是否开启统计
isExportExcel: false, // 是否生成excel
pathname: "", // 文件路径
...opts,
};
this.total = {
len: 0,
components: {},
};
}
constructor(options: Options) {
this.options = options
this.trait = {}
this.projectFiles = []
}
sort(obj: CountType) {
this.total.components = Object.fromEntries(
Object.entries(obj).sort(([, a], [, b]) => b - a)
);
}
maintainKind(branch: string, identifierName: string): void {
maintainKind(this, branch, identifierName)
}
// 生成excel 文件
toExcel() {
console.log("输出为表格待完善");
}
// 生成excel文件
toExcel(): void {
exportToExcel(this)
}
toLog() {
this.sort(this.total.components);
Object.keys(this.total.components).forEach((key) => {
const value = this.total.components[key];
const per = Number((value / this.total.len).toPrecision(3)) * 100;
console.log(
`\n${chalk.blue(key)} 组件引用次数 ${chalk.green(
value
)} 引用率 ${chalk.redBright(per)}%`
);
});
console.log(
`\n组件${chalk.blue("总共")}引用次数 ${chalk.green(this.total.len)}`
);
}
toLog(): void {
logResult(this)
}
apply(compiler: Compiler) {
const parser = (factory: any) => {
if (!this.opts.startCount) {
return;
}
factory.hooks.parser
.for("javascript/auto")
.tap("count-webpack-plugin", (parser: any) => {
parser.hooks.importSpecifier.tap(
"count-webpack-plugin",
(
_statement: string,
source: string,
_exportName: string,
identifierName: string
) => {
if (source.includes(this.opts.pathname)) {
this.total.len = this.total.len + 1;
const key = identifierName;
this.total.components[key] = this.total.components[key]
? this.total.components[key] + 1
: 1;
}
}
);
});
};
const done = () => {
if (!this.opts.startCount) {
return;
}
this.sort(this.total.components);
this.opts.isExportExcel ? this.toExcel() : this.toLog();
};
compiler.hooks.normalModuleFactory.tap(
"count-components-webpack-plugin",
parser
);
compiler.hooks.done.tap("count-components-webpack-plugin-done", done);
}
apply(compiler: Compiler): void {
hookNormalModuleFactory(this, compiler)
hookResolveFactory(this, compiler)
hookDone(this, compiler)
}
}
{
"compilerOptions": {
"target": "es2016",
"target": "ES5",
"module": "ESNext",

@@ -15,3 +15,3 @@ "esModuleInterop": true,

"declarationDir": "dist/types",
"outDir": "dist/lib",
"outDir": "dist",
"typeRoots": [

@@ -22,4 +22,9 @@ "node_modules/@types"

"include": [
"src"
"src",
"rollup.config.js"
],
"exclude": [
"dist",
"node_modules"
]
}