-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
Rewrite frontend in React #1273
Conversation
const Category = ({ category, examples, baseUri, isProductionBuild, onClick }) => ( | ||
<div> | ||
<h3 id={category.id}>{ category.name }</h3> | ||
<table className='badge'><tbody> |
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.
Do the ESLint rules not enforce a consistent attribute quotation style? Line 23 uses "
but this line uses '
. We should use "
" everywhere for JSX attributes.
Also, one tag per line please :)
<table className="badge">
<tbody>
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.
Looks pretty good. I've left some comments inline.
This makes light use of Next.js,
Any particular advantages of Next.js over create-react-app? Does Next.js have any runtime cost/overhead, or is it purely a dev tool?
baseUri: PropTypes.string.isRequired, | ||
isProductionBuild: PropTypes.bool.isRequired, | ||
onClick: PropTypes.func.isRequired, | ||
}; |
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.
I feel like we should avoid propTypes (which only does runtime type checking and can't easily be statically analyzed) and instead use Flow. Flow lets us check the typing statically, and supports React very well.
url += '&suffix=' + escapeField(this.suffixInput.value); | ||
url += '&query=' + this.queryInput.value; | ||
url += '&uri=' + escapeField(this.uriInput.value); | ||
return url; |
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.
What about using an object of key-value pairs for this? Something like:
buildURI({
colorB: this.state.colorInput,
prefix: this.state.prefixInput,
// ...
})
</datalist> | ||
<input | ||
className="short" | ||
ref={input => { this.labelInput = input; }} |
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.
This is not really the "React way" of doing things. React components should rarely directly touch the raw DOM elements. Instead of doing this, you should use controlled components (https://reactjs.org/docs/forms.html)
For example:
<input
className="short"
value={this.state.label}
onChange={evt => this.setState({label: evt.target.value})
/>
frontend/components/markup-modal.js
Outdated
export default class MarkupModal extends React.Component { | ||
constructor (props) { | ||
super(props); | ||
this.state = { |
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.
You can use class properties to set this, rather than doing it in the constructor:
export default class MarkupModal extends React.Component {
state = {
// ...
};
}
Note: This requires the appropriate Babel preset to be enabled (it should be)
frontend/components/markup-modal.js
Outdated
|
||
return ( | ||
<Modal | ||
isOpen={this.state.isOpen} |
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.
isOpen={this.props.example !== null}
would avoid the need to have isOpen
in state
.
Setting state
based on props
is often an anti-pattern, when the value could just be derived from the props directly.
frontend/components/usage.js
Outdated
<h2 id="styles">Styles</h2> | ||
|
||
<p> | ||
The following styles are available (flat is the default as of Feb 1st 2015): |
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.
Remove "as of Feb 1st 2015", not really needed any more.
frontend/components/usage.js
Outdated
</tr> | ||
<tr> | ||
<td><img src={baseUri + "/badge/style-social-green.svg?style=social"} alt="" /></td> | ||
<td><code>https://img.shields.io/badge/style-social-green.svg?style=social</code></td> |
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.
There's a lot of repetition here. Consider iterating over an array, roughly like:
const styles = [
'plastic',
'flat',
'flat-square',
......
];
<table className="badge-img"><tbody>
{styles.map(style => (
<tr>
<td><img src={baseUri + '/badge/style-' + style + '-green.svg?style=' + style} alt="" /></td>
<td><code>https://img.shields.io/badge/style-{style}-green.svg?style={style}</code></td>
</tr>
))}
</tbody></table>
frontend/components/usage.js
Outdated
<td><code>https://img.shields.io/badge/style-flat--square-green.svg?style=flat-square</code></td> | ||
</tr> | ||
<tr> | ||
<td><img src={baseUri + "/badge/style-for--the--badge-green.svg?style=for-the-badge"} alt="" /></td> |
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.
Use single quotes for strings (`baseUri + '/badge/......)
frontend/components/usage.js
Outdated
<tr><td><code>?logoWidth=40</code></td> | ||
<td>Set the horizontal space to give to the logo</td></tr> | ||
<tr><td><code>?link=http://left&link=http://right</code></td> | ||
<td>Specify what clicking on the left/right of a badge should do (esp. for |
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.
Indentation here is a bit weird.
pages/index.js
Outdated
isProductionBuild={isProductionBuild} /> | ||
<a | ||
href="https://gratipay.com/Shields/" | ||
style={{ textDecoration: 'none', color: 'rgba(0,0,0,0.1)' }}> |
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.
Use CSS file for this? CSS files are better for perf. If you do want to switch to using "CSS in JS", consider using a library like Glamor.
Thanks for the review! Will address + respond to these soon. |
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.
Have addressed most of these. What's left is the CSS, which I'm going to refactor now, and a few items I want to defer which I listed in the top post.
- Support single-server testing and a local dev server (like Next) that is on a different port from the shields server - Refactor config schema With this change, the suggestions work locally in #1273.
# Conflicts: # package-lock.json
Here's what I've been able to discern:
It does have a runtime library. |
I am not thrilled about the size of the built website. I'd be fine with something like 100k. This is clocking in around 400k. I did some profiling and it seems like this is substantially attributable to Next.js overhead, which is difficult to justify in a site this small. Otherwise I think we'd be between 50 and 100k. @Daniel15 mentioned CRA and Gatsby which are good suggestions. Let's experiment with those and address in a follow-up. |
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.
This looks good to me!
This is clocking in around 400k.
Wow, that's pretty big for a site that's essentially one page. The shields site likely doesn't need many of the features Next provides. create-react-app is probably a good fit, or just manually configure Webpack (which shouldn't be too difficult given the relative simplicity of the site).
.travis.yml
Outdated
@@ -17,7 +17,7 @@ before_script: | |||
script: | |||
- npm run lint | |||
- npm run test:js | |||
- npm run build:production | |||
- if [ "$TRAVIS_NODE_VERSION" == "6" ]; then echo "Skipping build on Node 6."; else make website; fi |
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.
Instead of blacklisting Node 6, what about whitelisting just the one Node version you want to perform the site build on?
Even better, this could be switched to CircleCI and you could use a separate build job for the site, with whichever Node.js version you like.
I guess this is just a temporary transition state though, right?
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 seems safer to blacklist Node 6, because if we upgrade beyond Node 8 this would just stop running. Since I added check-node-version
I could replace this with a semver expression, which expresses the intent even better.
Yea, it's just temporary until we get Node 8 on the server.
And tell us, we might be able to bring it to you anyway! | ||
</p> | ||
<p> | ||
<object |
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.
Why <object>
rather than <img>
?
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 makes embedded links work! Probably that belongs in a Shields FAQ somewhere…
Let’s open new issues for bugs, and track follow-ups here: https://github.com/badges/shields/projects/1 |
Great job @paulmelnikow it's nice to see the effort ! Keep up the great work ! |
Using fix from mapbox/react-click-to-select#15. From #1273
I rewrote the frontend in React. It's matched feature-for-feature with the current frontend, with only slight changes in the styling. I did not fuss about making the styling identical; the badge popup looks particularly different.
This makes the front end much easier to develop. I'm really looking forward to implementing #701, to which this paves the way.
This makes light use of Next.js, which I'm using for the first time. I like it. It provides webpack config and dev and build tooling, which worked very well and saved a lot of fussing. I also like the way it handles routing, though we're only using one route right now.
Todo:
previewUri
BASE_URI
in dev / productionnpm start
npm postinstall
?Deferred:
frontend/
(resolve module not found issues)