Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(turborepo): Rationalize the install and execution process. #5695

Merged
merged 5 commits into from
Aug 10, 2023

Conversation

nathanhammond
Copy link
Contributor

@nathanhammond nathanhammond commented Aug 9, 2023

Previously we had a lot of complexity in our install scripts inherited from esbuild. This change removes all of the incidental complexity in favor of relying upon default ecosystem behaviors in most cases.

Instead of attempting correction of configuration at both installation and invocation, it handles everything at invocation. Early returns ensure that we perform the exact same amount of work as we did in the previous variation.

It can now also detect and provide instructions on how to repair a broken package-lock.json caused by npm/cli#4828. (Note: if the "just try installing" saving throw works, we won't provide this information to the user. I elected this ordering for startup time reasons.)

As an added bonus, turbo no longer has a postinstall script which is more end-user-friendly.

Material changes:

  • Does not attempt to extract turbo from a Yarn PnP without preferUnplugged support. This works with all stable releases of yarn (berry). This is a change for users on canary versions >2.0.0-rc.0 && <=2.0.0-rc.30 from September 2019 – March 2020—but we already don't support in other portions of our codebase so this only changes where the error is thrown from.
  • In the event of npm install download failure it does not attempt to directly download a tarball. If a user misconfigured their setup and we didn't succeed at npm install to bail them out? It's okay for you to get an error with lots of details on how to fix your configuration.

@vercel
Copy link

vercel bot commented Aug 9, 2023

The latest updates on your projects. Learn more about Vercel for Git ↗︎

Name Status Preview Comments Updated (UTC)
examples-designsystem-docs 🔄 Building (Inspect) Visit Preview 💬 Add feedback Aug 10, 2023 5:16am
examples-kitchensink-blog 🔄 Building (Inspect) Visit Preview 💬 Add feedback Aug 10, 2023 5:16am
examples-vite-web 🔄 Building (Inspect) Visit Preview 💬 Add feedback Aug 10, 2023 5:16am
8 Ignored Deployments
Name Status Preview Comments Updated (UTC)
examples-basic-web ⬜️ Ignored (Inspect) Visit Preview Aug 10, 2023 5:16am
examples-cra-web ⬜️ Ignored (Inspect) Visit Preview Aug 10, 2023 5:16am
examples-gatsby-web ⬜️ Ignored (Inspect) Visit Preview Aug 10, 2023 5:16am
examples-native-web ⬜️ Ignored (Inspect) Visit Preview Aug 10, 2023 5:16am
examples-nonmonorepo ⬜️ Ignored (Inspect) Visit Preview Aug 10, 2023 5:16am
examples-svelte-web ⬜️ Ignored (Inspect) Visit Preview Aug 10, 2023 5:16am
examples-tailwind-web ⬜️ Ignored (Inspect) Visit Preview Aug 10, 2023 5:16am
turbo-site ⬜️ Ignored (Inspect) Visit Preview Aug 10, 2023 5:16am

@vercel
Copy link

vercel bot commented Aug 9, 2023

@nathanhammond is attempting to deploy a commit to the Vercel Team on Vercel.

A member of the Team first needs to authorize it.

Copy link
Contributor Author

@nathanhammond nathanhammond left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Reviewer's Guide!

Comment on lines +12 to +16
// If we do not find the correct platform binary, should we attempt to install it?
const SHOULD_INSTALL = true;

// If we do not find the correct platform binary, should we trust calling an emulated variant?
const SHOULD_ATTEMPT_EMULATED = true;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I left these in as configuration variables; but we can actually hardcode the decisions here.

Comment on lines +28 to +31
child_process.execSync(
`npm install --loglevel=error --prefer-offline --no-audit --progress=false`,
{ cwd: turboPath, stdio: "pipe", env }
);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Previously this had to carefully track which package and version, clean up after itself, and more.

Now we just rely on npm to do the right thing when looking at the package.json for turbo, clean up in the event of failure, etc.

// This provides logging messages as it progresses towards calculating the binary path.
function getBinaryPath() {
// First we see if the user has configured a particular binary path.
const TURBO_BINARY_PATH = process.env.TURBO_BINARY_PATH;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We still need to allow the user to specify a particular binary path.

const correctBinary = availablePlatforms.includes(platform) && availableArchs.includes(resolvedArch) ? `turbo-${platform}-${resolvedArch}/bin/turbo${ext}` : null;
if (correctBinary !== null) {
try {
return require.resolve(`${correctBinary}`);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

By rule we should be able to require.resolve() the platform-specific package from within the turbo directory, so we do that. (1:1 with the existing behavior.)

Comment on lines +83 to +85
installUsingNPM();
const resolvedPath = require.resolve(`${correctBinary}`);
console.warn('Installation has succeeded.');
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't succeed unless we can resolve it, so this gets split across lines.

packages/turbo/bin/turbo Outdated Show resolved Hide resolved
packages/turbo/bin/turbo Show resolved Hide resolved

console.error();
console.error('To resolve this issue for your repository, run:');
console.error(`npm install turbo${version} --package-lock-only${environment} && npm install`);
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@chris-olszewski This is the magic command that fixes things without rm -rf.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😮

break;
} catch (e) {}

let next = path.join(current, '..', '..', 'package-lock.json');
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No-dependencies find-up.

@@ -9,15 +9,12 @@
"main": "./bin/turbo",
"scripts": {
"postversion": "node bump-version.js",
"postinstall": "node install.js"
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉

Copy link
Contributor

@gsoltis gsoltis left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a couple of notes on errors / warnings, otherwise LGTM.

Are there any concerns about running this when the repo is using package managers besides npm?

packages/turbo/bin/turbo Outdated Show resolved Hide resolved
packages/turbo/bin/turbo Show resolved Hide resolved
Copy link
Member

@chris-olszewski chris-olszewski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is so much more straight forward!

I think we can get away with not building out this level of support for package-lock.json version 1. The last version of npm that used this version by default was 6 and node 16 (EOL 9/11) was the last one to ship with npm 6.

packages/turbo/bin/turbo Outdated Show resolved Hide resolved
packages/turbo/bin/turbo Show resolved Hide resolved

console.error();
console.error('To resolve this issue for your repository, run:');
console.error(`npm install turbo${version} --package-lock-only${environment} && npm install`);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😮

@gsoltis
Copy link
Contributor

gsoltis commented Aug 10, 2023 via email

@nathanhammond
Copy link
Contributor Author

Are there any concerns about running this when the repo is using package managers besides npm? - @gsoltis

Nope! There are two things happening here that do npm-related nonsense:

  1. An npm install inside of the <PROJECT>/node_modules/turbo folder.

Writing to this destination (no matter how it is implemented underneath the hood with linking) results in safe behavior—even if it pollutes the cache, even if that cache is later restored from a random cache, even if that cache comes from a different platform, even if the base project is a different package manager. It works because it leverages npm install to handle the behavior, which on rerun always puts things into the expected state for the dependencies, and the resolve algorithm.

The material difference is that, in a misconfigured repository, if we restore from a polluted cache, on the same platform (worst-case scenario), the correct binary will be found inside the node_modules/turbo/node_modules/turbo-<platform>-<arch> folder instead of node_modules/turbo-<platform>-arch. This is a harmless distinction since those two things should be identical in order to work anyway.

  1. Looking for package-lock.json.

This does not directly invoke or mutate npm, it just looks on the file system for evidence of the package-lock.json error and gives you a command to fix it. Even failing the command generation just gives you a slightly more-permissive turbo version.

@nathanhammond nathanhammond added the pr: automerge Kodiak will merge these automatically after checks pass label Aug 10, 2023
@kodiakhq kodiakhq bot merged commit ad313e6 into vercel:main Aug 10, 2023
34 checks passed
@nathanhammond nathanhammond deleted the no-postinstall branch August 10, 2023 05:53
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pr: automerge Kodiak will merge these automatically after checks pass
Projects
None yet
3 participants