Run happo via a node script?
silouanwright opened this issue · 8 comments
I'm trying to run happo via a node script, and I'm running into a lot of issues.
// scripts/happoScript.js
const executable = '<repo path>/node_modules/happo.io/build/cli.js'
const happo = spawn(
executable,
happoArgs,
{
stdio: 'inherit',
}
)
If I spawn this off, there's a couple of issues. Firstly, there will be a bunch of un-exited processes after the build has completed, if you grep for them (ps -ef | grep happo
).
The 2nd problem: The script will return a signal before it should. So in my cmd line, the script executes, completes and kicks you back to the command line, and then randomly outputs. It's also confusing as if you mash on ctrl + c, it won't do anything, as you're not actually inside a process.
Let me know if any of this makes any sense at all. Thanks.
Hi @reywright!
Can you describe the use-case behind running happo this way? I'm just trying to understand things better. Also, do you happen to have any error logs?
From a quick look, I think you could get things working by setting the cwd
option for spawn
. I just tried this locally, and it worked for one of my projects:
// ~/happoScript.js
const { spawn } = require("child_process");
const path = require("path");
const executable = "node_modules/happo.io/build/cli.js";
const happo = spawn(executable, ["run", "--only", "Button"], {
stdio: "inherit",
cwd: path.resolve(process.cwd(), "happo-project")
});
where happo-project
is a folder in my home directory (~
) where a happo project is located.
Also, while this is most likely not an issue (I don't plan on changing where that cli.js
file is located), it's probably better to use the binary instead:
const executable = "node_modules/.bin/happo";
Yeah absolutely, and thank you so much for the response. So I'll break this up into 2 comments, one describing the intention, and then later on I'll try out some of your suggestions, and see if those work (and if they don't, I'll try to create a working example).
So the the use case: at our company, we have a lot of different repo's, (or packages inside a mono repo) that share similar configuration. We're giving happo a trial period, and so in 2 separate packages, I had to install the same dependencies for happo itself, and 2 separate .happo config files (exactly the same). Now the trick with most dev dependencies in npm world, is they usually culminate in an entry into the scripts field in the package.json, pointing to some sort of cli. So all of the config, packages, etc for happo, all just culminate in something like
scripts: {
happo: happo dev
}
And the problem, is if we decide to update the configuration in one file, we have to make PR's for 8 different repo's, alter the dependencies in those, etc.
So the idea here is this: what if we could enforce the configuration to be standardized. So the idea, is you create a npm package that exposes a bin script, that has a bunch of cli commands. Whenever we have a new package or repo that we want to use happo on, we merely need to yarn add this package, and then do the following:
scripts: {
happo: cool-package happo
}
And then you don't need to pollute that package with all of the specific dev dependencies for happo, and you get the configuration for free.
This actually isn't a new concept though. kcd-scripts, react-scripts, ember-cli-, vue-cli, etc all have this similar concept. You can read through some resources here: https://github.com/reyronald/awesome-toolkits
But yeah this is nice as now we don't need to attempt to copy and paste stuff, as we evolve our happo configuration and such. You can also make this flexible by doing stuff like checking for the existence of a .happo.js
file inside the repo that's using these commands, and then use that if it's available, and if not, using the default .happo.js file.
We as a company have a lot of different projects, and not enough people to figure out how to configure stuff, and keep it updated, so providing pre-made configurations for consistency sake is actually pretty important for us.
And here's a direct example in kcd-scripts, just so you don't have to look around too much for something similar: https://github.com/kentcdodds/kcd-scripts/blob/master/src/scripts/lint.js
So here he has a linting script (eslint), and this allows him to fire off a command to run this, and keep the configuration consolidated.
It’s worth noting that this concept, including in the examples you mentioned, has lots of caveats and often breaks in surprising ways. Having a bunch of PRs and writing a tool to manage those might be easier than this approach.
@ljharb if you have time, could you list a few of those caveats? It doesn't have to be super specific, I'm guessing this is based on seeing issues over a long period of time in your own org? The ones I can think of is webpack config, css-loading, resolving paths relatively to the local package, etc.
@reywright if I remember @flarnie right (we chatted a few days back) you are using Storybook, right? Things might be a little simpler in that case, because I think you can always run happo from the root, but specify a configDir
for the happo-plugin-storybook
pointing to the local package. The .happo.js
(located in the root of the repo) config can then look something like
module.exports = {
// ... other config
plugins: [happoPluginStorybook({ configDir: path.join(process.env.HAPPO_PROJECT_DIR, '.storybook') }),
};
With this config, you can invoke happo with something like
HAPPO_PROJECT_DIR="project-a" npm run happo run
This is just an idea though -- let me know if that makes sense or if you need me to expand/explain things!
This user has run into a few :-) cwd confusion, process signals/traps, but also dependency issues; what happens if someone depends on one of the tools (eslint, happo, Babel, etc) directly and they conflict, IDE integration which fully supports eslint as a top level dep but may not necessarily if eslint happens not to be hoisted to the top level; also customization in general, react-scripts forces many CRA users to eject to do even basic enhancements to their linting or transpiling configs.
The OP suggests there’s issues with the happo binary a) not relaying signals properly and b) leaving behind running processes and c) outputting to stdio after the main process has already finished, all of which would be legit bugs - the use case is such, however, that even absent those issues, it might not be trivially achievable.
@ljharb very interesting, and thanks for the feedback.
I honestly just don't see a reality of a tool that can go out to these different repo's and projects and make these PR's you're referring, not only from a functionality perspective, but actually getting approval from the respective engineers on those projects, and then get merged in. Some of the PR's would eventually get stale as well, and subsequent PR's would potentially depend on the previous PR's. I just don't see this being possible.
I think the reality for us, is we'd like to do a lot more standardization across projects, so a lot of the pain points you mention are valid but are tradeoffs we'd potentially be willing to incur... unless it's absolutely not recommended, and I've seen a lot of different teams flourish with the approach.
I think it's harder for react-scripts, as they need to support a much wider audience and the enhancements they may want. For us, we have a much smaller surface area, we actually want to constrict the customization, and we can always evolve our own scripts for our needs. I do think this will be more work than what is trivial already, but the current setup we're running is untenable long term. When you say IDE integration, I'm assuming you're meaning of editors looking for a top level config file in the working project directory... that's a good point... I wonder if some script to symlink them to your working directory would suffice?
Is this something you've tried with your own teams (or know teams that have implemented it) and didn't have good results with it? I've just seen nothing but success stories (even with the pain points).
I’ve seen many issues with the public projects you mention - standard, react-scripts, etc - and we’ve run into similar issues trying to write a robust tool.
Making a bot account that can merge PRs without engineer approval, even, is totally doable.
I'm closing this due to lack of activity. Feel free to reopen if it still needs to be addressed!