-
-
Notifications
You must be signed in to change notification settings - Fork 348
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
Draft: Eject #1798
base: main
Are you sure you want to change the base?
Draft: Eject #1798
Conversation
Neat idea. Does it work?
If it works then, yes, that'd be great! |
Does it work for all package managers? E.g. Yarn, pnpm, Deno, and Bun. In general, do we foresee any potential issue? One drawback of this approach is that it doesn't eject the TypeScript source code. Maybe we can go for of a dual approach: some packages (e.g. Vike extensions) have first-class support for eject (e.g. ejecting TypeScript) while other packages fallback to using this |
I''l check on that.
Yes you are right. How about a flag |
👍 We can try that and see how it goes. (We'll probably stumble upon some issues but we may be able to work around all of them.) |
@brillout I added a new commit and I will need some feedback here on how to proceed. So as I understand now, the goal is basically to eject only dependencies from https://github.com/brillout/vike-apollo-react. I adjusted the coding a little bit and for now it would only work with this repo (which I think is a downside). The current command ejects the dependency into the ejected folder: The questions I have:
|
vike/node/cli/commands/scaffold.ts
Outdated
import { resolve } from 'path' | ||
import { Readable } from 'stream' | ||
import { finished } from 'stream/promises' | ||
// const response = await fetch(NPM_REGISTRY_BASE_URL + dependency) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
First thought of doing a more generic approach. However, this would let me rely on some source to get the information where to find the source files. So I went ahead and restricted it for now to only work with the mono-repo. I think we could maybe add some logic based on what repo?
vike/node/cli/bin.ts
Outdated
import { prerender } from './commands/prerender.js' | ||
import { eject } from './commands/eject.js' | ||
import { scaffold } from './commands/scaffold.js' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It felt odd to have everything in bin.ts
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In principle, I agree, but let's discuss this kind of things later. This will actually heavily conflict with what I'm currently working on (the Vike CLI fully replacing Vite's CLI) so I'm inclined to think it's best we revert this refactor.
We can store extra needed info under the // package.json
"vike-eject": {
"exports": {
"./something" : "./src/something.ts"
},
"repo": "https://github.com/vikejs/vike-react/tree/main/packages/vike-react-query"
}
User runs import { execSync } from 'child_process'
function detectPackageManager() {
// Check npm_config_user_agent first
const agent = process.env.npm_config_user_agent
if (agent) {
const [program] = agent.toLowerCase().split('/')
if (program === 'yarn') return 'yarn'
if (program === 'pnpm') return 'pnpm'
if (program === 'npm') return 'npm'
if (program === 'bun') return 'bun'
}
// Check npm_execpath for yarn
if (process.env.npm_execpath && process.env.npm_execpath.endsWith('yarn.js')) {
return 'yarn'
}
// Check npm_command for npm
if (process.env.npm_command) {
return 'npm'
}
// Check _ environment variable as a last resort
const parent = process.env._
if (parent) {
if (parent.endsWith('pnpx') || parent.endsWith('pnpm')) return 'pnpm'
if (parent.endsWith('yarn')) return 'yarn'
if (parent.endsWith('npm')) return 'npm'
if (parent.endsWith('bun')) return 'bun'
}
// If all else fails, assume npm
return 'npm'
}
const packageManager = detectPackageManager()
execSync(`${packageManager} install`) |
@nitedani thanks for the input
// would be stored close to the cli. Then we can maintain official extensions and they respective download paths
const extensions = {
"vike-react-apollo: "download_path"
} I like the idea of having a vike key inside the extension's // inside extension package.json
"vike": {
"cli": {
"eject": {
"exports": {}, // the new src exports so the file:./link works
"remove": {}, // files or folder which should be removed
"customScaffoldScript": "path_to_some_script which runs after the ejection",
// should maybe only work for trusted extensions, we might want to include trust level in the top list, WDYT?
"integratePaths": {
"pathInExtension": "pathInScaffoldedProject" // maybe for files which should directly be copied to renderer
},
"installDependencies": true
}
}
} |
You can use require.resolve or import.meta.resolve to get the path. import { createRequire } from 'node:module';
import { join } from 'node:path';
const require_ = createRequire(import.meta.url);
const packagePath = require_.resolve('vike-react-query');
const packageJsonPath = join(packagePath, 'package.json');
The dependencies always need to be installed, the package wouldn't work without that. For installation of dependencies I think you can just run the install command in process.cwd after patching the users package.json (also patch other already installed dependent extensions package.json) But how to find the dependent packages? For example In monorepo usually there is a single instance of an installed package, and its symlinked to multiple apps, so to avoid the wrong packages being loaded, we would need to eject all dependents to the local app/ejected directory. So if we eject
Or we can make this behavior explicit by ejecting to the monorepo root/ejected directory.
I wouldn't add these for now, let's see if it's really needed and we can add it later if it is. |
I guess, I wanted to get rid of the constraint that the user would need to install the package first. But I guess you are right, the constraint seems logical and makes developing much easier.
Yeah, I was just not sure if we want to run the install command. I would prefer to simply set everything up and then tell the user to run the install command. Then they would have some time to review the made changes. But Either way works for me.
I honestly don't think that this will be an issue. However, I know for
Honestly, this depends on what we are trying to achieve here. Looking at the original discussion, the need sounded to me more like scaffolding some
I guess, this is what I would have done anyway 🤔 So basically I would expect that the commands runs at the location where the package.json is which we want to update. Within the same dir I would create the ejected folder. If the person now runs this at root level package.json I would eject the dependency for all apps within the monorepo and update the main package.json |
I've given this a little bit more thoughts. How about the following? We have different levels of support:
I don't know what the differences between level 2 and 3 would be, and maybe we will end up with only level 1 and 2. Couple of notes:
Couple of features we could implement in the future:
But let's focus on the basics first. We can improve things later in subsequent PRs. Apologies for the delayed answer, I was busy with a couple of things. @snake-py if you're still up for it, then let's try to merge something not-perfect-but-functional relatively quickly.
Let me know if you need more input. Looking forward to merge eject 😍 |
I managed to be the owner of https://www.npmjs.com/package/eject. Ideally, long term, we will be able to make our work Vike agnostic. |
@brillout sorry for not answering, just very busy at the moment. If you really think it makes sense to go forward with the current work. I can finalize a MR. However, I also would be willing to contribute in a different way in case it is more productive for the project. In case I can proceed with the current could you maybe give me a clear scope how far I should go? I am a little confused by what eject now should and should not do? |
How about we first try something relatively simple, for example:
In other words, we don't fetch the TypeScript source. I think you already got something working? Is there something missing? I suggest we first finish this relatively simple solution, then let's see what we want to do next. Maybe we can then try fetching the TypeScript source in a subsequent PR. Or maybe we'll see some other neat things we want to polish about eject. WDYT? To be clear: I think eject should eventually support all of these options:
But let's start with only supporting level 1. The reason I think it makes sense to simultaneously support all these levels is because npm packages will work only with a certain level. |
@brillout alright, yes I have the coding for the level-1 already ready. I updated the code to include only the level-1 support. How it works:
"eject": "vike eject"
Please let me know if this suitable for first level. |
Very neat 💯 Actually, how about we go ahead and define it as Let me know your npm handle and I'll make you co-owner of the
I think we can/should already do this, even for level 1 (for all levels really). It's quite a scary operation, so I'm inclined to think it's best we enforce the user to have a clean Git state.
WDYT of running it on behalf of the user, as shown here? In general, there are pros and cons about doing this, but I think for eject it's worth it. I'll further review the code tomorrow. |
Sure I am following your lead there. I think you are right and it makes sense to have it as a stand alon package since, it is not really directly vike related. My npm profile name is the same as my GitHub https://www.npmjs.com/~snake-py I can implement both changes to the eject package then. I need to have a look around first. Will try to do it this week. |
👍 $ npm owner add snake-py eject
npm notice INFO: User snake-py invited to package eject successfully.
+ snake-py (eject) You should have received an invitation email. |
Alright, I have not much experiences with public npm packages. I have some basic org question. I see that currently this eject is providing the source code to the npm package. Will we keep the bigeasy's repo, or do you think we want to reconnect to yours? Or should I create a new one? Either way can you maybe make me maintainer or should I fork and do the changes in a fork? |
I think it's easier for now if we make the |
@brillout I hope I understood you correctly. I updated the code:
I had trouble to get it to work with just using eject as command. It seems to collide with brew's eject command. I don't know why exactly, that is why I renamed it to ejectjs. How it works:
"eject": "ejectjs"
Pitfalls
|
@brillout I just noticed that my last comment was not completely correct. Probably because I copied over from a previous one. The install is done for the user automatically. I added some flags to bypass git check or skip the install. |
Ok 👍 I just tried it, and it generates this commit. I guess there is a bug? |
Couple of notes:
|
Alright, no objections from my side. All your comments are reasonable. Will work on this shortly.
Hmm, odd that you don't have the ejections folder 🤔 Maybe due to symlinks? I will look into it. I have not tested the thing in a monorepo set up. |
I started to work on the
eject
command. Since I don't knowvike-react-apollo
I took a more generic route. I am unsure if this maybe also solves the need. Basically the command copies everxthing form the dependency over into a createdejected
folder and then linkspackage.json
to that folder. If this fits the needs as well I would go ahead and finalize this. Maybe someone can give some feed back as well?Prior art: