WHY are these changes introduced?
Fixes https://github.com/Shopify/shopify-cli-planning/issues/406
We want to provide CLI and plugin developers a set of components that can be used to improve the UI of what they output to the terminal. These components should be easy to use and also easy to create.
WHAT is this pull request doing?
- Introduce a new set of components that CLI and plugin developers can use to improve theirs UIs. To do so we've introduced
ink
as a rendering engine that allows us to build components with the expressiveness and power of React.
- Reimplement the current
dev
output with ink
and introduce one line of space among the various process outputs to keep things more readable, especially considering color accessibility. The output on the right hand side is now also colored like the left hand side.
- Add a new
shopify kitchen-sink
hidden command that can be used to showcase all the available UI components.
Summay of private (for now) components introduced as part of cli-kit
:
Banner
Banner
can have four different types (info
, warning
, error
, success
) and takes headline
and body
as params.
Maximum width is set to 60
. If the terminal is narrower than that, the banner will take the whole width.
These are some example outputs:
ConcurrentOutput
ConcurrentOutput
renders output from concurrent processes to the terminal.
Output will be divided in a two column layout, with the left column containing the process prefix and the right column containing the output.
Every process will be rendered with a different color, up to 4 colors.
Example with dev
:
FullScreen
FullScreen
renders all output in a new buffer and makes it full screen. This is useful when:
- You want to preserve terminal history.
ink
normally clears the terminal history if the rendered output is taller than the terminal window. By rendering in a separate buffer history will be preserved and will be visible after pressing Ctrl+C
.
- You want to respond to the resize event of the terminal. Whenever the user resizes their terminal window the output's height and width will be recalculated and re-rendered properly.
TextAnimation
TextAnimation
applies animations from chalk-animation to Text
children
List
List
displays an unordered or ordered list with text aligned with the bullet point and wrapped to the container width.
The type definition for a list item is:
type Token = string | CommandToken | LinkToken
export type ListItem = Token | Token[]
This means that developers can pass an array of items that can be composed by different tokens, which will be rendered by their corresponding component and separated by a space.
Link
Link
displays a clickable link when supported by the terminal.
Command
Command
displays a command as non-dimmed text.
Summary of public APIs:
renderConcurrent
Renders output from concurrent processes to the terminal with ConcurrentOutput
.
This function instantiates an AbortController
so that the various processes can subscribe to the same abort signal.
renderInfo
, renderSuccess
, renderWarning
, renderError
These are convenience methods that render a Banner
component with the corresponding type.
renderFatalError
This can be used to render an error of type Fatal
.
I'm going to work on replacing fatal errors with this new API in a follow up PR.
Testing
I've added tests for all the public methods. In order to test everything except renderConcurrent
you can use the usual mockOutput
we've been using for all the output
tests.
To test renderConcurrent
and commands that use similar more interactive experiences in the future, I've added a new run
helper function which accepts the name of a fixture file to run. It will then spawn a child process with execa
and return the output of stdout
. I've done this for a few reasons:
- Because of https://github.com/vadimdemedes/ink/pull/266 we need to make sure that
CI
is set to false
just for tests that call ink's render
function. This is because ink
behaves differently in CI
environments by writing only the non static output to stdout on unmount
, and the ConcurrentOutput
component uses only Static
lines.
- With this setup we'll also be able to add more integration level tests of components that react on user input. So if we have a future component that waits for a key to be pressed we can test it by using
run
and sending signals to it.
- Testing of thrown errors and their output becomes really simple as we can simply throw in the fixture as we would in the real environment.
How to test your changes?
- Run
yarn --cwd fixtures/app shopify app dev
to see the new concurrent output
- Run
yarn shopify kitchen-sink
to see all the new banner outputs. Feel free to play with the data in the kitchen-sink.ts
file and see how it would get displayed.
Measuring impact
How do we know this change was effective? Please choose one:
- [x] n/a - this doesn't need measurement, e.g. a linting rule or a bug-fix
- [ ] Existing analytics will cater for this addition
- [ ] PR includes analytics changes to measure impact
Checklist
- [x] I've considered possible cross-platform impacts (Mac, Linux, Windows)
- [x] I've considered possible documentation changes