Skip to content

feat: publish netlify package #7293

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

Merged
merged 21 commits into from
May 19, 2025
Merged

Conversation

eduardoboucas
Copy link
Member

Summary

Adds a script that publishes the same code as a second package (netlify). We have different options to make this happen, like making netlify-cli a dependency of netlify. But to minimise the changes to netlify-cli (which doesn't even have a main field at the moment), I went for a script that is meant to be run in the CI and patches package.json with the new name and main before publishing it.

@eduardoboucas eduardoboucas requested a review from a team as a code owner May 14, 2025 10:22
Copy link

github-actions bot commented May 14, 2025

📊 Benchmark results

Comparing with 298a379

  • Dependency count: 1,148 (no change)
  • Package size: 271 MB (no change)
  • Number of ts-expect-error directives: 397 (no change)

const newPackageJSON = {
...packageJSON.contents,
main: './dist/index.js',
name: 'netlify',
Copy link
Member Author

Choose a reason for hiding this comment

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

Now I'm wondering if we should also change the name of the binary so that npx netlify and any globally-installed netlify-cli do not collide?

Copy link
Member

Choose a reason for hiding this comment

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

As far as I understand the wonky npm heuristics here:

  • if a user has both netlify and netlify-cli installed (both locally or both globally), npx netlify will run netlify
  • if a user has netlify-cli and does not have netlify, npx netlify will always run netlify-cli rather than try to install netlify
  • if a user has neither installed, npx netlify will install and run netlify

(It's likely worth verifying these)

Does this seem ok or are any of these scenarios problematic?

Copy link
Member Author

Choose a reason for hiding this comment

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

My question is whether npx netlify will also install the binary into the PATH, in the same way that globally-installing a package does. If that's the case, then the netlify binary will overwrite the binary with the same name that had been injected by a globally-installed netlify-cli, which is not intended.

But if npx netlify simply runs the binary without adding it to the PATH (which I feel is the expected behaviour), this should be fine.

Copy link
Member

Choose a reason for hiding this comment

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

nit: I was going to comment that this codebase does not follow this naming convention, but I see that scripts/prepublishOnly is the one exception, which you probably saw right next to this one!

🤷🏼

Copy link
Contributor

Choose a reason for hiding this comment

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

I did name scripts/prepublishOnly as it is (despite not matching other file naming conventions) specifically so it would match up exactly with the npm script name.


async function getPackageJSON() {
const packageJSONPath = resolve(fileURLToPath(import.meta.url), '../../package.json')
const contents = JSON.parse(await readFile(packageJSONPath, 'utf8'))
Copy link
Member

Choose a reason for hiding this comment

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

nit: We already have a dep on normalize-package-data you can use here to avoid contents being any

There's even a util src/utils/get-cli-package-json.ts you should be able to use

Copy link
Member Author

Choose a reason for hiding this comment

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

This use case is a bit different. We're reading package.json and then writing it back, so I don't think we should be normalising it.

I have used the Package type now.

@@ -0,0 +1,4 @@
// This is an entrypoint that mirrors the interface that the `netlify` package
Copy link
Member

Choose a reason for hiding this comment

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

thought: Should we log a warning here that the package has been renamed?

Copy link
Member Author

Choose a reason for hiding this comment

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

That feels a bit extreme? We might be logging something that is not actionable to the user, since this might be a transitive dependency.

Comment on lines 36 to 39
console.log('Re-installing dependencies to update lockfile...')
await execa('npm', ['install'], {
cwd: dirname(packageJSON.path),
})
Copy link
Member

Choose a reason for hiding this comment

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

Hrm, his is getting difficult to reason about... So, before this script runs in CI, we'll have run this as part of the netlify-ci publish step: https://github.com/netlify/cli/blob/47242ce76c7aa57978e14e9e075ca6f0f76af348/scripts/prepublishOnly.js.

This means we'll have mutated package.json to prune dev deps, converted the package-lock.json to an npm-shrinkwrap.json, then restored the original package.json... now here we'll mutate package.json again to update name and add main, then run npm i again, which will restore the dev deps into the npm-shrinkwrap.json, making netlify twice as big to install as netlify-cli. 😰 Did I get all that right?

@ndhoule and I just recently decomplicated all of this (with many false starts due to how tangled and brittle it was), so I think it would be worth avoiding getting back into this state if we can help it. I don't have concrete suggestions that fit in a comment box, but I'm happy to pair on it if you'd like.

Copy link
Member Author

Choose a reason for hiding this comment

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

Okay, I hadn't realised that this flow had changed. My bad.

In 70dacdb I have made the following changes:

  1. Changed prepublishOnly.js to stop trying to restore the original state of package.json. This flow is meant to run in the CI only, where trying to restore things has no benefit and will only slow things down.
  2. Changed netlifyPackage.js to run npm shrinkwrap (instead of npm install) so that the shrinkwrap file is updated with the right package name. It will have the same dependencies, as we've preserved the package.json file modified in step 1.

Let me know if that makes sense.

const newPackageJSON = {
...packageJSON.contents,
main: './dist/index.js',
name: 'netlify',
Copy link
Member

Choose a reason for hiding this comment

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

As far as I understand the wonky npm heuristics here:

  • if a user has both netlify and netlify-cli installed (both locally or both globally), npx netlify will run netlify
  • if a user has netlify-cli and does not have netlify, npx netlify will always run netlify-cli rather than try to install netlify
  • if a user has neither installed, npx netlify will install and run netlify

(It's likely worth verifying these)

Does this seem ok or are any of these scenarios problematic?

@eduardoboucas eduardoboucas merged commit bda3784 into main May 19, 2025
52 checks passed
@eduardoboucas eduardoboucas deleted the feat/publish-netlify-package branch May 19, 2025 13:48
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants