Skip to content

Commit 539130a

Browse files
authored
feat(cli): use --prefer-local option to link external `node_modules (google#1117)
* chore: bump to v8.4.0 * feat(cli): use `--prefer-local` option to link external `node_modules` closes google#1116 * chore: minor code imprs
1 parent 778fd03 commit 539130a

File tree

5 files changed

+57
-14
lines changed

5 files changed

+57
-14
lines changed

.size-limit.json

+2-2
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
{
1010
"name": "zx/index",
1111
"path": "build/*.{js,cjs}",
12-
"limit": "812 kB",
12+
"limit": "812.1 kB",
1313
"brotli": false,
1414
"gzip": false
1515
},
@@ -30,7 +30,7 @@
3030
{
3131
"name": "all",
3232
"path": "build/*",
33-
"limit": "850.3 kB",
33+
"limit": "851 kB",
3434
"brotli": false,
3535
"gzip": false
3636
}

docs/cli.md

+2-2
Original file line numberDiff line numberDiff line change
@@ -106,10 +106,10 @@ zx --shell=/bin/another/sh script.mjs
106106

107107
## `--prefer-local, -l`
108108

109-
Prefer locally installed packages bins.
109+
Prefer locally installed packages and binaries.
110110

111111
```bash
112-
zx --shell=/bin/bash script.mjs
112+
zx --prefer-local=/external/node_modules/or/nm-root script.mjs
113113
```
114114

115115
## `--prefix & --postfix`

man/zx.1

+1-1
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ prefix all commands
2020
.SS --postfix=<command>
2121
postfix all commands
2222
.SS --prefer-local, -l
23-
prefer locally installed packages bins
23+
prefer locally installed packages and binaries
2424
.SS --eval=<js>, -e
2525
evaluate script
2626
.SS --ext=<.mjs>

src/cli.ts

+28-9
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ export function printUsage() {
6363
--shell=<path> custom shell binary
6464
--prefix=<command> prefix all commands
6565
--postfix=<command> postfix all commands
66-
--prefer-local, -l prefer locally installed packages bins
66+
--prefer-local, -l prefer locally installed packages and binaries
6767
--cwd=<path> set current directory
6868
--eval=<js>, -e evaluate script
6969
--ext=<.mjs> script extension
@@ -81,8 +81,10 @@ export function printUsage() {
8181

8282
// prettier-ignore
8383
export const argv: minimist.ParsedArgs = parseArgv(process.argv.slice(2), {
84+
default: { ['prefer-local']: false },
85+
// exclude 'prefer-local' to let minimist infer the type
8486
string: ['shell', 'prefix', 'postfix', 'eval', 'cwd', 'ext', 'registry', 'env'],
85-
boolean: ['version', 'help', 'quiet', 'verbose', 'install', 'repl', 'experimental', 'prefer-local'],
87+
boolean: ['version', 'help', 'quiet', 'verbose', 'install', 'repl', 'experimental'],
8688
alias: { e: 'eval', i: 'install', v: 'version', h: 'help', l: 'prefer-local', 'env-file': 'env' },
8789
stopEarly: true,
8890
parseBoolean: true,
@@ -126,19 +128,22 @@ async function runScript(
126128
scriptPath: string,
127129
tempPath: string
128130
): Promise<void> {
129-
const rmTemp = () => fs.rmSync(tempPath, { force: true })
131+
let nm = ''
132+
const rmTemp = () => {
133+
fs.rmSync(tempPath, { force: true, recursive: true })
134+
nm && fs.rmSync(nm, { force: true, recursive: true })
135+
}
130136
try {
131137
if (tempPath) {
132138
scriptPath = tempPath
133139
await fs.writeFile(tempPath, script)
134140
}
135-
141+
const cwd = path.dirname(scriptPath)
142+
if (typeof argv.preferLocal === 'string') {
143+
nm = linkNodeModules(cwd, argv.preferLocal)
144+
}
136145
if (argv.install) {
137-
await installDeps(
138-
parseDeps(script),
139-
path.dirname(scriptPath),
140-
argv.registry
141-
)
146+
await installDeps(parseDeps(script), cwd, argv.registry)
142147
}
143148

144149
injectGlobalRequire(scriptPath)
@@ -151,6 +156,20 @@ async function runScript(
151156
}
152157
}
153158

159+
function linkNodeModules(cwd: string, external: string): string {
160+
const nm = 'node_modules'
161+
const alias = path.resolve(cwd, nm)
162+
const target =
163+
path.basename(external) === nm
164+
? path.resolve(external)
165+
: path.resolve(external, nm)
166+
167+
if (fs.existsSync(alias) || !fs.existsSync(target)) return ''
168+
169+
fs.symlinkSync(target, alias, 'junction')
170+
return target
171+
}
172+
154173
async function readScript() {
155174
const [firstArg] = argv._
156175
let script = ''

test/cli.test.js

+24
Original file line numberDiff line numberDiff line change
@@ -186,6 +186,30 @@ describe('cli', () => {
186186
}
187187
})
188188

189+
test('supports --prefer-local to load modules', async () => {
190+
const cwd = tmpdir()
191+
const external = tmpdir()
192+
await fs.outputJson(path.join(external, 'node_modules/a/package.json'), {
193+
name: 'a',
194+
version: '1.0.0',
195+
type: 'module',
196+
exports: './index.js',
197+
})
198+
await fs.outputFile(
199+
path.join(external, 'node_modules/a/index.js'),
200+
`
201+
export const a = 'AAA'
202+
`
203+
)
204+
const script = `
205+
import {a} from 'a'
206+
console.log(a);
207+
`
208+
const out =
209+
await $`node build/cli.js --cwd=${cwd} --prefer-local=${external} --test <<< ${script}`
210+
assert.equal(out.stdout, 'AAA\n')
211+
})
212+
189213
test('scripts from https 200', async () => {
190214
const resp = await fs.readFile(path.resolve('test/fixtures/echo.http'))
191215
const port = await getPort()

0 commit comments

Comments
 (0)