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

A global CLI for running a single component #645

Closed
gaearon opened this issue Sep 14, 2016 · 24 comments
Closed

A global CLI for running a single component #645

gaearon opened this issue Sep 14, 2016 · 24 comments

Comments

@gaearon
Copy link
Contributor

gaearon commented Sep 14, 2016

This is something @lacker was working on before Create React App. That project got shelved but I think we could revive it in some form now.

The idea is that instead of creating a project, you just start with a single file that is the root component:

App.js

import React from 'react';

export default function App() {
  return <h1>Hello</h1>;
}
run-react-component App.js

It would use the same infrastructure as Create React App (exact same Babel and Webpack settings and CLI output), but would work in any folder without npm start.

So you could run-react-component NavBar.js and see just that component, regardless of where it is in the project, and whether it is in a project or not. The only run-react-component requirement is that whatever you import (e.g. react) exists in node_modules.

Benefits of this approach:

  • Can jump right into prototyping with a single file. (Generate even less code? #642)
  • The install cost is only paid once, you can run run-react-component right away in any folder on the disk. (The downside is you actually have to update global CLI to get updates.)
  • We could offer a way to “convert” such a prototype into a full CRA-based project, and they will be compatible.
  • You could even use that in a CRA-based project to work on a single component at a time.

What do you think? Would that be useful?

@tugberkugurlu
Copy link

tugberkugurlu commented Sep 14, 2016

@gaearon I liked that. I guess it wouldn't work for the case where a component looks at a URL and figues something based on that, correct? Or, maybe it would be possible to pass the location prop through the CLI as well?

@dperetti
Copy link

dperetti commented Sep 14, 2016

What about the props passed to the component ? Where would they be defined ? I think that's what would make the tool worth to use or not. Ideally a UI to tweak the props in realtime :-)
The styling of the component is also important. Usually I import a .less file but sometimes it just overrides styles defined at the top of the project. Without the right style, the component isn't displayed correctly and is unusable.
How would that work with this tool ?

@threepointone
Copy link

@tugberkugurlu you could have a defaultProp in place of a url that's passed in?
@dperetti defaultProps should get you most of the way there, you could also read a NODE_ENV/command line value for specific stuff. Further, you should really consider writing styles isolated to the component; depending on the cascade of classnames etc wouldn't make the component standalone in any case. That said, it's usually not as bad you'd imagine!

@amsdamsgram
Copy link

Good idea! Besides all the benefits @gaearon said, it could also be very useful to beginners in react. They could go right into creating a new component and understand quickly how react works.

Would it work with component that have children components too? Do children have to be in the same folder as the root component?

import React from 'react';

import ChildrenComponent from 'components/childrenComponent'

export default function App() {
  return (
      <div>
          <h1>Hello</h1>
          <ChildrenComponent />
      </div>
  )
}

@gaearon
Copy link
Contributor Author

gaearon commented Sep 14, 2016

Child components and CSS would be importable relatively, just like they are in Create React App.

@dcamilleri
Copy link

Great initiative !
Agreed with @dperetti. As this CLI will be useful for beginners/prototyping, the way props are handled is really important. Reactive UI is a good idea, to actually see the component change realtime. We can also imagine directly passing props from the CLI like:

run-react-component App.js --prop1=foo --prop2=bar

@andreypopp
Copy link
Contributor

Not sure why there's need to specify props as CLI when you can do this in JS! Simpler and doesn't require restarting when props change.

@dperetti
Copy link

@gaearon then isn't your component starting to look like a standalone app ?

@insin
Copy link
Contributor

insin commented Sep 14, 2016

@dperetti It's not too much extra work to support exporting a React element once you have functionality for supporting exported components in place.

@andreypopp contributed this exact functionality to react-heatpack and it worked nicely.

@andreypopp
Copy link
Contributor

andreypopp commented Sep 14, 2016

@insin with functional components this is probably not needed anymore:

export default () => <MyComponent prop1={42} />

@amsdamsgram
Copy link

@andreypopp @insin That would mean having a webpack dev server running? Or is it possible without? It's a little big heavy to "just" prototype a single component no?

@gaearon
Copy link
Contributor Author

gaearon commented Sep 14, 2016

You can specify props with defaultProps on the component itself, or with a wrapping component.

For example you can create Button.example.js that just renders <Button /> with a few different colors and prop combinations. Then use run-react-component Button.example.js to quickly serve just that page and quickly iterate on it. You could even run it side by side with your main development server.

@gaearon
Copy link
Contributor Author

gaearon commented Sep 14, 2016

Not sure what you mean by "heavy". Yes it would run the same development server as CRA itself under the hood.

@andreypopp
Copy link
Contributor

Do we really need another project for that? Maybe it is better to rename CRA to react-cli and make it host both CRA functionality and proposed run-react-component?

  • react create-app
  • react run-component

@amsdamsgram
Copy link

amsdamsgram commented Sep 14, 2016

@gaearon Got it. I didn't understand it was CRA under the hood the first time you answered me, my bad :)

@andreypopp renaming CRA is not a good idea to me since it is pretty recent. That would confuse people :/

@gre
Copy link

gre commented Sep 14, 2016

I'm not a big fan of forcing that defaultProps must implement all props. It changes a bit the semantic of defaultProps to me. Some components (most of them actually) have props that can't be defined trivially. Any component that takes a model data. Or things like Relay component (but this is another topic, could imagine having run-react-relay-component :D)

Maybe another way would be to have a convention like you have to define a Comp.mock.js next to Comp.js in the case Comp is not renderable with no props? e.g. that Comp.mock.js:
export default () => <Comp {...someProps} />.


Pushing initial idea a bit, I think if you can render a component standalone like this, another nice property is you could also jest-snapshot-test it automatically! We could have the jest snapshot feature for free, config-less, without ever have written a single line of test.

@arunoda
Copy link
Contributor

arunoda commented Sep 14, 2016

I think this is really tool where it helps to onboard a lot of new users to React.
Also this will be a good tool for when developing your components.

I think this is a smaller version of React Storybook

@deanrad
Copy link

deanrad commented Sep 14, 2016

By 'run a component' - do you mean - invoke its render method once, and print what's returned?
If printing, does it look like reactElements or JSX ? I think I need some sample output to picture it.

@jdlehman
Copy link

This is a great idea! I had something similar in a project I was working on, but it was implemented as a separate webpack build that rendered the desired component into a full screen container (we were aiming to create a fully responsive experience). I found that this was great not just for isolating components, but it was actually really helpful for styling shared components because it helped enforce keeping layout/positioning styles where they belonged. Doing this with a CLI is a much nicer experience.

As @arunoda mentioned, this seems similar in nature to React Storybook and its ClojureScript predecessor, devcards, so it would probably be good to examine libraries like these to see the current state of the art and gain insight they may have learned along the way.

The most interesting problem I see right now is determining how to pass props (or even context) to a component. Off the top of my head we could have some JSON defined in a run-react-component config, or a convention like a JSON file that is a sibling to the component file (eg. App.props.json). This structure could also allow named keys that define different collections of props. Something like the following:

{
  default: {
    prop1: value,
    prop2: value
  },
  loading: { ... },
  withMaxCount: { ... }
}

Then run-react-component App.js would use the default key by default and could specify a different collection of props being passed down with run-react-component App.js --withMaxCount or run-react-component App.js --loading

@vjeux
Copy link
Contributor

vjeux commented Sep 14, 2016

cc @frantic

@frantic
Copy link

frantic commented Sep 16, 2016

I had a prototype of this for React Native: depending on the file extension (.ios.js / .android.js) or --platform flag it could run either iOS or Android simulator.

@gaearon
Copy link
Contributor Author

gaearon commented Sep 17, 2016

Maybe it is better to rename CRA to react-cli and make it host both CRA functionality and proposed run-react-component?

The confusing part here is people will start trying to do react start and react build and we’ll have to explain npm scripts. They’ll also expect code generation and unfavorably compare CRA to Ember/Angular CLIs because they provide it. We don’t want to give false impressions about project’s scope.

@lacker
Copy link
Contributor

lacker commented Sep 24, 2016

I think the best way to handle props with this would be just making a small new file and running that. With this sort of script it should be easy to have multiple entry points in a huge project. So if you really want to see <MyComponent foo=7 /> in the browser, you could make a new file that just contained

import React from 'React';
import MyComponent from 'wherever';
export default () => <MyComponent foo=7 />

and react-run that. If you're working on a single component in a large codebase this seems like it could be handy. Props on the command line could be useful too, although escaping might get annoying.

Also, if we can really strip down the requirements to a single JavaScript file, there might be some interesting possibilities of finding a subset of features that works in multiple development environments. The initial use case I was thinking about for this whole thing was teaching people React through websites similarly to what we are doing on the React Native website. If you could teach people via something like codepen, where you build an app with just a single file, and the same exact thing is runnable locally, that seems like a nice way to learn. If the codepen app layout is different from the layout of a real application, it's somewhat frustrating to learn it one way and then port your knowledge over.

React Native is an interesting case too - if we could make the tooling very similar between React and React Native init for noobs, it could be easier to learn one and port your knowledge to the other.

@gaearon
Copy link
Contributor Author

gaearon commented Sep 30, 2016

I think documenting Storybook integration might address this better than us building a dedicated tool. Closing in favor of #738.

@gaearon gaearon closed this as completed Sep 30, 2016
@lock lock bot locked and limited conversation to collaborators Jan 22, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests