brainy/verify-package-size.js
David Snelling 5f694bf1d1 **feat(cli): add script to estimate package size and .npmignore cleanup**
### Changes:
- **verify-package-size.js**:
  - Added a CLI script to calculate and display the estimated package size.
  - Integrated support for parsing `.npmignore` and `package.json` `files` patterns.
  - Outputs total package size and lists the largest files included.

- **.npmignore**:
  - Introduced an `.npmignore` file to exclude unnecessary development, configuration, and large files from the package.
  - Added patterns for source maps, development files, configuration files, and artifacts.

- **package.json**:
  - Updated the `files` array to include new patterns for distribution files (`.js`, `.d.ts`, `types`).
  - Improved package inclusion accuracy with precise file patterns.

### Purpose:
Introduced a new utility to provide quick insights into the package size for better maintenance and optimization. Optimized `.npmignore` and `files` configurations in `package.json` to exclude irrelevant files, ensuring a smaller, cleaner package distribution.
2025-06-23 10:39:05 -07:00

135 lines
3.5 KiB
JavaScript
Executable file

#!/usr/bin/env node
import fs from 'fs'
import path from 'path'
import { execSync } from 'child_process'
import { fileURLToPath } from 'url'
// Get the current directory
const __filename = fileURLToPath(import.meta.url)
const __dirname = path.dirname(__filename)
// Function to get the size of a file in MB
function getFileSizeInMB(filePath) {
const stats = fs.statSync(filePath)
return stats.size / (1024 * 1024)
}
// Function to check if a file should be included in the package
function shouldIncludeFile(filePath, npmignorePatterns, includePatterns) {
const relativePath = path.relative('.', filePath)
// Check if the file matches any npmignore pattern
for (const pattern of npmignorePatterns) {
if (pattern.test(relativePath)) {
return false
}
}
// If we have explicit include patterns, check if the file matches any
if (includePatterns.length > 0) {
for (const pattern of includePatterns) {
if (pattern.test(relativePath)) {
return true
}
}
return false
}
return true
}
// Parse .npmignore file
function parseNpmignore() {
const patterns = []
if (fs.existsSync('.npmignore')) {
const content = fs.readFileSync('.npmignore', 'utf8')
const lines = content.split('\n')
for (const line of lines) {
const trimmedLine = line.trim()
if (trimmedLine && !trimmedLine.startsWith('#')) {
// Convert glob pattern to regex
let pattern = trimmedLine
.replace(/\./g, '\\.')
.replace(/\*/g, '.*')
.replace(/\?/g, '.')
// Handle directory patterns
if (pattern.endsWith('/')) {
pattern = `${pattern}.*`
}
patterns.push(new RegExp(`^${pattern}$`))
}
}
}
return patterns
}
// Parse package.json files array
function parsePackageFiles() {
const patterns = []
const packageJson = JSON.parse(fs.readFileSync('package.json', 'utf8'))
if (packageJson.files && Array.isArray(packageJson.files)) {
for (const pattern of packageJson.files) {
// Convert glob pattern to regex
let regexPattern = pattern
.replace(/\./g, '\\.')
.replace(/\*/g, '.*')
.replace(/\?/g, '.')
// Handle directory patterns
if (regexPattern.endsWith('/')) {
regexPattern = `${regexPattern}.*`
}
patterns.push(new RegExp(`^${regexPattern}$`))
}
}
return patterns
}
// Calculate the total size of files that would be included in the package
function calculatePackageSize() {
const npmignorePatterns = parseNpmignore()
const includePatterns = parsePackageFiles()
let totalSize = 0
let includedFiles = []
function processDirectory(dirPath) {
const entries = fs.readdirSync(dirPath, { withFileTypes: true })
for (const entry of entries) {
const fullPath = path.join(dirPath, entry.name)
if (entry.isDirectory()) {
processDirectory(fullPath)
} else if (entry.isFile()) {
if (shouldIncludeFile(fullPath, npmignorePatterns, includePatterns)) {
const sizeInMB = getFileSizeInMB(fullPath)
totalSize += sizeInMB
includedFiles.push({ path: fullPath, size: sizeInMB })
}
}
}
}
processDirectory('.')
// Sort files by size (largest first)
includedFiles.sort((a, b) => b.size - a.size)
console.log('Estimated package size: ' + totalSize.toFixed(2) + ' MB')
console.log('\nLargest files:')
for (let i = 0; i < Math.min(10, includedFiles.length); i++) {
console.log(
`${includedFiles[i].path}: ${includedFiles[i].size.toFixed(2)} MB`
)
}
}
calculatePackageSize()