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

[Tooling] yarn splash (beta) #2113

Merged
merged 40 commits into from
Sep 13, 2019
Merged

[Tooling] yarn splash (beta) #2113

merged 40 commits into from
Sep 13, 2019

Conversation

kaelig
Copy link
Contributor

@kaelig kaelig commented Sep 10, 2019

Screenshots

First iteration

Screen Shot 2019-09-09 at 11 33 26 PM

Second iteration (with real data)

Screen Shot 2019-09-10 at 11 02 27 PM

Third iteration (loading state, empty state)

No changes detected

Screen Shot 2019-09-11 at 11 27 12 PM

Loading

Screen Shot 2019-09-11 at 11 26 53 PM

Changes detected

Screen Shot 2019-09-11 at 11 26 59 PM

scripts/observer/index.tsx Outdated Show resolved Hide resolved
scripts/observer/index.tsx Outdated Show resolved Hide resolved
treebuilder.ts Outdated Show resolved Hide resolved
treebuilder.ts Outdated Show resolved Hide resolved
@kaelig kaelig changed the title [WIP][Tooling] First iteration of the observer CLI [Tooling] yarn splash (beta) Sep 12, 2019
@kaelig kaelig marked this pull request as ready for review September 12, 2019 17:57
package.json Show resolved Hide resolved
scripts/splash/index.tsx Outdated Show resolved Hide resolved
Copy link
Contributor

@amrocha amrocha left a comment

Choose a reason for hiding this comment

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

Lots of comments, mostly questions

scripts/splash/index.tsx Show resolved Hide resolved

const formatDependencies = (dependencies) =>
dependencies
.filter(({fileName}) => excludedFileNames(fileName))
Copy link
Contributor

Choose a reason for hiding this comment

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

Do you think we should filter here too?

I think, for example, if you made a change to Avatar/index.ts, or to a utils.ts file, I would still expect the tool to tell me accurately what the impact is

Copy link
Contributor Author

Choose a reason for hiding this comment

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

You're right. Let me put those index and utils back in. If feedback says this is too overwhelming we can always filter them out again.

scripts/splash/index.tsx Outdated Show resolved Hide resolved

const excludedFileNames = (fileName) =>
!fileName.includes('test') &&
!fileName.includes('types') &&
Copy link
Contributor

Choose a reason for hiding this comment

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

I think we'll want to include types in the future, when we have per-export granularity. Right now I'm of two minds about it, maybe we should include types and maybe we shouldn't. I'll leave it up to you

Copy link
Contributor Author

Choose a reason for hiding this comment

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

IMHO type changes are really well handled via VSCode, so I'm not sure we'd be adding value by having this in the tool.

import {argv} from 'yargs';
import {getGitStagedFiles, getDependencies} from './treebuilder';

const excludedFileNames = (fileName) =>
Copy link
Contributor

Choose a reason for hiding this comment

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

I think these checks are a bit too lose. For example, .includes('test') will also filter file names that just happen to include those characters, even if it's not a test. I think it'd be good to be a bit more specific here for all checks

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah I agree. As we make it more codebase-agnostic, this won't scale.

const staged = (await getGitStagedFiles('src/')) as string[];
setStagedFiles(staged);

if (staged.length === 0) {
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not sure I understand this, can you explain why you have this check?

Copy link
Contributor Author

@kaelig kaelig Sep 12, 2019

Choose a reason for hiding this comment

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

If there are no staged files, then we don't need to run a compilation task and we can stop updating the UI.

Setting the data status to 'loaded' is a way to do that.

Copy link
Contributor

Choose a reason for hiding this comment

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

Logically this is a bit confusing, since this function is just supposed to get the staged files.

Can you move this to a useEffect hook that executes on stagedFiles changing?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That's exactly what's happening: this is executed in two useEffect hooks hence why it's in its own function.

Copy link
Contributor

Choose a reason for hiding this comment

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

Right, I think it's fine to keep the getStagedFiles function separate. But it doesn't make sense to set state in this function, that's why I think you should move the state handling part to the hooks themselves

Copy link
Contributor Author

Choose a reason for hiding this comment

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

move the state handling part to the hooks themselves

I tried that, but then it ended up "watching" in both useEffects, instead of the first one only running once and then exiting :/

getStagedFiles();
}
});
// ^ no dependencies = keeps watching
Copy link
Contributor

Choose a reason for hiding this comment

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

Why not just use this one?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

It doesn't exit correctly (promises keep firing). I kind of stumbled upon this by accident and thought it'd be a good way to have an alpha for the watcher until we have a better solution.

Copy link
Contributor

Choose a reason for hiding this comment

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

So does this just constantly execute in the background?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah, not sure how, though!

Copy link
Contributor

Choose a reason for hiding this comment

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

Hmm, my guess is that it's just re-running constantly. In that case can you run a quick perf check? If it's not a big impact then it's fine, but I want to avoid a situation where we're shipping something that slows down people's computers for no discernible reason

Copy link
Contributor Author

Choose a reason for hiding this comment

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

As discussed: this is not good for performance, but not crippling.

Since it's behind a command argument and we tell people this is an alpha, let's :shipit: and improve it later.


useEffect(() => {
if (stagedFiles.length > 0) {
const dependencies = getDependencies(
Copy link
Contributor

Choose a reason for hiding this comment

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

I'm not too happy with the API here, what do you think? Any suggestions for how to improve it?

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 also think we can improve it. Since we'll gain insights as you explore how to make this work for GitHub, webpack, and storybook… I'd like to wait to revamp it when you know more about all these other use cases.

const App = () => {
const [stagedFiles, setStagedFiles] = useState([]);
const [data, setData] = useState([]);
const [dataStatus, setDataStatus] = useState('loading');
Copy link
Contributor

Choose a reason for hiding this comment

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

I think it makes more sense to make this a loading boolean prop

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right now it's loading/loaded, but there can be other loading states, such as 'error' or 'cancelled' that I'd like to leave this open for.

Copy link
Member

@BPScott BPScott Sep 12, 2019

Choose a reason for hiding this comment

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

In that case can we have the vale be an enum rather than an arbitary string. There's an example of that in #2067

enum Status {
  Pending = 'PENDING',
  Loaded = 'LOADED',
  Errored = 'ERRORED',
}

Then in your useState:

 const [status, setStatus] = useState<Status>(Status.Pending);

stagedFiles,
);
setData(formatDependencies(dependencies));
setDataStatus('loaded');
Copy link
Contributor

Choose a reason for hiding this comment

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

You never set this prop to loading. Wouldn't you want to do that when a re-render is triggered, and you're re-running the script and the git status function?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Not sure what you mean by that, but let's talk about it during our next pairing session

Copy link
Member

@BPScott BPScott left a comment

Choose a reason for hiding this comment

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

I've not got much skin in this game and this is a first pass so whatevs.

Code in the treebuilder looks good. It's pretty dense so I'm not going to pretend to understand it but does the job. It looks like we might run into issues if we have circular dependencies, I'd be nice to work out how to stop that, but it doesn't need to block getting this merged.

I've got some concerns with the display rendering:

  • Currently it truncates content if if text is thinner than your terminal and we're all been around the web long enough to know truncation is not a content strategy. You can see this in action if you go see the results of editing src/components/ResourceList/components/FilterControl/components/DateSelector/Da teSelector.tsx
  • The output does fancy writing into placeholder area things, I don't know how that redrawing of the terminal will work if you want to output info this as part of the storybook webpack build, but my gut fears this may be too clever.

It'd also be really nice to be able to specify a filepath / glob to check on the command line so I don't have to go edit a particular file to see its splashzone. Checking changed items can be done with a flag:

yarn run splash src/components/Button/Button.tsx shows you button's splashzone, while yarn run splash --modified (or some other arg) will show you the output of changed items

),
}));

const Component = ({pathname, filename, dependencies}) => (
Copy link
Member

Choose a reason for hiding this comment

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

Please define these components (and really all top-level functions) using the function Component() style syntax. Using Arrow functions means that the components will all have no name to use for debugging which will be a pain when you get stack trace staying there was an error in Unknown component which was inside Unknown component.

const [dataStatus, setDataStatus] = useState('loading');

const getStagedFiles = async () => {
const staged = (await getGitStagedFiles('src/')) as string[];
Copy link
Member

Choose a reason for hiding this comment

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

Can we fix this by setting the return type of getGitStagedFiles to be Promise<string[]> in treebuilder instead of having to redefine it here

}
}

return Object.keys(dependencies)
Copy link
Member

Choose a reason for hiding this comment

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

This feels like an opinion on output formatting, should this filtering of index files be the responsibility of the rendering logic in splash/index?

compile(codebase, {
noEmitOnError: true,
noImplicitAny: true,
target: ts.ScriptTarget.ES5,
Copy link
Member

Choose a reason for hiding this comment

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

Do these output config bits need to be configured if we're ingesting the code but not outputting anything from TS?

This reverts commit 7eeba2a.
Copy link
Contributor

@amrocha amrocha left a comment

Choose a reason for hiding this comment

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

There's a few things to improve, but we'll do that as we go. We tried doing it before merging but ran into some weird behaviour and we want to get this out asap, so let's merge and improve

@kaelig kaelig merged commit c4037e0 into master Sep 13, 2019
@kaelig kaelig deleted the ink-cli branch September 13, 2019 14:51
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.

3 participants