prod-files 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -20
- package/index.mjs +228 -62
- package/package.json +4 -6
package/README.md
CHANGED
|
@@ -11,7 +11,7 @@ projects, or you’re just obsessed with small deployments.
|
|
|
11
11
|
|
|
12
12
|
It's relatively fast, prunes
|
|
13
13
|
[Sentry's `node_modules`](https://github.com/getsentry/sentry/blob/master/package.json)
|
|
14
|
-
in
|
|
14
|
+
in 1.8s (M2 MacBook). Prod deps only though, installed with `pnpm i --prod`, but
|
|
15
15
|
that's the common use-case anyway.
|
|
16
16
|
|
|
17
17
|
## Install
|
|
@@ -62,7 +62,9 @@ Flags:
|
|
|
62
62
|
|
|
63
63
|
-g, --globs Prints out the default globs.
|
|
64
64
|
|
|
65
|
-
-n, --noSize Skips the size
|
|
65
|
+
-n, --noSize Skips the size calculation.
|
|
66
|
+
|
|
67
|
+
-q, --quiet Quiet output, suppresses stdout.
|
|
66
68
|
```
|
|
67
69
|
|
|
68
70
|
With a package manager:
|
|
@@ -122,42 +124,41 @@ RUN node pf.js my-app/foo/node_modules/.pnpm
|
|
|
122
124
|
|
|
123
125
|
## Development
|
|
124
126
|
|
|
125
|
-
Unit tests are written with node's test utils.
|
|
126
|
-
|
|
127
127
|
```sh
|
|
128
|
-
pnpm
|
|
128
|
+
pnpm i
|
|
129
129
|
```
|
|
130
130
|
|
|
131
|
-
|
|
132
|
-
random deps. You can run the script against it to see how it fairs in real usage
|
|
133
|
-
and get some timing data.
|
|
131
|
+
### Unit tests
|
|
134
132
|
|
|
135
|
-
|
|
133
|
+
Unit tests are written with node's test utils.
|
|
136
134
|
|
|
137
135
|
```sh
|
|
138
|
-
pnpm test
|
|
136
|
+
pnpm test
|
|
139
137
|
```
|
|
140
138
|
|
|
141
|
-
|
|
139
|
+
### End to end tests
|
|
140
|
+
|
|
141
|
+
In `test-project` directory has Sentry's `package.json`. You can run the script
|
|
142
|
+
against it to see how it does in real-world use and get some timing data.
|
|
142
143
|
|
|
143
144
|
```sh
|
|
144
|
-
|
|
145
|
+
# Re-installs the packages and runs the script on it
|
|
146
|
+
pnpm test:e2e
|
|
147
|
+
# Disable size reportings since it adds 200-300ms
|
|
148
|
+
pnpm test:e2e --noSize
|
|
145
149
|
```
|
|
146
150
|
|
|
147
|
-
|
|
148
|
-
before running another test.
|
|
149
|
-
|
|
150
|
-
Or chain it for ease of use (with timing):
|
|
151
|
+
The nuke command removes `node_modules` and prunes the store:
|
|
151
152
|
|
|
152
153
|
```sh
|
|
153
|
-
pnpm test:
|
|
154
|
+
pnpm test:e2e:nuke
|
|
154
155
|
```
|
|
155
156
|
|
|
156
|
-
There's also a simple script to print the
|
|
157
|
-
using `du
|
|
157
|
+
There's also a simple script to print the weight of `test-project/node_modules/`
|
|
158
|
+
using `du`. You can run it before and after to see more detailed results:
|
|
158
159
|
|
|
159
160
|
```sh
|
|
160
|
-
pnpm test:
|
|
161
|
+
pnpm test:e2e:weight
|
|
161
162
|
```
|
|
162
163
|
|
|
163
164
|
## Prior art
|
package/index.mjs
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
|
|
1
|
+
// oxlint-disable prefer-spread
|
|
2
|
+
import cp from 'node:child_process'
|
|
2
3
|
import fs from 'node:fs/promises'
|
|
3
4
|
import { matchesGlob, join, isAbsolute, resolve } from 'node:path'
|
|
4
|
-
import { parseArgs, styleText } from 'node:util'
|
|
5
|
+
import { parseArgs, promisify, styleText } from 'node:util'
|
|
6
|
+
|
|
7
|
+
const exec = promisify(cp.exec)
|
|
5
8
|
|
|
6
9
|
/**
|
|
7
10
|
* A list of glob patterns for files/dirs to be deleted. The globs are matched
|
|
8
11
|
* with node's `matchesGlob()`. With one special rule: globs which end in `/`
|
|
9
12
|
* are marked as directories.
|
|
10
13
|
*
|
|
11
|
-
*
|
|
14
|
+
* Roughly ordered by popularity (educated guess).
|
|
12
15
|
*
|
|
13
16
|
* Partially based on
|
|
14
17
|
* @see {@link https://github.com/duniul/clean-modules/blob/main/.cleanmodules-default}
|
|
@@ -21,16 +24,21 @@ const defaultGlobs = [
|
|
|
21
24
|
'**/*.tsx',
|
|
22
25
|
'**/doc{,s}/',
|
|
23
26
|
|
|
24
|
-
//
|
|
27
|
+
// Types
|
|
25
28
|
'**/*tsconfig*.json',
|
|
26
29
|
'**/*.tsbuildinfo',
|
|
30
|
+
'**/flow-typed/',
|
|
31
|
+
|
|
32
|
+
// Sensitive
|
|
33
|
+
'**/.env*',
|
|
27
34
|
|
|
28
35
|
// Package mangers
|
|
29
36
|
'**/.npm*',
|
|
30
|
-
'**/pnpm
|
|
37
|
+
'**/pnpm-{lock,workspace}.yaml',
|
|
31
38
|
'**/.yarn*',
|
|
32
39
|
'**/yarn.lock',
|
|
33
40
|
'**/bun.lock',
|
|
41
|
+
'**/bunfig.toml',
|
|
34
42
|
|
|
35
43
|
// IDE
|
|
36
44
|
'**/.idea/',
|
|
@@ -50,6 +58,13 @@ const defaultGlobs = [
|
|
|
50
58
|
// CI/CD
|
|
51
59
|
'**/.github/',
|
|
52
60
|
'**/.circleci/',
|
|
61
|
+
'**/.vercel',
|
|
62
|
+
'**/now.json',
|
|
63
|
+
'**/.travis.yml',
|
|
64
|
+
|
|
65
|
+
// Docker
|
|
66
|
+
'**/Dockerfile*',
|
|
67
|
+
'**/.dockerignore',
|
|
53
68
|
|
|
54
69
|
// Tests
|
|
55
70
|
'**/test{,s}/',
|
|
@@ -60,31 +75,42 @@ const defaultGlobs = [
|
|
|
60
75
|
'**/karma.conf.{js,ts}',
|
|
61
76
|
'**/wallaby.conf.{js,ts}',
|
|
62
77
|
'**/wallaby.{js,ts}',
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
78
|
+
'**/playwright.config.{js,ts}',
|
|
79
|
+
'**/.mocharc*',
|
|
80
|
+
|
|
81
|
+
// Build/bundle config
|
|
82
|
+
'**/{rollup,rolldown,vite}.config.{js,ts,mjs}',
|
|
83
|
+
'**/webpack.config.{js,mjs,cjs,ts}',
|
|
84
|
+
'**/babel.config.{js,mjs,cjs,json}',
|
|
85
|
+
'**/parcel.config.{js,ts,json}',
|
|
86
|
+
'**/rspack.config.{js,mjs,cjs,ts}',
|
|
87
|
+
'**/.babelrc*',
|
|
88
|
+
'**/turbo.json',
|
|
89
|
+
'**/.browserslist*',
|
|
90
|
+
'**/metro.config.{js,json}',
|
|
66
91
|
'**/{G,g}runtfile.{js,ts}',
|
|
67
92
|
'**/{G,g}ulpfile.{js,ts}',
|
|
68
93
|
'**/{M,m}akefile',
|
|
94
|
+
'**/gemfile',
|
|
69
95
|
|
|
70
96
|
// Images
|
|
71
97
|
'**/*.jp{,e}g',
|
|
72
|
-
'**/*.png',
|
|
73
|
-
'**/*.gif',
|
|
74
98
|
'**/*.svg',
|
|
99
|
+
'**/*.gif',
|
|
100
|
+
'**/*.png',
|
|
75
101
|
|
|
76
102
|
// Linters and formatters
|
|
77
|
-
'**/.jshintrc',
|
|
78
|
-
'**/.lint',
|
|
79
|
-
'**/.prettier*',
|
|
80
|
-
'**/prettier.config*',
|
|
81
|
-
'**/biome.json{,c}',
|
|
82
|
-
'**/tslint.json',
|
|
83
|
-
'**/.eslintrc',
|
|
84
103
|
'**/eslint*.{json,jsonc,ts}',
|
|
104
|
+
'**/.eslintrc',
|
|
105
|
+
'**/prettier.config*',
|
|
106
|
+
'**/.prettier*',
|
|
85
107
|
'**/.ox{lint,fmt}rc.json{,c}',
|
|
86
108
|
'**/ox{lint,fmt}*.{json,jsonc,ts}',
|
|
109
|
+
'**/biome.json{,c}',
|
|
87
110
|
'**/.dprint.json{,c}',
|
|
111
|
+
'**/.jshintrc',
|
|
112
|
+
'**/.lint',
|
|
113
|
+
'**/tslint.json',
|
|
88
114
|
|
|
89
115
|
// Git
|
|
90
116
|
'**/.git/',
|
|
@@ -93,7 +119,7 @@ const defaultGlobs = [
|
|
|
93
119
|
|
|
94
120
|
// Code coverage
|
|
95
121
|
'**/.nyc_output/',
|
|
96
|
-
'**/.nycrc',
|
|
122
|
+
'**/.nycrc*',
|
|
97
123
|
'**/.codecov.y{,a}ml',
|
|
98
124
|
'**/coverage/',
|
|
99
125
|
|
|
@@ -123,6 +149,7 @@ const defaultGlobs = [
|
|
|
123
149
|
'**/*.coffee',
|
|
124
150
|
|
|
125
151
|
// Misc
|
|
152
|
+
'**/.jscpd',
|
|
126
153
|
'**/*.jst',
|
|
127
154
|
'**/*.log',
|
|
128
155
|
'**/*.mkd',
|
|
@@ -188,10 +215,12 @@ function usage() {
|
|
|
188
215
|
|
|
189
216
|
-g, --globs Prints out the default globs.
|
|
190
217
|
|
|
191
|
-
-n, --noSize Skips the size
|
|
218
|
+
-n, --noSize Skips the size calculation.
|
|
219
|
+
|
|
220
|
+
-q, --quiet Quiet output, suppresses stdout.
|
|
192
221
|
`
|
|
193
222
|
|
|
194
|
-
|
|
223
|
+
log.log(usageText)
|
|
195
224
|
}
|
|
196
225
|
|
|
197
226
|
/**
|
|
@@ -213,29 +242,70 @@ function bail(message, error, withUsage = false) {
|
|
|
213
242
|
|
|
214
243
|
/**
|
|
215
244
|
* @typedef {Object} Logger
|
|
216
|
-
* @property {
|
|
217
|
-
* @property {
|
|
218
|
-
* @property {
|
|
245
|
+
* @property {typeof console.error} error - Logs error messages in red
|
|
246
|
+
* @property {typeof console.info} info - Logs information messages in blue
|
|
247
|
+
* @property {typeof console.info} log - Logs with no color
|
|
248
|
+
* @property {typeof console.log} success - Logs success messages in green
|
|
249
|
+
* @property {typeof console.table} table - Logs as table
|
|
219
250
|
*/
|
|
220
251
|
|
|
252
|
+
// Quiet mode
|
|
253
|
+
let quiet = /** @type {boolean} */ (false)
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* @param {import('node:util').InspectColor} color
|
|
257
|
+
* @param {any[]} args
|
|
258
|
+
* @returns
|
|
259
|
+
*/
|
|
260
|
+
const style = (color, args) => args.map(a => styleText(color, String(a)))
|
|
261
|
+
|
|
221
262
|
/**
|
|
222
263
|
* A utility for styled console logs
|
|
223
264
|
* @type {Logger}
|
|
224
265
|
*/
|
|
225
|
-
const log = {
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
266
|
+
export const log = {
|
|
267
|
+
error: (...a) =>
|
|
268
|
+
quiet ? undefined : console.error.apply(console, style('red', a)),
|
|
269
|
+
info: (...a) =>
|
|
270
|
+
quiet ? undefined : console.info.apply(console, style('blue', a)),
|
|
271
|
+
log: (...a) => (quiet ? undefined : console.log.apply(console, a)),
|
|
272
|
+
success: (...a) =>
|
|
273
|
+
quiet ? undefined : console.log.apply(console, style('green', a)),
|
|
274
|
+
table: (...a) => (quiet ? undefined : console.table.apply(console, a)),
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
/**
|
|
278
|
+
* Get disk usage via du (512-byte blocks)
|
|
279
|
+
* @param {string} dirPath
|
|
280
|
+
* @returns {Promise<number>}
|
|
281
|
+
*/
|
|
282
|
+
async function getSize(dirPath) {
|
|
283
|
+
const { stdout, stderr } = await exec(`LC_ALL=C du -s ${dirPath}`)
|
|
284
|
+
if (stderr.length > 0) bail(stderr)
|
|
285
|
+
const size = stdout.split('\t')[0]
|
|
286
|
+
return size ? Number.parseInt(size, 10) : 0
|
|
229
287
|
}
|
|
230
288
|
|
|
231
289
|
/**
|
|
232
|
-
*
|
|
233
|
-
* @param {string}
|
|
234
|
-
* @returns {number}
|
|
290
|
+
* Sums disk usage of a path using lstat blocks (512-byte blocks, same as du)
|
|
291
|
+
* @param {string} path
|
|
292
|
+
* @returns {Promise<number>} Total in 512-byte blocks
|
|
235
293
|
*/
|
|
236
|
-
function
|
|
237
|
-
|
|
238
|
-
|
|
294
|
+
async function treeSize(path) {
|
|
295
|
+
/** @type {import('node:fs').Stats} */
|
|
296
|
+
let stat
|
|
297
|
+
try {
|
|
298
|
+
stat = await fs.lstat(path)
|
|
299
|
+
} catch {
|
|
300
|
+
// Entry disappeared (concurrent pruning), count as 0
|
|
301
|
+
return 0
|
|
302
|
+
}
|
|
303
|
+
if (!stat.isDirectory()) return stat.blocks
|
|
304
|
+
const names = await fs.readdir(path).catch(() => [])
|
|
305
|
+
const sizes = await Promise.all(names.map(n => treeSize(join(path, n))))
|
|
306
|
+
let total = 0
|
|
307
|
+
for (const s of sizes) total += s
|
|
308
|
+
return total
|
|
239
309
|
}
|
|
240
310
|
|
|
241
311
|
/**
|
|
@@ -253,16 +323,23 @@ function calcSize(originalSize, prunedSize) {
|
|
|
253
323
|
/**
|
|
254
324
|
* Prints a nice diff table
|
|
255
325
|
* @param {object} opts
|
|
256
|
-
* @param {number | undefined} opts.
|
|
326
|
+
* @param {number | undefined} opts.removedBytes
|
|
257
327
|
* @param {number} opts.startTime
|
|
258
328
|
* @param {number} opts.itemCount
|
|
259
329
|
* @param {number | undefined} opts.originalSize
|
|
260
330
|
*/
|
|
261
|
-
export function printDiff({
|
|
262
|
-
|
|
331
|
+
export function printDiff({
|
|
332
|
+
removedBytes,
|
|
333
|
+
startTime,
|
|
334
|
+
itemCount,
|
|
335
|
+
originalSize,
|
|
336
|
+
}) {
|
|
337
|
+
log.table([
|
|
263
338
|
{
|
|
264
|
-
|
|
265
|
-
|
|
339
|
+
...(originalSize &&
|
|
340
|
+
removedBytes && {
|
|
341
|
+
Pruned: calcSize(originalSize, originalSize - removedBytes),
|
|
342
|
+
}),
|
|
266
343
|
Time: `${((Date.now() - startTime) / 1000).toFixed(1)}s`,
|
|
267
344
|
Items: itemCount,
|
|
268
345
|
},
|
|
@@ -278,12 +355,14 @@ export function printDiff({ prunedSize, startTime, itemCount, originalSize }) {
|
|
|
278
355
|
* @property {boolean} help - Prints help
|
|
279
356
|
* @property {boolean} noSize - Don't show size savings
|
|
280
357
|
* @property {boolean} globs - Prints globs
|
|
358
|
+
* @property {boolean} quiet - Suppress console.log output
|
|
281
359
|
*/
|
|
282
360
|
|
|
283
361
|
/**
|
|
284
362
|
* Parse the command-line arguments into an object
|
|
285
363
|
* @returns {Args}
|
|
286
364
|
*/
|
|
365
|
+
|
|
287
366
|
function handleArgs() {
|
|
288
367
|
try {
|
|
289
368
|
const {
|
|
@@ -297,6 +376,7 @@ function handleArgs() {
|
|
|
297
376
|
help: { type: 'boolean', short: 'h', default: false },
|
|
298
377
|
globs: { type: 'boolean', short: 'g', default: false },
|
|
299
378
|
noSize: { type: 'boolean', short: 'n', default: false },
|
|
379
|
+
quiet: { type: 'boolean', short: 'q', default: false },
|
|
300
380
|
},
|
|
301
381
|
})
|
|
302
382
|
|
|
@@ -326,14 +406,6 @@ export async function validateNodeModulesPath(nodeModulesPath) {
|
|
|
326
406
|
}
|
|
327
407
|
}
|
|
328
408
|
|
|
329
|
-
/**
|
|
330
|
-
* Removes a directory or a file
|
|
331
|
-
* @param {string} file - the file or dir to remove
|
|
332
|
-
*/
|
|
333
|
-
async function rimraf(file) {
|
|
334
|
-
await fs.rm(file, { recursive: true, force: true })
|
|
335
|
-
}
|
|
336
|
-
|
|
337
409
|
/**
|
|
338
410
|
* `file.matchesGlob()` does not match dotfiles, this util replaces leading dots
|
|
339
411
|
* with an underscore
|
|
@@ -643,6 +715,104 @@ export function compactPaths(paths) {
|
|
|
643
715
|
return compact
|
|
644
716
|
}
|
|
645
717
|
|
|
718
|
+
/**
|
|
719
|
+
* @typedef {object} WalkResult
|
|
720
|
+
* @property {string[]} removed - Compacted list of removed paths
|
|
721
|
+
* @property {number} removedBlocks - Removed disk usage in 512-byte blocks
|
|
722
|
+
*/
|
|
723
|
+
|
|
724
|
+
/**
|
|
725
|
+
* Parallel walker that finds junk, removes it, and cleans empty dirs in one
|
|
726
|
+
* pass. Skips recursing into junk directories (implicit path compacting) and
|
|
727
|
+
* removes empty ancestors bottom-up as the recursion unwinds.
|
|
728
|
+
* @param {string} rootDir - The directory to walk
|
|
729
|
+
* @param {CompiledGlobs} compiledGlobs - Precompiled glob matchers
|
|
730
|
+
* @param {boolean} trackSize - Whether to collect byte sizes of removed items
|
|
731
|
+
* @returns {Promise<WalkResult>}
|
|
732
|
+
*/
|
|
733
|
+
async function walkAndPrune(rootDir, compiledGlobs, trackSize) {
|
|
734
|
+
/** @type {string[]} */
|
|
735
|
+
const removed = []
|
|
736
|
+
let removedBlocks = 0
|
|
737
|
+
const hasAnyGlobs = compiledGlobs.any.globs.length > 0
|
|
738
|
+
const hasDirGlobs = compiledGlobs.dir.globs.length > 0
|
|
739
|
+
|
|
740
|
+
/**
|
|
741
|
+
* Walks a directory in parallel, removes junk, and reports whether the
|
|
742
|
+
* directory still has content so the caller can clean up empty parents
|
|
743
|
+
* @param {string} dir
|
|
744
|
+
* @returns {Promise<boolean>} true when the directory still has content
|
|
745
|
+
*/
|
|
746
|
+
async function walkDir(dir) {
|
|
747
|
+
const entries = await fs.readdir(dir, { withFileTypes: true })
|
|
748
|
+
|
|
749
|
+
/** @type {string[]} */
|
|
750
|
+
const junkPaths = []
|
|
751
|
+
/** @type {string[]} */
|
|
752
|
+
const keptDirPaths = []
|
|
753
|
+
let keptFiles = 0
|
|
754
|
+
|
|
755
|
+
for (const entry of entries) {
|
|
756
|
+
const { name } = entry
|
|
757
|
+
const isDir = entry.isDirectory()
|
|
758
|
+
const path = join(dir, name)
|
|
759
|
+
|
|
760
|
+
// Basename checks are cheapest, try them first
|
|
761
|
+
if (
|
|
762
|
+
matchesSet(name, compiledGlobs.any) ||
|
|
763
|
+
(isDir && matchesSet(name, compiledGlobs.dir))
|
|
764
|
+
) {
|
|
765
|
+
junkPaths.push(path)
|
|
766
|
+
continue
|
|
767
|
+
}
|
|
768
|
+
|
|
769
|
+
// Full path glob checks only when compiled globs exist
|
|
770
|
+
if (hasAnyGlobs || (isDir && hasDirGlobs)) {
|
|
771
|
+
const escapedPath = escapeLeadingDots(isDir ? `${path}/` : path)
|
|
772
|
+
if (
|
|
773
|
+
compiledGlobs.any.globs.some(g => matchesGlob(escapedPath, g)) ||
|
|
774
|
+
(isDir &&
|
|
775
|
+
compiledGlobs.dir.globs.some(g => matchesGlob(escapedPath, g)))
|
|
776
|
+
) {
|
|
777
|
+
junkPaths.push(path)
|
|
778
|
+
continue
|
|
779
|
+
}
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
if (isDir) keptDirPaths.push(path)
|
|
783
|
+
else keptFiles += 1
|
|
784
|
+
}
|
|
785
|
+
|
|
786
|
+
// Collect removed paths before awaiting (no junk dir recursion = compacting)
|
|
787
|
+
for (const p of junkPaths) removed.push(p)
|
|
788
|
+
|
|
789
|
+
// Size (when tracking), remove junk, and recurse kept subdirs in parallel
|
|
790
|
+
const [junkSizes, walkResults] = await Promise.all([
|
|
791
|
+
Promise.all(
|
|
792
|
+
junkPaths.map(async p => {
|
|
793
|
+
const size = trackSize ? await treeSize(p) : 0
|
|
794
|
+
await fs.rm(p, { recursive: true, force: true })
|
|
795
|
+
return size
|
|
796
|
+
})
|
|
797
|
+
),
|
|
798
|
+
Promise.all(keptDirPaths.map(walkDir)),
|
|
799
|
+
])
|
|
800
|
+
|
|
801
|
+
for (const s of junkSizes) removedBlocks += s
|
|
802
|
+
|
|
803
|
+
// Subdirs that became empty after pruning their contents
|
|
804
|
+
const emptyDirs = keptDirPaths.filter((_, i) => !walkResults[i])
|
|
805
|
+
if (emptyDirs.length > 0) {
|
|
806
|
+
await Promise.all(emptyDirs.map(d => fs.rmdir(d)))
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
return keptFiles + keptDirPaths.length - emptyDirs.length > 0
|
|
810
|
+
}
|
|
811
|
+
|
|
812
|
+
await walkDir(rootDir)
|
|
813
|
+
return { removed, removedBlocks }
|
|
814
|
+
}
|
|
815
|
+
|
|
646
816
|
/**
|
|
647
817
|
* @typedef {Args & { path: string }} ArgsWithRequiredPath
|
|
648
818
|
*/
|
|
@@ -655,36 +825,30 @@ export async function prune(opts) {
|
|
|
655
825
|
const startTime = Date.now()
|
|
656
826
|
log.info('Pruning:', opts.path)
|
|
657
827
|
|
|
658
|
-
|
|
828
|
+
// Fire early so du runs concurrently with the walk
|
|
829
|
+
const sizePromise = opts.noSize ? undefined : getSize(opts.path)
|
|
659
830
|
const excludedGlobs = new Set(opts.exclude)
|
|
660
831
|
const activeGlobs = [...defaultGlobs, ...opts.include].filter(
|
|
661
832
|
glob => !excludedGlobs.has(glob)
|
|
662
833
|
)
|
|
663
834
|
const compiledGlobs = compileGlobs(activeGlobs)
|
|
664
835
|
|
|
665
|
-
|
|
666
|
-
|
|
667
|
-
recursive: true,
|
|
668
|
-
withFileTypes: true,
|
|
669
|
-
})
|
|
670
|
-
|
|
671
|
-
const junkFiles = findJunkFiles(allFiles, compiledGlobs)
|
|
672
|
-
const results = compactPaths(junkFiles)
|
|
673
|
-
|
|
836
|
+
/** @type {WalkResult} */
|
|
837
|
+
let result
|
|
674
838
|
try {
|
|
675
|
-
await
|
|
839
|
+
result = await walkAndPrune(opts.path, compiledGlobs, !opts.noSize)
|
|
676
840
|
} catch (err) {
|
|
677
841
|
throw bail(undefined, err)
|
|
678
842
|
}
|
|
679
843
|
|
|
680
844
|
printDiff({
|
|
681
|
-
itemCount:
|
|
682
|
-
|
|
683
|
-
originalSize,
|
|
845
|
+
itemCount: result.removed.length,
|
|
846
|
+
removedBytes: opts.noSize ? undefined : result.removedBlocks,
|
|
847
|
+
originalSize: sizePromise ? await sizePromise : undefined,
|
|
684
848
|
startTime,
|
|
685
849
|
})
|
|
686
850
|
|
|
687
|
-
return
|
|
851
|
+
return result.removed
|
|
688
852
|
}
|
|
689
853
|
|
|
690
854
|
const entry = process.argv[1]
|
|
@@ -694,13 +858,15 @@ const runAsScript =
|
|
|
694
858
|
if (runAsScript) {
|
|
695
859
|
const args = handleArgs()
|
|
696
860
|
|
|
861
|
+
quiet = args.quiet
|
|
862
|
+
|
|
697
863
|
if (args.help) {
|
|
698
864
|
usage()
|
|
699
865
|
process.exit(0)
|
|
700
866
|
}
|
|
701
867
|
|
|
702
868
|
if (args.globs) {
|
|
703
|
-
|
|
869
|
+
log.log(JSON.stringify(defaultGlobs, null, 2))
|
|
704
870
|
process.exit(0)
|
|
705
871
|
}
|
|
706
872
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "prod-files",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "Keep only prod files by pruning non-prod files from node_modules before deploying",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"clean",
|
|
@@ -40,10 +40,8 @@
|
|
|
40
40
|
"pf": "node ./index.mjs",
|
|
41
41
|
"pub": "(npm whoami || npm login) && pnpm publish --access=public --tag=latest",
|
|
42
42
|
"test": "node --test",
|
|
43
|
-
"test:
|
|
44
|
-
"test:
|
|
45
|
-
"test:
|
|
46
|
-
"test:size": "du -sh ./test-project/node_modules/.pnpm | sort -h",
|
|
47
|
-
"test:watch": "node --test --watch"
|
|
43
|
+
"test:e2e": "cd test-project && bash prepare_test.sh && time node ../index.mjs node_modules/.pnpm",
|
|
44
|
+
"test:e2e:nuke": "trash ./test-project/node_modules ./test-project/pnpm-lock.yaml && pnpm store prune",
|
|
45
|
+
"test:e2e:weight": "du -sh ./test-project/node_modules/.pnpm | sort -h"
|
|
48
46
|
}
|
|
49
47
|
}
|