Skip to content

Commit e2fa853

Browse files
committed
Avoid installing unused devDependencies at deploy time
1 parent d621a58 commit e2fa853

File tree

2 files changed

+68
-0
lines changed

2 files changed

+68
-0
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
"lint-fix": "npx eslint --fix --ext .js,.mjs ./",
1313
"postinstall": "rm -f .eslintcache && husky",
1414
"prepare": "husky",
15+
"prepare-deploy": "node scripts/prepare-deploy.mjs",
1516
"size": "size-limit",
1617
"test": "node --env-file=.env node_modules/@playwright/test/cli test",
1718
"test:absolute-links": "lychee src/index.html",

scripts/prepare-deploy.mjs

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
/**
2+
* @file Running this script before `npm ci` (e.g. in a deployment script) will
3+
* remove the `devDependencies` that are not needed in order to deploy. This
4+
* way, `npm ci` will install less files and won’t bloat your disk space.
5+
*
6+
* This is an all-or-nothing script: if a dependency has an invalid name or if
7+
* NPM fails at removing one of them, none will be removed. This is because
8+
* `npm pkg delete` is called once with all dependencies (fast). This is
9+
* way faster than calling it once per dependency.
10+
*/
11+
12+
import { execSync } from 'node:child_process'
13+
import console from 'node:console'
14+
15+
console.time('Cleaning of devDependencies list')
16+
17+
/** The list of `devDependencies` not needed to build the app. */
18+
const USELESS_DEPS = [
19+
'@axe-core/playwright',
20+
'@eslint/js',
21+
'@playwright/test',
22+
'@size-limit/preset-app',
23+
'axe-html-reporter',
24+
'eslint-formatter-codeframe',
25+
'eslint-plugin-playwright',
26+
'eslint',
27+
'globals',
28+
'size-limit',
29+
'typescript-eslint',
30+
'typescript',
31+
]
32+
33+
const depsArgs = USELESS_DEPS
34+
/**
35+
* Exclude invalid names, which reduces the risk of failure since we try
36+
* to remove all deps in one command: they’ll all be deleted or fail.
37+
*/
38+
.filter(hasValidName)
39+
40+
// Wrap dep names with single quotes, which is needed for `@scope/name` deps.
41+
.map(dep => `'${dep}'`)
42+
43+
// Create a space-separated list of `devDepencies.'(@scope/)name'`.
44+
.join(` devDependencies.`)
45+
46+
try {
47+
execSync(`npm pkg delete devDependencies.${depsArgs}`, {
48+
stdio: 'inherit',
49+
timeout: 5000,
50+
})
51+
} catch (error) {
52+
console.warn(`Slicing of devDepencencies failed: ${error.message}`);
53+
}
54+
55+
console.timeEnd('Cleaning of devDependencies list');
56+
57+
/** Utils */
58+
59+
function hasValidName (name) {
60+
const isValid = /^[a-zA-Z0-9@/_.-]+$/.test(name)
61+
62+
if (!isValid) {
63+
console.warn(`Invalid dependency name: ${name} will stay.`)
64+
}
65+
66+
return isValid
67+
}

0 commit comments

Comments
 (0)