7 | {paragraphTheme.maxWidth && paragraphTheme.maxWidth.map((maxWidth, m) => (
8 |
9 |
{fontSize}px + {maxWidth}
10 |
19 | Short Text Example
20 |
21 |
30 | Medium length text example where it's a few lines of wrapping
31 | text but not a full paragraph.
32 |
33 |
42 | Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
43 |
44 |
45 | ))}
46 |
47 | ))}
48 |
49 | ))}
50 |
--------------------------------------------------------------------------------
/examples/src/registerServiceWorker.js:
--------------------------------------------------------------------------------
1 | // In production, we register a service worker to serve assets from local cache.
2 |
3 | // This lets the app load faster on subsequent visits in production, and gives
4 | // it offline capabilities. However, it also means that developers (and users)
5 | // will only see deployed updates on the "N+1" visit to a page, since previously
6 | // cached resources are updated in the background.
7 |
8 | // To learn more about the benefits of this model, read https://goo.gl/KwvDNy.
9 | // This link also includes instructions on opting out of this behavior.
10 |
11 | const isLocalhost = Boolean(
12 | window.location.hostname === 'localhost' ||
13 | // [::1] is the IPv6 localhost address.
14 | window.location.hostname === '[::1]' ||
15 | // 127.0.0.1/8 is considered localhost for IPv4.
16 | window.location.hostname.match(
17 | /^127(?:\.(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$/
18 | )
19 | );
20 |
21 | export default function register() {
22 | if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
23 | // The URL constructor is available in all browsers that support SW.
24 | const publicUrl = new URL(process.env.PUBLIC_URL, window.location);
25 | if (publicUrl.origin !== window.location.origin) {
26 | // Our service worker won't work if PUBLIC_URL is on a different origin
27 | // from what our page is served on. This might happen if a CDN is used to
28 | // serve assets; see https://github.com/facebookincubator/create-react-app/issues/2374
29 | return;
30 | }
31 |
32 | window.addEventListener('load', () => {
33 | const swUrl = `${process.env.PUBLIC_URL}/service-worker.js`;
34 |
35 | if (!isLocalhost) {
36 | // Is not local host. Just register service worker
37 | registerValidSW(swUrl);
38 | } else {
39 | // This is running on localhost. Lets check if a service worker still exists or not.
40 | checkValidServiceWorker(swUrl);
41 | }
42 | });
43 | }
44 | }
45 |
46 | function registerValidSW(swUrl) {
47 | navigator.serviceWorker
48 | .register(swUrl)
49 | .then(registration => {
50 | registration.onupdatefound = () => {
51 | const installingWorker = registration.installing;
52 | installingWorker.onstatechange = () => {
53 | if (installingWorker.state === 'installed') {
54 | if (navigator.serviceWorker.controller) {
55 | // At this point, the old content will have been purged and
56 | // the fresh content will have been added to the cache.
57 | // It's the perfect time to display a "New content is
58 | // available; please refresh." message in your web app.
59 | console.log('New content is available; please refresh.');
60 | } else {
61 | // At this point, everything has been precached.
62 | // It's the perfect time to display a
63 | // "Content is cached for offline use." message.
64 | console.log('Content is cached for offline use.');
65 | }
66 | }
67 | };
68 | };
69 | })
70 | .catch(error => {
71 | console.error('Error during service worker registration:', error);
72 | });
73 | }
74 |
75 | function checkValidServiceWorker(swUrl) {
76 | // Check if the service worker can be found. If it can't reload the page.
77 | fetch(swUrl)
78 | .then(response => {
79 | // Ensure service worker exists, and that we really are getting a JS file.
80 | if (
81 | response.status === 404 ||
82 | response.headers.get('content-type').indexOf('javascript') === -1
83 | ) {
84 | // No service worker found. Probably a different app. Reload the page.
85 | navigator.serviceWorker.ready.then(registration => {
86 | registration.unregister().then(() => {
87 | window.location.reload();
88 | });
89 | });
90 | } else {
91 | // Service worker found. Proceed as normal.
92 | registerValidSW(swUrl);
93 | }
94 | })
95 | .catch(() => {
96 | console.log(
97 | 'No internet connection found. App is running in offline mode.'
98 | );
99 | });
100 | }
101 |
102 | export function unregister() {
103 | if ('serviceWorker' in navigator) {
104 | navigator.serviceWorker.ready.then(registration => {
105 | registration.unregister();
106 | });
107 | }
108 | }
109 |
--------------------------------------------------------------------------------
/examples/src/Buttons.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import logo from './logo.svg';
3 | import './App.css';
4 | import glamorous from 'glamorous'
5 | import theme from './theme'
6 | import buttonTheme from './buttonTheme'
7 |
8 | const Box = glamorous.button({
9 | display: 'inline-block',
10 | fontFamily: theme.fonts[0]
11 | })
12 |
13 | const Header = glamorous.div({
14 | borderBottom: '1px solid black',
15 | padding: '.5rem 1rem',
16 | display: 'flex',
17 | justifyContent: 'space-between',
18 | alignItems: 'center'
19 | })
20 |
21 | const Div = glamorous.div({})
22 |
23 | class App extends Component {
24 | render() {
25 | return (
26 |
387 | );
388 | }
389 | }
390 |
391 | export default App;
392 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | **
2 | This is a write up of work in progress talk I gave at the Web London meetup last year.
3 | **
4 |
5 | # Component Styling API
6 |
7 | I read a book one time called 'Refactoring your wetware'. There was an
8 | interesting part about thinking about a problem as if you were looking at it
9 | from 10 thousand feet up in the air.
10 |
11 | I was driving in Sunday morning traffic one time. I was on my way from San
12 | Francisco to a flea market. The GPS in my car told me there was an exit coming
13 | up I should take and that I should get into one of the two lanes on the right.
14 | About a dozen blinkers turned on at the exact same time and cars started to
15 | merge into the right two lanes. From 10k feet up i bet that looks pretty wild.
16 | You hear an automated voice. All cars put on their blinker at the same time to
17 | break off from the highway to head to the same destination.
18 |
19 |
20 | *Two completely different view points*
21 |
22 |
23 |
24 | I'm here to talk about Design systems, Css, Js and of course Css in Js.
25 | And what does that look like if we as a community try to think at 10,000 feet?
26 |
27 | When I say 10,000 feet I don't just mean think abstractly. I mean actually do
28 | it. You should visualize yourself being far above something. But what is the
29 | thing? One thing I meditate on is looking at a timeline of history from very
30 | far away. And if we look at a timeline of how humans have designed and built
31 | things throughout history...how do the problems and the process in which we
32 | solve them evolve? Particularly since we started styling digital ui with css?
33 |
34 | A guy I collaborate with that goes by the name John Otander [(@johno)](https://github.com/johno) is pretty
35 | good at thinking at 10,000 feet. He comes up with *wild* ideas. Last year he decided to
36 | download the css for top million websites, in 1 month intervals, dating back to
37 | 2005 (if available).
38 |
39 | My first thought was - that's pretty neat. We can show people their css graphed
40 | out over time.
41 |
42 |
43 |
44 |
45 |
46 |
47 | You can learn a bunch just by analyzing your own site. *But, what does it look
48 | like to see this at 10,000 feet?*
49 |
50 | [Ask Audience]
51 | What do you think you could learn by analyzing this data? What kind of tools could you build with it?
52 |
53 | Some possibilities that come to mind for me:
54 | - Can analyze values and look for trends
55 | - Find most common property value rules for given components with common class names
56 | - Identify pattern outliers
57 | - Find common mistakes and try to build automated tools to solve them
58 | - Could overlay other data: Browser usage, timeline of introduction of various technologies (frameworks, addiitons to the spec, etc.)
59 | - We can visualize the history of design systems. We can animate them and watch how they evolve over time!
60 | - Given an array of urls, you could visualize the intersection of common values
61 | for things like: type scale, colors, background colors, font-family. This can
62 | help show how consistently your brand is implmented across a number of
63 | different front-end code bases. Most companies have different code bases
64 | for: their marketing site, their blog, their app, docs, external status
65 | page, and potentially a number of other micro sites. Having a feedback
66 | loop of common values can be helpful when trying to standardize an
67 | existing palette, or creating a feedback loop moving forward to see if you
68 | are becoming more or less consistent.
69 |
70 | [Harley Turan](https://twitter.com/hturan), scraped a bunch of data and did exactly this. Here is a collection of color
71 | palettes pulled from multiple sites that belong to the same company visualized from 2009 through 2017.
72 |
73 |
74 |
75 | Now those are just a few half-baked ideas around what you can do to analyze static
76 | files. And I'd love to do nothing else then to sit and chat about what we can do with
77 | all of this data but that's a different story for a different time.
78 |
79 | Below is a list of css properties. I often think of css as the styling api for
80 | html. At first glance it's a lot of stuff. Especially if you're a beginner.
81 |
82 | But you can build a lot of pretty neat UI without worrying about a lot of these
83 | properties and how they work. When I am a beginner one of the most difficult
84 | things is figuring out what *to* worry about and what *not to*. I can confidently
85 | say, when styling a button, I've never needed to set caption-side. Or
86 | counter-increment, counter-reset, or volume for that matter. This doesn't mean you
87 | should never use them, but they aren't common properties attached to button
88 | styles.
89 |
90 | Can we use this pattern to potentially make front-end code more accessible for new people?
91 |
92 | Components could, essentially have all of the necessary visual styling properties
93 | exposed, where a designer can configure the values they want to pass in.
94 |
95 | Instead of a blank slate, they could discover common things to account for
96 | within different components. The pseudo state :focus would be a tough thing to
97 | intuitively account for if you've never worked on the web before. Offering it
98 | in configuration can at the very least, offer guidance around what to research.
99 |
100 |
101 | *List of Css properties*
102 | ```
103 | accelerator
104 | azimuth
105 | background
106 | background-attachment
107 | background-color
108 | background-image
109 | background-position
110 | background-position-x
111 | background-position-y
112 | background-repeat
113 | behavior
114 | border
115 | border-bottom
116 | border-bottom-color
117 | border-bottom-style
118 | border-bottom-width
119 | border-collapse
120 | border-color
121 | border-left
122 | border-left-color
123 | border-left-style
124 | border-left-width
125 | border-right
126 | border-right-color
127 | border-right-style
128 | border-right-width
129 | border-spacing
130 | border-style
131 | border-top
132 | border-top-color
133 | border-top-style
134 | border-top-width
135 | border-width
136 | bottom
137 | caption-side
138 | clear
139 | clip
140 | color
141 | content
142 | counter-increment
143 | counter-reset
144 | cue
145 | cue-after
146 | cue-before
147 | cursor
148 | direction
149 | display
150 | elevation
151 | empty-cells
152 | filter
153 | float
154 | font
155 | font-family
156 | font-size
157 | font-size-adjust
158 | font-stretch
159 | font-style
160 | font-variant
161 | font-weight
162 | height
163 | ime-mode
164 | include-source
165 | layer-background-color
166 | layer-background-image
167 | layout-flow
168 | layout-grid
169 | layout-grid-char
170 | layout-grid-char-spacing
171 | layout-grid-line
172 | layout-grid-mode
173 | layout-grid-type
174 | left
175 | letter-spacing
176 | line-break
177 | line-height
178 | list-style
179 | list-style-image
180 | list-style-position
181 | list-style-type
182 | margin
183 | margin-bottom
184 | margin-left
185 | margin-right
186 | margin-top
187 | marker-offset
188 | marks
189 | max-height
190 | max-width
191 | min-height
192 | min-width
193 | orphans
194 | outline
195 | outline-color
196 | outline-style
197 | outline-width
198 | overflow
199 | overflow-X
200 | overflow-Y
201 | padding
202 | padding-bottom
203 | padding-left
204 | padding-right
205 | padding-top
206 | page
207 | page-break-after
208 | page-break-before
209 | page-break-inside
210 | pause
211 | pause-after
212 | pause-before
213 | pitch
214 | pitch-range
215 | play-during
216 | position
217 | quotes
218 | -replace
219 | richness
220 | right
221 | ruby-align
222 | ruby-overhang
223 | ruby-position
224 | -set-link-source
225 | size
226 | speak
227 | speak-header
228 | speak-numeral
229 | speak-punctuation
230 | speech-rate
231 | stress
232 | scrollbar-arrow-color
233 | scrollbar-base-color
234 | scrollbar-dark-shadow-color
235 | scrollbar-face-color
236 | scrollbar-highlight-color
237 | scrollbar-shadow-color
238 | scrollbar-3d-light-color
239 | scrollbar-track-color
240 | table-layout
241 | text-align
242 | text-align-last
243 | text-decoration
244 | text-indent
245 | text-justify
246 | text-overflow
247 | text-shadow
248 | text-transform
249 | text-autospace
250 | text-kashida-space
251 | text-underline-position
252 | top
253 | unicode-bidi
254 | -use-link-source
255 | vertical-align
256 | visibility
257 | voice-family
258 | volume
259 | white-space
260 | widows
261 | width
262 | word-break
263 | word-spacing
264 | word-wrap
265 | writing-mode
266 | z-index
267 | zoom
268 | ```
269 |
270 | Some people [jxnblk](http://jxnblk.com) have told me that Component Styling API is a
271 | horrible name for this concept and he's likely correct. Regardless, I think the
272 | following descriptions, from a website called wikipedia, are interesting to
273 | consider.
274 |
275 | *API: Application programming interface*
276 |
277 | > "In general terms, it is a set of clearly defined methods of communication between various software components."
278 |
279 | > "By abstracting the underlying implementation and only exposing objects or actions the developer needs, an API simplifies programming."
280 |
281 | > "Thus, the design of an API attempts to provide only the tools a user would expect."
282 |
283 | [https://en.wikipedia.org/wiki/Application_programming_interface](https://en.wikipedia.org/wiki/Application_programming_interface)
284 |
285 | When I'm styling a button, I don't expect to use volume. Or page-break. Or a
286 | number of other properties. The goal though is not to eliminate options, it's
287 | to narrow focus on the essential, allowing for expansion and exploration if
288 | necessary. But this idea defining a component API has benefits extending beyond
289 | this.
290 |
291 | The most influential tip on how to think about designing a component I've ever
292 | seen is from Nicole Sullivan's excellent article [The media object saves
293 | hundreds of lines of
294 | code](http://www.stubbornella.org/content/2010/06/25/the-media-object-saves-hundreds-of-lines-of-code/)
295 |
296 | > "When I’m building a new object, the first thing I do is to figure out which parts are reusable components, and define what I know and do not know about them."
297 | > "For example: Can be nested, Optional right button, Must clearfix"
298 | - [Nicole Sullivan](http://stubbornella.org)
299 |
300 | I can't recommend this process for designing and developing components enough.
301 | One of the things I like about react and css in js, is that it's easy to work
302 | within this mental model. It's helpful to actively think and sketch out what
303 | you know and what you don't know. This can help you build components that are
304 | more resiliant, flexible, and reusable.
305 |
306 | So, say we defined some scales, or options to work with for the following
307 | properties.
308 |
309 | #### Typography
310 | - Font-family
311 | - Line-height
312 | - Type-scale
313 | - Measure (max line length)
314 | - Font Weights
315 | - Text Transform
316 |
317 | #### Layout
318 | - Spacing
319 | - Width
320 |
321 | #### Theme
322 | - Colors
323 | - Border Widths
324 | - Border Colors
325 | - Border Radii
326 | - Box Shadows
327 |
328 | #### Motion
329 | - Animation speed
330 | - Easing Functions
331 | - Movement patterns
332 |
333 | Maybe this would look something like this
334 |
335 | ```
336 | const theme = {
337 | breakpoints: [
338 | 36, 48, 64
339 | ],
340 | fontFamily:[ '"Gotham", "Avenir Next", "Proxima Nova", "Helvetica"' ],
341 | fontSize: [
342 | 12, 14, 16, 20, 24, 32, 48, 64, 96, 128
343 | ],
344 | fontWeight: [ 400, 600, 700 ],
345 | lineHeight: [ 1, 1.25, 1.5 ],
346 | colors: [
347 | { text: "#000", bg: "#fff" },
348 | { text: "#374047", bg: "#f8f9f9" },
349 | { text: "#7f8a93", bg: "#f8f9f9" },
350 | { text: "#0077cc", bg: "#f8f9f9" },
351 | { text: "#005da0", bg: "#f8f9f9" },
352 | { text: "#00365d", bg: "#f8f9f9" },
353 | { text: "#00a243", bg: "#fff" },
354 | ],
355 | borderStyle: [
356 | 'solid',
357 | 'double',
358 | 'dotted'
359 | ],
360 | borderWidth: [ 0, 1, 2, 4 ],
361 | borderDirection: [
362 | 'all',
363 | 'top',
364 | 'bottom'
365 | ],
366 | radii: [
367 | 0, 3, 5, 17, 9999
368 | ],
369 | space: [
370 | 0, 2, 4, 8, 16, 32, 64, 128, 256, 512
371 | ],
372 | measure: [ '20em', '30em', '34em' ],
373 | boxShadow: [ '0 0 16px rgba(0,0,0,.2)' ],
374 | }
375 |
376 | export default theme
377 | ```
378 |
379 | Some of you might have already seen a file like this before. Maybe it was a js
380 | file, maybe it was a sass, less, or stylus file. This is pretty boring and
381 | there isn't anything new about it. It's just a theme.
382 |
383 | Thinking about the previous quote by Nicole Sullivan... What if I had to
384 | design a button and I wanted it to use values from our design system. We could
385 | define the styling API for a button. (People love buttons.) Potentially, we
386 | could define a template for a button styling API. So we'd need to think about
387 | which properties we *always* want exposed. I think it's safe to say that people
388 | should be able to set the background color on a button. The default color isn't
389 | perfect or anything. It's reasonable for a well designed interface to have buttons with
390 | different background colors. As a section in the button API we'd also want to
391 | declare which properties should be available to style on hover. I believe it's reasonable
392 | to change the background color on hover. So I think that should also be a part of the
393 | API. Returning to the base part of the button API, it would be seemingly
394 | reasonable to be able to set the font-weight to something other than the
395 | default. In all my years of browsing the web I've never hovered on a button and
396 | seen the font-weight change and thought "This is so nice." My first thought is
397 | generally "Well this must be a bug." So here we could choose to leave font-weight out of
398 | the hover, focus, and active sections in the API.
399 |
400 | A generic template for a button styling API might look like this:
401 |
402 | ```
403 | import theme from './theme'
404 |
405 | const buttonThemeTemplate = {
406 |
407 | // Typography
408 | fontFamily: [ ],
409 | fontSize: [ ],
410 | fontWeight: [ ],
411 | textTransform: [ ],
412 |
413 | // Palette
414 | colors: [ ],
415 | backgroundColors: [ ],
416 |
417 | // Borders
418 | borderColors: [ ]
419 | borderRadius: [ ],
420 | borderStyle: [ ],
421 | borderWidth: [ ],
422 | borderDirections: [ ],
423 |
424 | // Spacing
425 | paddingTop: [],
426 | paddingLeft: [],
427 | paddingBottom: [],
428 | paddingRight: [],
429 |
430 | // Hover states
431 | hoverColor: [ ],
432 | hoverBg: [ ],
433 | hoverBoxShadow: [ ],
434 | hoverBorderColor: [ ],
435 | hoverSize: [ ],
436 |
437 | // Focus states
438 | focusColor: [ ],
439 | focusBg: [ ],
440 | focusBorderColor: [ ],
441 | focusBoxShadow: [ ],
442 | focusSize: [ ],
443 |
444 | // Focus states
445 | activeColor: [ ],
446 | activeBg: [ ],
447 | activeBorderColor: [ ],
448 | activeBoxShadow: [ ],
449 | activeSize: [ ],
450 |
451 | transitionProperty: [ ],
452 | transitionDuration: [ ],
453 | transitionTimingFunction: [ ],
454 | }
455 |
456 | export default buttonThemeTemplate
457 | ```
458 |
459 | Then we could define what values we want to pass in. We might pass in an entire
460 | array, declare literal values, pass in a filtered array. We have javascript. We
461 | can do whatever we want!
462 |
463 | ```
464 | import theme from './theme'
465 |
466 | const buttonTheme = {
467 | radii: theme.radii, // Entire scale
468 | space: [
469 | // Explicit steps from the scale
470 | theme.space[3],
471 | theme.space[4],
472 | ],
473 | fontSize: theme.fontSize.slice(0,-8), // Everything but the last 8 steps in the scale
474 | fontFamily: theme.fontFamily[0], // An explicit step in the scale
475 | borderStyle: [
476 | theme.borderStyle[0],
477 | theme.borderStyle[1]
478 | ],
479 | borderWidth: theme.borderWidth,
480 | fontWeight: theme.fontWeight,
481 | colors: theme.colors,
482 | backgroundColors: theme.colors,
483 |
484 | // hover, focus, active states
485 |
486 | hoverColor: [
487 | theme.colors[0].text,
488 | theme.colors[1].text
489 | ],
490 | hoverBgColor: [
491 | theme.colors[0].bg,
492 | theme.colors[0].bg
493 | ],
494 | focusColor: [
495 | theme.colors[1].text,
496 | theme.colors[1].bg
497 | ],
498 | textTransform: ['uppercase', 'capitalized'],
499 | transitionProperty: ['opacity', 'color', 'background-color'],
500 | transitionDuration: ['.25s'],
501 | transitionTimingFunction: ['ease-out'],
502 | }
503 |
504 | export default buttonTheme
505 | ```
506 |
507 | As a design community, we could make boilerplate config files for common ui components.
508 | Over time we could reinvent fewer and fewer wheels. This would allow us to go deeper on
509 | other areas that haven't been explored as much as button styles.
510 |
511 | This is where I think it gets *really* interesting.
512 |
513 | Now we have a system.
514 | We can use combinational logic to generate all possible combinations of buttons
515 | given the input provided by a theme file. We could also use this pattern to
516 | create a finite state machine, and visualize transitions between any discrete
517 | state a given component can be in.
518 |
519 | A simple config file like this generates thousands and thousands of button designs.
520 | Here is an example of generating avatars and buttons.
521 |
522 | https://examples-jchwaftrgo.now.sh
523 |
524 | Or we can make this a finite state machine and animate between the options. You
525 | know, if you don't like scrolling for days and days and days. (Again, animation
526 | created & provided by the one and only Harley Turan).
527 |
528 | https://examples-wrjcynrjhj.now.sh
529 |
530 | *Let's step back and think at ten thousand feet again.*
531 |
532 | - We can show how many options a design system can generate. This can be
533 | helpful because some people feel they might be constrained by working with
534 | defined scales. This can help show how varied their visual designs can still
535 | be. A lot of people still haven't worked with scales and as a creative person
536 | constraint can be scary at first.
537 | - We can quickly identify desirable regions, which can help us quickly discover
538 | patterns of inputs needed for a desired output. This can expose properties
539 | you might want to couple together and set rules for. Sense of proportion can
540 | change dramatically at each end of the scale.
541 | - Could automatically a/b test design options with real user metrics
542 | - Wire up options to an interface that allows for collaborative voting on which
543 | component variations feel most on brand. You could even hook this voting up
544 | to a neural network.
545 | - One of if not the most difficult part about image classification is coming up with the training data.
546 | The generated data could help train an image classifier which will in turn
547 | help audit existing UI on websites. Imagine being able to input a url and
548 | query the design with questions lke:
549 | - "Show me all of the buttons."
550 | - "Show me all of the orange buttons."
551 | - "Show me all of the buttons that have inaccessible color combinations."
552 |
553 | This is an exciting reality to live in. We can more quickly generate lots of design
554 | options to test with real users. We can shorten the feedback loop around discovering
555 | what matters and what doesn't. This is a stark contrast to our current reality, which is that
556 | most designs we ship have not been validated with real users. We don't design multiple options in
557 | parallel. We end up designing a single option that is optimized for getting stakeholder signoff in a series
558 | of status meetings.
559 |
560 | But at the very least this concept is exciting to me because I'm very lazy and
561 | I don't want to design buttons anymore.
562 |
--------------------------------------------------------------------------------
/examples/README.md:
--------------------------------------------------------------------------------
1 | This project was bootstrapped with [Create React App](https://github.com/facebookincubator/create-react-app).
2 |
3 | Below you will find some information on how to perform common tasks.
4 | You can find the most recent version of this guide [here](https://github.com/facebookincubator/create-react-app/blob/master/packages/react-scripts/template/README.md).
5 |
6 | ## Table of Contents
7 |
8 | - [Updating to New Releases](#updating-to-new-releases)
9 | - [Sending Feedback](#sending-feedback)
10 | - [Folder Structure](#folder-structure)
11 | - [Available Scripts](#available-scripts)
12 | - [npm start](#npm-start)
13 | - [npm test](#npm-test)
14 | - [npm run build](#npm-run-build)
15 | - [npm run eject](#npm-run-eject)
16 | - [Supported Language Features and Polyfills](#supported-language-features-and-polyfills)
17 | - [Syntax Highlighting in the Editor](#syntax-highlighting-in-the-editor)
18 | - [Displaying Lint Output in the Editor](#displaying-lint-output-in-the-editor)
19 | - [Debugging in the Editor](#debugging-in-the-editor)
20 | - [Formatting Code Automatically](#formatting-code-automatically)
21 | - [Changing the Page ``](#changing-the-page-title)
22 | - [Installing a Dependency](#installing-a-dependency)
23 | - [Importing a Component](#importing-a-component)
24 | - [Code Splitting](#code-splitting)
25 | - [Adding a Stylesheet](#adding-a-stylesheet)
26 | - [Post-Processing CSS](#post-processing-css)
27 | - [Adding a CSS Preprocessor (Sass, Less etc.)](#adding-a-css-preprocessor-sass-less-etc)
28 | - [Adding Images, Fonts, and Files](#adding-images-fonts-and-files)
29 | - [Using the `public` Folder](#using-the-public-folder)
30 | - [Changing the HTML](#changing-the-html)
31 | - [Adding Assets Outside of the Module System](#adding-assets-outside-of-the-module-system)
32 | - [When to Use the `public` Folder](#when-to-use-the-public-folder)
33 | - [Using Global Variables](#using-global-variables)
34 | - [Adding Bootstrap](#adding-bootstrap)
35 | - [Using a Custom Theme](#using-a-custom-theme)
36 | - [Adding Flow](#adding-flow)
37 | - [Adding Custom Environment Variables](#adding-custom-environment-variables)
38 | - [Referencing Environment Variables in the HTML](#referencing-environment-variables-in-the-html)
39 | - [Adding Temporary Environment Variables In Your Shell](#adding-temporary-environment-variables-in-your-shell)
40 | - [Adding Development Environment Variables In `.env`](#adding-development-environment-variables-in-env)
41 | - [Can I Use Decorators?](#can-i-use-decorators)
42 | - [Integrating with an API Backend](#integrating-with-an-api-backend)
43 | - [Node](#node)
44 | - [Ruby on Rails](#ruby-on-rails)
45 | - [Proxying API Requests in Development](#proxying-api-requests-in-development)
46 | - ["Invalid Host Header" Errors After Configuring Proxy](#invalid-host-header-errors-after-configuring-proxy)
47 | - [Configuring the Proxy Manually](#configuring-the-proxy-manually)
48 | - [Configuring a WebSocket Proxy](#configuring-a-websocket-proxy)
49 | - [Using HTTPS in Development](#using-https-in-development)
50 | - [Generating Dynamic `` Tags on the Server](#generating-dynamic-meta-tags-on-the-server)
51 | - [Pre-Rendering into Static HTML Files](#pre-rendering-into-static-html-files)
52 | - [Injecting Data from the Server into the Page](#injecting-data-from-the-server-into-the-page)
53 | - [Running Tests](#running-tests)
54 | - [Filename Conventions](#filename-conventions)
55 | - [Command Line Interface](#command-line-interface)
56 | - [Version Control Integration](#version-control-integration)
57 | - [Writing Tests](#writing-tests)
58 | - [Testing Components](#testing-components)
59 | - [Using Third Party Assertion Libraries](#using-third-party-assertion-libraries)
60 | - [Initializing Test Environment](#initializing-test-environment)
61 | - [Focusing and Excluding Tests](#focusing-and-excluding-tests)
62 | - [Coverage Reporting](#coverage-reporting)
63 | - [Continuous Integration](#continuous-integration)
64 | - [Disabling jsdom](#disabling-jsdom)
65 | - [Snapshot Testing](#snapshot-testing)
66 | - [Editor Integration](#editor-integration)
67 | - [Developing Components in Isolation](#developing-components-in-isolation)
68 | - [Getting Started with Storybook](#getting-started-with-storybook)
69 | - [Getting Started with Styleguidist](#getting-started-with-styleguidist)
70 | - [Making a Progressive Web App](#making-a-progressive-web-app)
71 | - [Opting Out of Caching](#opting-out-of-caching)
72 | - [Offline-First Considerations](#offline-first-considerations)
73 | - [Progressive Web App Metadata](#progressive-web-app-metadata)
74 | - [Analyzing the Bundle Size](#analyzing-the-bundle-size)
75 | - [Deployment](#deployment)
76 | - [Static Server](#static-server)
77 | - [Other Solutions](#other-solutions)
78 | - [Serving Apps with Client-Side Routing](#serving-apps-with-client-side-routing)
79 | - [Building for Relative Paths](#building-for-relative-paths)
80 | - [Azure](#azure)
81 | - [Firebase](#firebase)
82 | - [GitHub Pages](#github-pages)
83 | - [Heroku](#heroku)
84 | - [Netlify](#netlify)
85 | - [Now](#now)
86 | - [S3 and CloudFront](#s3-and-cloudfront)
87 | - [Surge](#surge)
88 | - [Advanced Configuration](#advanced-configuration)
89 | - [Troubleshooting](#troubleshooting)
90 | - [`npm start` doesn’t detect changes](#npm-start-doesnt-detect-changes)
91 | - [`npm test` hangs on macOS Sierra](#npm-test-hangs-on-macos-sierra)
92 | - [`npm run build` exits too early](#npm-run-build-exits-too-early)
93 | - [`npm run build` fails on Heroku](#npm-run-build-fails-on-heroku)
94 | - [`npm run build` fails to minify](#npm-run-build-fails-to-minify)
95 | - [Moment.js locales are missing](#momentjs-locales-are-missing)
96 | - [Something Missing?](#something-missing)
97 |
98 | ## Updating to New Releases
99 |
100 | Create React App is divided into two packages:
101 |
102 | * `create-react-app` is a global command-line utility that you use to create new projects.
103 | * `react-scripts` is a development dependency in the generated projects (including this one).
104 |
105 | You almost never need to update `create-react-app` itself: it delegates all the setup to `react-scripts`.
106 |
107 | When you run `create-react-app`, it always creates the project with the latest version of `react-scripts` so you’ll get all the new features and improvements in newly created apps automatically.
108 |
109 | To update an existing project to a new version of `react-scripts`, [open the changelog](https://github.com/facebookincubator/create-react-app/blob/master/CHANGELOG.md), find the version you’re currently on (check `package.json` in this folder if you’re not sure), and apply the migration instructions for the newer versions.
110 |
111 | In most cases bumping the `react-scripts` version in `package.json` and running `npm install` in this folder should be enough, but it’s good to consult the [changelog](https://github.com/facebookincubator/create-react-app/blob/master/CHANGELOG.md) for potential breaking changes.
112 |
113 | We commit to keeping the breaking changes minimal so you can upgrade `react-scripts` painlessly.
114 |
115 | ## Sending Feedback
116 |
117 | We are always open to [your feedback](https://github.com/facebookincubator/create-react-app/issues).
118 |
119 | ## Folder Structure
120 |
121 | After creation, your project should look like this:
122 |
123 | ```
124 | my-app/
125 | README.md
126 | node_modules/
127 | package.json
128 | public/
129 | index.html
130 | favicon.ico
131 | src/
132 | App.css
133 | App.js
134 | App.test.js
135 | index.css
136 | index.js
137 | logo.svg
138 | ```
139 |
140 | For the project to build, **these files must exist with exact filenames**:
141 |
142 | * `public/index.html` is the page template;
143 | * `src/index.js` is the JavaScript entry point.
144 |
145 | You can delete or rename the other files.
146 |
147 | You may create subdirectories inside `src`. For faster rebuilds, only files inside `src` are processed by Webpack.
148 | You need to **put any JS and CSS files inside `src`**, otherwise Webpack won’t see them.
149 |
150 | Only files inside `public` can be used from `public/index.html`.
151 | Read instructions below for using assets from JavaScript and HTML.
152 |
153 | You can, however, create more top-level directories.
154 | They will not be included in the production build so you can use them for things like documentation.
155 |
156 | ## Available Scripts
157 |
158 | In the project directory, you can run:
159 |
160 | ### `npm start`
161 |
162 | Runs the app in the development mode.
163 | Open [http://localhost:3000](http://localhost:3000) to view it in the browser.
164 |
165 | The page will reload if you make edits.
166 | You will also see any lint errors in the console.
167 |
168 | ### `npm test`
169 |
170 | Launches the test runner in the interactive watch mode.
171 | See the section about [running tests](#running-tests) for more information.
172 |
173 | ### `npm run build`
174 |
175 | Builds the app for production to the `build` folder.
176 | It correctly bundles React in production mode and optimizes the build for the best performance.
177 |
178 | The build is minified and the filenames include the hashes.
179 | Your app is ready to be deployed!
180 |
181 | See the section about [deployment](#deployment) for more information.
182 |
183 | ### `npm run eject`
184 |
185 | **Note: this is a one-way operation. Once you `eject`, you can’t go back!**
186 |
187 | If you aren’t satisfied with the build tool and configuration choices, you can `eject` at any time. This command will remove the single build dependency from your project.
188 |
189 | Instead, it will copy all the configuration files and the transitive dependencies (Webpack, Babel, ESLint, etc) right into your project so you have full control over them. All of the commands except `eject` will still work, but they will point to the copied scripts so you can tweak them. At this point you’re on your own.
190 |
191 | You don’t have to ever use `eject`. The curated feature set is suitable for small and middle deployments, and you shouldn’t feel obligated to use this feature. However we understand that this tool wouldn’t be useful if you couldn’t customize it when you are ready for it.
192 |
193 | ## Supported Language Features and Polyfills
194 |
195 | This project supports a superset of the latest JavaScript standard.
196 | In addition to [ES6](https://github.com/lukehoban/es6features) syntax features, it also supports:
197 |
198 | * [Exponentiation Operator](https://github.com/rwaldron/exponentiation-operator) (ES2016).
199 | * [Async/await](https://github.com/tc39/ecmascript-asyncawait) (ES2017).
200 | * [Object Rest/Spread Properties](https://github.com/sebmarkbage/ecmascript-rest-spread) (stage 3 proposal).
201 | * [Dynamic import()](https://github.com/tc39/proposal-dynamic-import) (stage 3 proposal)
202 | * [Class Fields and Static Properties](https://github.com/tc39/proposal-class-public-fields) (part of stage 3 proposal).
203 | * [JSX](https://facebook.github.io/react/docs/introducing-jsx.html) and [Flow](https://flowtype.org/) syntax.
204 |
205 | Learn more about [different proposal stages](https://babeljs.io/docs/plugins/#presets-stage-x-experimental-presets-).
206 |
207 | While we recommend to use experimental proposals with some caution, Facebook heavily uses these features in the product code, so we intend to provide [codemods](https://medium.com/@cpojer/effective-javascript-codemods-5a6686bb46fb) if any of these proposals change in the future.
208 |
209 | Note that **the project only includes a few ES6 [polyfills](https://en.wikipedia.org/wiki/Polyfill)**:
210 |
211 | * [`Object.assign()`](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Object/assign) via [`object-assign`](https://github.com/sindresorhus/object-assign).
212 | * [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) via [`promise`](https://github.com/then/promise).
213 | * [`fetch()`](https://developer.mozilla.org/en/docs/Web/API/Fetch_API) via [`whatwg-fetch`](https://github.com/github/fetch).
214 |
215 | If you use any other ES6+ features that need **runtime support** (such as `Array.from()` or `Symbol`), make sure you are including the appropriate polyfills manually, or that the browsers you are targeting already support them.
216 |
217 | ## Syntax Highlighting in the Editor
218 |
219 | To configure the syntax highlighting in your favorite text editor, head to the [relevant Babel documentation page](https://babeljs.io/docs/editors) and follow the instructions. Some of the most popular editors are covered.
220 |
221 | ## Displaying Lint Output in the Editor
222 |
223 | >Note: this feature is available with `react-scripts@0.2.0` and higher.
224 | >It also only works with npm 3 or higher.
225 |
226 | Some editors, including Sublime Text, Atom, and Visual Studio Code, provide plugins for ESLint.
227 |
228 | They are not required for linting. You should see the linter output right in your terminal as well as the browser console. However, if you prefer the lint results to appear right in your editor, there are some extra steps you can do.
229 |
230 | You would need to install an ESLint plugin for your editor first. Then, add a file called `.eslintrc` to the project root:
231 |
232 | ```js
233 | {
234 | "extends": "react-app"
235 | }
236 | ```
237 |
238 | Now your editor should report the linting warnings.
239 |
240 | Note that even if you edit your `.eslintrc` file further, these changes will **only affect the editor integration**. They won’t affect the terminal and in-browser lint output. This is because Create React App intentionally provides a minimal set of rules that find common mistakes.
241 |
242 | If you want to enforce a coding style for your project, consider using [Prettier](https://github.com/jlongster/prettier) instead of ESLint style rules.
243 |
244 | ## Debugging in the Editor
245 |
246 | **This feature is currently only supported by [Visual Studio Code](https://code.visualstudio.com) and [WebStorm](https://www.jetbrains.com/webstorm/).**
247 |
248 | Visual Studio Code and WebStorm support debugging out of the box with Create React App. This enables you as a developer to write and debug your React code without leaving the editor, and most importantly it enables you to have a continuous development workflow, where context switching is minimal, as you don’t have to switch between tools.
249 |
250 | ### Visual Studio Code
251 |
252 | You would need to have the latest version of [VS Code](https://code.visualstudio.com) and VS Code [Chrome Debugger Extension](https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome) installed.
253 |
254 | Then add the block below to your `launch.json` file and put it inside the `.vscode` folder in your app’s root directory.
255 |
256 | ```json
257 | {
258 | "version": "0.2.0",
259 | "configurations": [{
260 | "name": "Chrome",
261 | "type": "chrome",
262 | "request": "launch",
263 | "url": "http://localhost:3000",
264 | "webRoot": "${workspaceRoot}/src",
265 | "userDataDir": "${workspaceRoot}/.vscode/chrome",
266 | "sourceMapPathOverrides": {
267 | "webpack:///src/*": "${webRoot}/*"
268 | }
269 | }]
270 | }
271 | ```
272 | >Note: the URL may be different if you've made adjustments via the [HOST or PORT environment variables](#advanced-configuration).
273 |
274 | Start your app by running `npm start`, and start debugging in VS Code by pressing `F5` or by clicking the green debug icon. You can now write code, set breakpoints, make changes to the code, and debug your newly modified code—all from your editor.
275 |
276 | ### WebStorm
277 |
278 | You would need to have [WebStorm](https://www.jetbrains.com/webstorm/) and [JetBrains IDE Support](https://chrome.google.com/webstore/detail/jetbrains-ide-support/hmhgeddbohgjknpmjagkdomcpobmllji) Chrome extension installed.
279 |
280 | In the WebStorm menu `Run` select `Edit Configurations...`. Then click `+` and select `JavaScript Debug`. Paste `http://localhost:3000` into the URL field and save the configuration.
281 |
282 | >Note: the URL may be different if you've made adjustments via the [HOST or PORT environment variables](#advanced-configuration).
283 |
284 | Start your app by running `npm start`, then press `^D` on macOS or `F9` on Windows and Linux or click the green debug icon to start debugging in WebStorm.
285 |
286 | The same way you can debug your application in IntelliJ IDEA Ultimate, PhpStorm, PyCharm Pro, and RubyMine.
287 |
288 | ## Formatting Code Automatically
289 |
290 | Prettier is an opinionated code formatter with support for JavaScript, CSS and JSON. With Prettier you can format the code you write automatically to ensure a code style within your project. See the [Prettier's GitHub page](https://github.com/prettier/prettier) for more information, and look at this [page to see it in action](https://prettier.github.io/prettier/).
291 |
292 | To format our code whenever we make a commit in git, we need to install the following dependencies:
293 |
294 | ```sh
295 | npm install --save husky lint-staged prettier
296 | ```
297 |
298 | Alternatively you may use `yarn`:
299 |
300 | ```sh
301 | yarn add husky lint-staged prettier
302 | ```
303 |
304 | * `husky` makes it easy to use githooks as if they are npm scripts.
305 | * `lint-staged` allows us to run scripts on staged files in git. See this [blog post about lint-staged to learn more about it](https://medium.com/@okonetchnikov/make-linting-great-again-f3890e1ad6b8).
306 | * `prettier` is the JavaScript formatter we will run before commits.
307 |
308 | Now we can make sure every file is formatted correctly by adding a few lines to the `package.json` in the project root.
309 |
310 | Add the following line to `scripts` section:
311 |
312 | ```diff
313 | "scripts": {
314 | + "precommit": "lint-staged",
315 | "start": "react-scripts start",
316 | "build": "react-scripts build",
317 | ```
318 |
319 | Next we add a 'lint-staged' field to the `package.json`, for example:
320 |
321 | ```diff
322 | "dependencies": {
323 | // ...
324 | },
325 | + "lint-staged": {
326 | + "src/**/*.{js,jsx,json,css}": [
327 | + "prettier --single-quote --write",
328 | + "git add"
329 | + ]
330 | + },
331 | "scripts": {
332 | ```
333 |
334 | Now, whenever you make a commit, Prettier will format the changed files automatically. You can also run `./node_modules/.bin/prettier --single-quote --write "src/**/*.{js,jsx}"` to format your entire project for the first time.
335 |
336 | Next you might want to integrate Prettier in your favorite editor. Read the section on [Editor Integration](https://github.com/prettier/prettier#editor-integration) on the Prettier GitHub page.
337 |
338 | ## Changing the Page ``
339 |
340 | You can find the source HTML file in the `public` folder of the generated project. You may edit the `` tag in it to change the title from “React App” to anything else.
341 |
342 | Note that normally you wouldn’t edit files in the `public` folder very often. For example, [adding a stylesheet](#adding-a-stylesheet) is done without touching the HTML.
343 |
344 | If you need to dynamically update the page title based on the content, you can use the browser [`document.title`](https://developer.mozilla.org/en-US/docs/Web/API/Document/title) API. For more complex scenarios when you want to change the title from React components, you can use [React Helmet](https://github.com/nfl/react-helmet), a third party library.
345 |
346 | If you use a custom server for your app in production and want to modify the title before it gets sent to the browser, you can follow advice in [this section](#generating-dynamic-meta-tags-on-the-server). Alternatively, you can pre-build each page as a static HTML file which then loads the JavaScript bundle, which is covered [here](#pre-rendering-into-static-html-files).
347 |
348 | ## Installing a Dependency
349 |
350 | The generated project includes React and ReactDOM as dependencies. It also includes a set of scripts used by Create React App as a development dependency. You may install other dependencies (for example, React Router) with `npm`:
351 |
352 | ```sh
353 | npm install --save react-router
354 | ```
355 |
356 | Alternatively you may use `yarn`:
357 |
358 | ```sh
359 | yarn add react-router
360 | ```
361 |
362 | This works for any library, not just `react-router`.
363 |
364 | ## Importing a Component
365 |
366 | This project setup supports ES6 modules thanks to Babel.
367 | While you can still use `require()` and `module.exports`, we encourage you to use [`import` and `export`](http://exploringjs.com/es6/ch_modules.html) instead.
368 |
369 | For example:
370 |
371 | ### `Button.js`
372 |
373 | ```js
374 | import React, { Component } from 'react';
375 |
376 | class Button extends Component {
377 | render() {
378 | // ...
379 | }
380 | }
381 |
382 | export default Button; // Don’t forget to use export default!
383 | ```
384 |
385 | ### `DangerButton.js`
386 |
387 |
388 | ```js
389 | import React, { Component } from 'react';
390 | import Button from './Button'; // Import a component from another file
391 |
392 | class DangerButton extends Component {
393 | render() {
394 | return ;
395 | }
396 | }
397 |
398 | export default DangerButton;
399 | ```
400 |
401 | Be aware of the [difference between default and named exports](http://stackoverflow.com/questions/36795819/react-native-es-6-when-should-i-use-curly-braces-for-import/36796281#36796281). It is a common source of mistakes.
402 |
403 | We suggest that you stick to using default imports and exports when a module only exports a single thing (for example, a component). That’s what you get when you use `export default Button` and `import Button from './Button'`.
404 |
405 | Named exports are useful for utility modules that export several functions. A module may have at most one default export and as many named exports as you like.
406 |
407 | Learn more about ES6 modules:
408 |
409 | * [When to use the curly braces?](http://stackoverflow.com/questions/36795819/react-native-es-6-when-should-i-use-curly-braces-for-import/36796281#36796281)
410 | * [Exploring ES6: Modules](http://exploringjs.com/es6/ch_modules.html)
411 | * [Understanding ES6: Modules](https://leanpub.com/understandinges6/read#leanpub-auto-encapsulating-code-with-modules)
412 |
413 | ## Code Splitting
414 |
415 | Instead of downloading the entire app before users can use it, code splitting allows you to split your code into small chunks which you can then load on demand.
416 |
417 | This project setup supports code splitting via [dynamic `import()`](http://2ality.com/2017/01/import-operator.html#loading-code-on-demand). Its [proposal](https://github.com/tc39/proposal-dynamic-import) is in stage 3. The `import()` function-like form takes the module name as an argument and returns a [`Promise`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise) which always resolves to the namespace object of the module.
418 |
419 | Here is an example:
420 |
421 | ### `moduleA.js`
422 |
423 | ```js
424 | const moduleA = 'Hello';
425 |
426 | export { moduleA };
427 | ```
428 | ### `App.js`
429 |
430 | ```js
431 | import React, { Component } from 'react';
432 |
433 | class App extends Component {
434 | handleClick = () => {
435 | import('./moduleA')
436 | .then(({ moduleA }) => {
437 | // Use moduleA
438 | })
439 | .catch(err => {
440 | // Handle failure
441 | });
442 | };
443 |
444 | render() {
445 | return (
446 |
447 |
448 |
449 | );
450 | }
451 | }
452 |
453 | export default App;
454 | ```
455 |
456 | This will make `moduleA.js` and all its unique dependencies as a separate chunk that only loads after the user clicks the 'Load' button.
457 |
458 | You can also use it with `async` / `await` syntax if you prefer it.
459 |
460 | ### With React Router
461 |
462 | If you are using React Router check out [this tutorial](http://serverless-stack.com/chapters/code-splitting-in-create-react-app.html) on how to use code splitting with it. You can find the companion GitHub repository [here](https://github.com/AnomalyInnovations/serverless-stack-demo-client/tree/code-splitting-in-create-react-app).
463 |
464 | ## Adding a Stylesheet
465 |
466 | This project setup uses [Webpack](https://webpack.js.org/) for handling all assets. Webpack offers a custom way of “extending” the concept of `import` beyond JavaScript. To express that a JavaScript file depends on a CSS file, you need to **import the CSS from the JavaScript file**:
467 |
468 | ### `Button.css`
469 |
470 | ```css
471 | .Button {
472 | padding: 20px;
473 | }
474 | ```
475 |
476 | ### `Button.js`
477 |
478 | ```js
479 | import React, { Component } from 'react';
480 | import './Button.css'; // Tell Webpack that Button.js uses these styles
481 |
482 | class Button extends Component {
483 | render() {
484 | // You can use them as regular CSS styles
485 | return ;
486 | }
487 | }
488 | ```
489 |
490 | **This is not required for React** but many people find this feature convenient. You can read about the benefits of this approach [here](https://medium.com/seek-ui-engineering/block-element-modifying-your-javascript-components-d7f99fcab52b). However you should be aware that this makes your code less portable to other build tools and environments than Webpack.
491 |
492 | In development, expressing dependencies this way allows your styles to be reloaded on the fly as you edit them. In production, all CSS files will be concatenated into a single minified `.css` file in the build output.
493 |
494 | If you are concerned about using Webpack-specific semantics, you can put all your CSS right into `src/index.css`. It would still be imported from `src/index.js`, but you could always remove that import if you later migrate to a different build tool.
495 |
496 | ## Post-Processing CSS
497 |
498 | This project setup minifies your CSS and adds vendor prefixes to it automatically through [Autoprefixer](https://github.com/postcss/autoprefixer) so you don’t need to worry about it.
499 |
500 | For example, this:
501 |
502 | ```css
503 | .App {
504 | display: flex;
505 | flex-direction: row;
506 | align-items: center;
507 | }
508 | ```
509 |
510 | becomes this:
511 |
512 | ```css
513 | .App {
514 | display: -webkit-box;
515 | display: -ms-flexbox;
516 | display: flex;
517 | -webkit-box-orient: horizontal;
518 | -webkit-box-direction: normal;
519 | -ms-flex-direction: row;
520 | flex-direction: row;
521 | -webkit-box-align: center;
522 | -ms-flex-align: center;
523 | align-items: center;
524 | }
525 | ```
526 |
527 | If you need to disable autoprefixing for some reason, [follow this section](https://github.com/postcss/autoprefixer#disabling).
528 |
529 | ## Adding a CSS Preprocessor (Sass, Less etc.)
530 |
531 | Generally, we recommend that you don’t reuse the same CSS classes across different components. For example, instead of using a `.Button` CSS class in `` and `` components, we recommend creating a `