Skip to content

Commit

Permalink
Delegate to local installs of wrangler when possible (#1270)
Browse files Browse the repository at this point in the history
Delegate to a local install of `wrangler` if one exists.

Users will frequently install `wrangler` globally to run commands like
`wrangler init`, but we also recommend pinning a specific version of
`wrangler` in a project's `package.json`. Now, when a user invokes a
global install of `wrangler`, we'll check to see if they also have a
local installation. If they do, we'll delegate to that version.

This requires that we define a `main` (maybe `module` would work too?)
field in `package.json` so that `require.resolve` can find `"wrangler"`,
but it's something of an implementation detail.
  • Loading branch information
Cass Fridkin authored Jun 21, 2022
1 parent 5698e81 commit 7ed5e1a
Show file tree
Hide file tree
Showing 2 changed files with 68 additions and 4 deletions.
7 changes: 7 additions & 0 deletions .changeset/lovely-toys-happen.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
---
"wrangler": patch
---

Delegate to a local install of `wrangler` if one exists.

Users will frequently install `wrangler` globally to run commands like `wrangler init`, but we also recommend pinning a specific version of `wrangler` in a project's `package.json`. Now, when a user invokes a global install of `wrangler`, we'll check to see if they also have a local installation. If they do, we'll delegate to that version.
65 changes: 61 additions & 4 deletions packages/wrangler/bin/wrangler.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,10 @@ const MIN_NODE_VERSION = "16.7.0";

let wranglerProcess;

async function main() {
/**
* Executes ../wrangler-dist/cli.js
*/
function runWrangler() {
if (semiver(process.versions.node, MIN_NODE_VERSION) < 0) {
// Note Volta and nvm are also recommended in the official docs:
// https://developers.cloudflare.com/workers/get-started/guide#2-install-the-workers-cli
Expand Down Expand Up @@ -46,7 +49,7 @@ Consider using a Node.js version manager such as https://volta.sh/ or https://gi
pathToCACerts = certPath;
}

wranglerProcess = spawn(
return spawn(
process.execPath,
[
...(semiver(process.versions.node, "18.0.0") >= 0
Expand All @@ -70,11 +73,65 @@ Consider using a Node.js version manager such as https://volta.sh/ or https://gi
);
}

/**
* Runs a locally-installed version of wrangler, delegating from this version.
* @throws {MODULE_NOT_FOUND} if there isn't a locally installed version of wrangler.
*/
function runDelegatedWrangler() {
const packageJsonPath = require.resolve("wrangler/package.json", {
paths: [process.cwd()],
});
const {
bin: { wrangler: binaryPath },
version,
} = JSON.parse(fs.readFileSync(packageJsonPath));
const resolvedBinaryPath = path.resolve(packageJsonPath, "..", binaryPath);

console.log(
`Delegating to locally-installed version of wrangler @ v${version}`
);
// this call to `spawn` is simpler because the delegated version will do all
// of the other work.
return spawn(
process.execPath,
[resolvedBinaryPath, ...process.argv.slice(2)],
{
stdio: "inherit",
}
).on("exit", (code) =>
process.exit(code === undefined || code === null ? 0 : code)
);
}

/**
* Indicates if this invocation of `wrangler` should delegate
* to a locally-installed version.
*/
function shouldDelegate() {
try {
// `require.resolve` will throw if it can't find
// a locally-installed version of `wrangler`
const delegatedPackageJson = require.resolve("wrangler/package.json", {
paths: [process.cwd()],
});
const thisPackageJson = path.resolve(__dirname, "..", "package.json");
// if it's the same path, then we're already a local install -- no need to delegate
return thisPackageJson !== delegatedPackageJson;
} catch (e) {
// there's no local version to delegate to -- `require.resolve` threw
return false;
}
}

async function main() {
wranglerProcess = shouldDelegate() ? runDelegatedWrangler() : runWrangler();
}

process.on("SIGINT", () => {
wranglerProcess.kill();
wranglerProcess?.kill();
});
process.on("SIGTERM", () => {
wranglerProcess.kill();
wranglerProcess?.kill();
});

void main();

0 comments on commit 7ed5e1a

Please sign in to comment.