diff --git a/css/style.css b/css/style.css index c4ef0df..d6ee931 100755 --- a/css/style.css +++ b/css/style.css @@ -392,6 +392,10 @@ clear:both; padding-bottom:10px; } +.new { + color: #550000; +} + #shelf { padding-bottom:28px; text-align:center; @@ -489,11 +493,12 @@ display:block; font-style:italic; padding:15px 15px 35px 15px; box-shadow:0 1px 3px #d3d3d3; +font-size: 14px; color: #444444; } -blockquote cite { display: block; font-size: 12px; color: #555555; } +blockquote cite { display: block; font-size: 13px; color: #444444; } blockquote cite:before { content: "\2014 \0020"; } -blockquote cite a, blockquote cite a:visited { color: #555555; } +blockquote cite a, blockquote cite a:visited { color: #444444; } abbr, acronym { text-transform: uppercase; font-size: 90%; color: #222222; border-bottom: 1px solid #ddd; cursor: help; } diff --git a/images/testimonial_adam.jpg b/images/testimonial_adam.jpg new file mode 100644 index 0000000..35019c8 Binary files /dev/null and b/images/testimonial_adam.jpg differ diff --git a/images/testimonial_author_1.jpg b/images/testimonial_author_1.jpg deleted file mode 100755 index e24ceea..0000000 Binary files a/images/testimonial_author_1.jpg and /dev/null differ diff --git a/images/testimonial_author_2.jpg b/images/testimonial_author_2.jpg deleted file mode 100755 index 4b6ed21..0000000 Binary files a/images/testimonial_author_2.jpg and /dev/null differ diff --git a/images/testimonial_jon.jpg b/images/testimonial_jon.jpg new file mode 100644 index 0000000..059f10e Binary files /dev/null and b/images/testimonial_jon.jpg differ diff --git a/images/testimonial_spencer.jpg b/images/testimonial_spencer.jpg new file mode 100644 index 0000000..ac8da2b Binary files /dev/null and b/images/testimonial_spencer.jpg differ diff --git a/index.html b/index.html index 248c60f..de05191 100755 --- a/index.html +++ b/index.html @@ -1,240 +1,253 @@ - - - - - - -Pro React - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - - - -
-
- - - -
-
- - -
    -
  • -

    Complete

    Covers React in depth, including component composition, routing, animations, drag-n-drop, Flux, universal apps, performance tuning and testing.

  • -
  • -

    Up-to-date

    Keep updated with online appendixes and upgraded material.

  • -
  • -

    Tools of the trade

    The book uses Webpack and ESS2015 with Babel 6 - the most up-to-date and recommended setup used by React developers.

  • -
  • -

    Online API

    Download the server source code or develop using the freely available public API.

  • -
- -
-
- - - - - -
-
- - -
-The explanations are thorough but concise. I highly recommend it. -
-Mel Martins -
Mel Martins
-Engineer -
-
- - - -
-His technical writing is top notch, you'd be crazy to miss it. -
-Arthur Debert -
Arthur Debert
-CTO @ Loggi -
-
- - - -
-
- - -
-
- -
- eBook Landing Page -
- - -
-

Dozens of code samples

-

Plus a full featured kanban style app built throughout the book

- -

Take a look at the source code at the book's GitHub page.

- -
- -
-
- - - -
-
-
- - -Author - - -
- -

About the Author

- -

Cássio de Souza Antonio started programming 20 years ago with a Sinclair Spectrum and has since built a career as software engineer and technical manager in Brazil and USA.

- -

He has developed and contributed to projects for major brands such as Microsoft, Coca-Cola, Unilever, and HSBC, among others.

- -

His startup was acquired in late 2014. Currently Cássio works as a consultant. You can follow him on Twitter (@cassiozen)

- -
-
- -
- - -eBook Landing Page - - -
- -
-
- - - - - -
-
- - - - - - - - - - - + + + + + + +Pro React + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+
+ + + +
+
+ + +
    +
  • +

    Complete

    Covers React in depth, including component composition, routing, animations, drag-n-drop, Flux and Redux, universal apps, performance tuning and testing.

  • +
  • +

    Up-to-date

    Keep updated with online appendixes and upgraded material.

  • +
  • +

    Tools of the trade

    The book uses Webpack and ESS2015 with Babel 6 - the most up-to-date and recommended setup used by React developers.

  • +
  • +

    Online API

    Download the server source code or develop using the freely available APIs for the exercises and sample codes in the book.

  • +
+ +
+
+ + + + + +
+
+ + +
+Pro React is the book I wish I had when I first started learning React/JS.
Cassio does a fantastic job at introducing and explaining some of the key React concepts that took me digging through tons of blog posts to learn.
I highly recommend picking this book up.
+
+Spencer Dixon +
Spencer Dixon
+Software Engineer +
+
+ + + + +
+I have read a lot of software books, and this is one of the best. React comes in lots of little bits, which makes difficult to understand the whole system. The book did cover all of the steps but it also has sections on architecture, strategies and best practices. It is a really comprehensive resource. +
+Arthur Debert +
Jon Smith
+Software Architect +
+
+ + + +
+This is an outstanding dive into React.
The coverage of each topic is very well designed:
He initially makes a simple example, just to show the underlying concept bereft of any un-needed complexity, and then follows it up with a much more complex and realistic scenario.
+
+Adam Rackis +
Adam Rackis
+Software Engineer +
+
+ + + +
+
+ + +
+
+ +
+ eBook Landing Page +
+ + +
+

Dozens of code samples

+

Plus a full featured kanban style app built throughout the book

+ +

Take a look at the source code at the book's GitHub page.

+ +
+ +
+
+ + + +
+
+
+ + +Author + + +
+ +

About the Author

+ +

Cássio de Souza Antonio started programming 20 years ago with a Sinclair Spectrum and has since built a career as software engineer and technical manager in Brazil and USA.

+ +

He has developed and contributed to projects for major brands such as Microsoft, Coca-Cola, Unilever, and HSBC, among others.

+ +

His startup was acquired in late 2014. Currently Cássio works as a consultant. You can follow him on Twitter (@cassiozen)

+ +
+
+ +
+ + +eBook Landing Page + + +
+ +
+
+ + + + + +
+
+ + + + + + + + + + + diff --git a/logos/redux-bank.svg b/logos/redux-bank.svg new file mode 100644 index 0000000..4a6e6b5 --- /dev/null +++ b/logos/redux-bank.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/materials/appendixA.pdf b/materials/appendixA.pdf new file mode 100644 index 0000000..efcb6bc Binary files /dev/null and b/materials/appendixA.pdf differ diff --git a/materials/appendixA/images/picture1.png b/materials/appendixA/images/picture1.png new file mode 100644 index 0000000..fe60322 Binary files /dev/null and b/materials/appendixA/images/picture1.png differ diff --git a/materials/appendixA/images/picture2.png b/materials/appendixA/images/picture2.png new file mode 100644 index 0000000..69dcf34 Binary files /dev/null and b/materials/appendixA/images/picture2.png differ diff --git a/materials/appendixA/images/picture3.png b/materials/appendixA/images/picture3.png new file mode 100644 index 0000000..6d89359 Binary files /dev/null and b/materials/appendixA/images/picture3.png differ diff --git a/materials/appendixA/images/picture4.png b/materials/appendixA/images/picture4.png new file mode 100644 index 0000000..4177ff3 Binary files /dev/null and b/materials/appendixA/images/picture4.png differ diff --git a/materials/appendixA/images/picture5.png b/materials/appendixA/images/picture5.png new file mode 100644 index 0000000..768453f Binary files /dev/null and b/materials/appendixA/images/picture5.png differ diff --git a/materials/appendixA/images/picture6.png b/materials/appendixA/images/picture6.png new file mode 100644 index 0000000..28c808b Binary files /dev/null and b/materials/appendixA/images/picture6.png differ diff --git a/materials/appendixA/images/picture7.png b/materials/appendixA/images/picture7.png new file mode 100644 index 0000000..a7700ef Binary files /dev/null and b/materials/appendixA/images/picture7.png differ diff --git a/materials/appendixA/images/picture8.png b/materials/appendixA/images/picture8.png new file mode 100644 index 0000000..14fd894 Binary files /dev/null and b/materials/appendixA/images/picture8.png differ diff --git a/materials/appendixA/images/pro-react-cover.png b/materials/appendixA/images/pro-react-cover.png new file mode 100644 index 0000000..4eb35f8 Binary files /dev/null and b/materials/appendixA/images/pro-react-cover.png differ diff --git a/materials/appendixA/index.html b/materials/appendixA/index.html new file mode 100644 index 0000000..74a5160 --- /dev/null +++ b/materials/appendixA/index.html @@ -0,0 +1,1339 @@ + + + + + + Webpack for React + + + + + + + +
+ + Pro React - Appendix A +
+ + +
+
+

Appendix A: Webpack for React

+

Although Webpack is used throughout the book, it never got a comprehensive treatment because all the focus was on React. In this Appendix, you will have the chance to examine Webpack in depth, get a better understanding of how it works and learn more about loaders, plugins, hot module replacement and much more. By the end of this appendix you will be confident to setup your ideal development environment for your React projects with Webpack.

+ +

What is Webpack?

+ +

Over the years, web development evolved from pages with few assets and little to none JavaScript into full featured web applications with complex JavaScript and big dependency trees (files that depend upon multiple other files).

+ +

To help cope with this growing complexity, the community came up with different approaches and practices, such as: +

+ +

+ +

But while immensely helpful, these advances have brought the need for an additional step in the development process: We need to bundle together and transform (transpile / compile) these files into something that the browser can understand. That's where tools such as Webpack are necessary.

+ +

Webpack is a module bundler: A tool that can analyze your project's structure, find JavaScript modules and other assets to bundle and pack them for the browser.

+ + + + +

How does Webpack compare to build tools such as Grunt and Gulp?

+ +

Webpack is different from task runners and build systems such as Grunt and Gulp because it's not a build tool itself, but it can replace them with advantages.

+ +

Build tools such as Grunt and Gulp work by looking into a defined path for files that match your configuration. In the configuration file you also specify the tasks and steps that should run to transform, combine and/or minify each of these files.

+ +

Webpack, instead, analyzes your project as a whole. Given a starting main file, Webpack looks through all of your project's dependencies (by following require and import statements in JavaScript), processes them using loaders and generates a bundled JavaScript file.

+ +

Webpack's approach is faster and more straightforward. And, as you will see later in this chapter, opens lots of new possibilities for bundling different file types.

+ + +
+ + +

Getting Started

+ +

Webpack can be installed through npm. Install it globally using

npm install -g webpack

+

or add it as dependency in your project with

npm install --save-dev webpack

+ + + +

Sample project

+ +

Let's create a sample project to use Webpack. Start with a new, empty folder and create a package.json file - a standard npm manifest that holds various information about the project and let the developer specify dependencies (that can get automatically downloaded and installed) and define script tasks. To create a package.json file, run the following command on the terminal:

+ +

npm init

+ +

The init command will ask you a series of questions regarding your project (such as project name, description, information about the author, etc.) Don't worry too much - the answers to the questions are not so important if you don't want to publish your project to npm.

+ +

With a package.json file in place, add webpack as a project dependency and install it with:

+ +

npm install --save-dev webpack

+ +

With the project set up and webpack installed, let's move on to the project structure, which will consist of two folders: an "app" folder for original source code / JavaScript modules, and a "public" folder for files that are ready to be used in the browser (which include the bundled JavaScript file generated by Webpack, as well as an index.html file). You will create three files: An index.html file on the public folder and two JavaScript files on the app folder: main.js and Greeter.js. In the end, the project structure will look like the image below:

+ +

The index.html will contain a pretty basic HTML page, whose only purpose is to load the bundled JavaScript file:

+


+<!DOCTYPE html>
+<html lang="en">
+  <head>
+    <meta charset="utf-8">
+    <title>Webpack Sample Project</title>
+  </head>
+  <body>
+    <div id='root'>
+    </div>
+    <script src="bundle.js"></script>
+  </body>
+</html>
+      

+ +

Next, you will head to the JavaScript files: main.js and Greeter.js. The Greeter.js is simply a function that returns a new HTML element with a greeting message. The main.js file will insert the HTML element returned by the Greeter module in the page.

+ +

The main.js source code:

+


+var greeter = require('./Greeter.js');
+document.getElementById('root').appendChild(greeter());
+      

+ +

The Greeter.js source code:

+ +


+module.exports = function() {
+  var greet = document.createElement('div');
+  greet.textContent = "Hi there and greetings!";
+  return greet;
+};
+      

+ +
+

Note: Throughout the book, the recently standardized ES6 module definition was used. In its current version, though, Webpack only supports the commonJS module definition out of the box (i.e. require). Using ES6 modules with webpack will be covered later in this appendix.

+
+ + + + +

Running Your First Build

+ +

The basic command line syntax for webpack is "webpack {entry file} {destination for bundled file}". Remember, Webpack requires you to point only one entry file - it will figure out all the project's dependencies automatically. Additionally, if you don't have webpack installed globally, you will need to reference the webpack command in the node_modules folder of your project. For the sample project, the command will look like this:

+ +

node_modules/.bin/webpack app/main.js public/bundle.js

+ +

You should see the following output in the terminal:

+ +

+ +

Notice that Webpack bundled both the main.js and the Greeter.js files. If you open the index.html file on the browser, the result will look like this:

+ + + + +
+ + + +

Configuring Webpack

+ +

Webpack has a lot of different and advanced options and allows for the usage of loaders and plugins to apply transformations on the loaded modules. Although its possible to use webpack with all options from the command line, the process tends to get slow and error-prone. A better approach is to define a configuration file - a simple JavaScript module where you can put all information relating to your build.

+ +

To exemplify, create a file named webpack.config.js in your sample project. At bare minimum, the Webpack configuration file must reference the entry file and the destination for the bundled file:

+ +


+module.exports = {
+  entry:  __dirname + "/app/main.js",
+  output: {
+    path: __dirname + "/public",
+    filename: "bundle.js"
+  }
+}
+      

+ +
+

Note: "__dirname" is a node.js global variable containing the name of the directory that the currently executing script resides in.

+
+ +

Now you can simply run 'webpack' on the terminal without any parameters - since a webpack.config file is now present, the webpack command will build your application based on the configuration made available. The result of the command should look like this:

+ + + +

Adding task Shortcuts

+ +

Executing a long command such as "node_modules/.bin/webpack" is boring and error prone. Thankfully, npm can be used as a task runner, hiding verbose scripts under simple commands such as "npm start". This can be achieved easily by setting up a scripts section to package.json, as shown below:

+

Notice that all scripts configured in the package.json file already have the “node_modules/.bin” folder in the path, so you don’t need to explicitly call the desired command with the full path.

+ +


+{
+  "name": "webpack-sample-project",
+  "version": "1.0.0",
+  "description": "Sample webpack project",
+  "scripts": {
+    "start": "webpack"
+  },
+  "author": "Cássio Zen",
+  "license": "ISC",
+  "devDependencies": {
+    "webpack": "^1.12.9"
+  }
+}
+      
+ +

"start" is a special script name that can be executed with the command "npm start". You can create any other script names that you want, but in order to execute them you will need to use the command "npm run {script name}" (such as "npm run build", for example). You can see below the webpack command being executed from the npm start script:

+ + + +

Generating source maps

+ +

There is a handful of options for configuring Webpack - Let's get started with one of most important and used ones: Source Maps.

+ +

While packing together all of your project's JavaScript modules into one (or a few) bundled file to use on the browser presents a lot of advantages, one clear disadvantage is that you won't be able to reference back your original code in their original files when debugging in the browser - It becomes very challenging to locate exactly where the code you are trying to debug maps to your original authored code. However, Webpack can generate source maps when bundling - A source map provides a way of mapping code within a bundled file back to its original source file, making the code readable and easier to debug in the browser.

+ +

To configure Webpack to generate source maps that points to the original files, use the "devtool" setting with one of the following options:

+ + + + + + + + + + + + + + + + + + + + + + + + +
+

devtool option

+
+

Description

+
+

source-map

+
+

Generate a complete, full featured source map in a separate file. This option has the best quality of source map, but it does slow down the build process.

+
+

cheap-module-source-map

+
+

Generate source map in a separate file without column-mappings. Stripping the column mapping favors a better build performance introducing a minor inconvenience for debugging: The browser developer tools will only be able to point to the line of the original source code, but not to a specific column (or character).

+
+

eval-source-map

+
+

Bundles the source code modules using "eval", with nested, complete source map in the same file. This option does generate a full featured source map without a big impact on build time, but with performance and security drawbacks in the JavaScript execution. While it's a good option for using during development, this option should never be used in production.

+
+

cheap-module-eval-source-map

+
+

The fastest way to generate a source map during build. The generated source map will be inlined with the same bundled JavaScript file, without column-mappings. As in the previous option, there are drawbacks in JavaScript execution time, so this option is not appropriate for generating production-ready bundles.

+
+ +

As you can tell from the descriptions, the options are sorted from the slowest build time (on the top of the table) to the fastest (on the bottom). The options at the top produce better output with fewer downsides, while the options at the bottom introduce penalties during JavaScript execution in order to achieve better build speed.

+ +

Especially during learning and on small to medium sized projects, the "eval-source-map" is a good option: It generates a complete source map and since you can keep a separate configuration file for building production-ready bundles (as you will see later in this appendix), you can use it only during development without introducing any JavaScript execution penalties when the project goes live. You can see below the updated webpack.config.js file for the sample project.

+ +


+module.exports = {
+  devtool: 'eval-source-map',
+  entry:  __dirname + "/app/main.js",
+  output: {
+    path: __dirname + "/public",
+    filename: "bundle.js"
+  }
+}
+      

+ +
+

Note: There are even faster options for devtool (namely eval, cheap-source-map and cheap-eval-source-map). Although faster, these options don't map the bundled code straight to the original source files, and are more appropriate for bigger projects were build times are a concern. You can learn more about all the available options at webpack's documentation

+
+ + + +
+ + +

Webpack Development Server

+ +

Webpack has an optional server for local development purposes. It is a smallnode.js expressapp that serves static files and builds your assets according to your webpack configuration, keeping them in memory, and doing so automatically refreshing the browser as you change your source files. It's a separate npm module that should be installed as a project dependency:

+ +

npm install --save-dev webpack-dev-server

+ +

The webpack dev server can be configured in the same webpack.config.js configuration file, in a separate "devserver" entry. Configuration settings include:

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+

devserver setting

+
+

Description

+
+

contentBase

+
+

By default, thewebpack-dev-serverwill serve the files in the root of the project. To serve files from a different folder (such as the "public" folder in our sample project, you need to configure a specific content base.

+
+

port

+
+

Which port to use. If omitted, defaults to "8080".

+
+

inline

+
+

Set to "true" to insert a small client entry to the bundle to refresh the page on change.

+
+

colors

+
+

Add colors to the terminal output when the server is running.

+
+

historyApiFallback

+
+

Useful during the development of single page applications that make use of the HTML5 history API. When set to "true", all requests to thewebpack-dev-serverthat do not map to an existing asset will instead by routed straight to/, that is, theindex.htmlfile.

+
+ +

Putting it all together in the sample project, the webpack configuration file will look like this:

+ +


+module.exports = {
+  devtool: 'eval-source-map',
+
+  entry:  __dirname + "/app/main.js",
+  output: {
+    path: __dirname + "/public",
+    filename: "bundle.js"
+  },
+
+  devServer: {
+    contentBase: "./public",
+    colors: true,
+    historyApiFallback: true,
+    inline: true
+  } 
+}
+      

+ +

Instead of running the webpack command, now you will execute the "webpack-dev-server" to start the server:

+ +

node_modules/.bin/webpack-dev-server

+ +

For convenience, you can edit the "scripts" section in your project's package.json file to run the server by invoking "npm start", as shown below (remember that it’s not necessary to fill the complete path to “node_modules/.bin” inside the scripts section):

+ +


+{
+  "name": "webpack-sample-project",
+  "version": "1.0.0",
+  "description": "Sample webpack project",
+  "scripts": {
+    "start": "webpack-dev-server --progress"
+  },
+  "author": "Cássio Zen",
+  "license": "ISC",
+  "devDependencies": {
+    "webpack": "^1.12.9",
+    "webpack-dev-server": "^1.14.0"
+  }
+}
+      

+ +
+

Tip: The "--progress" parameter is only available in the command line. It shows a progress indicator in the terminal during the build step.

+
+ + + +
+ + + +

Loaders

+ +

One of the most exciting features of Webpack are loaders. Through the use of loaders, webpack can preprocess the source files through external scripts and tools as it loads them to apply all kinds of changes and transformations. These transformations are useful in many circumstances, for example for parsing JSON files into plain JavaScript or turning next generation's JavaScript code into regular JavaScript that current browsers can understand (so you can use next generation features today). Loaders are also essential for React development, as they can be used to transform React's JSX into plain JavaScript.

+ +

Loaders need to be installed separately and should be configured under the "modules" key in webpack.config.js. Loader configuration setting include: +

+

+ +

To exemplify, let's change our sample application and move the greeting text to a separate Json configuration file. Start by installing Webpack's json loader module:

+ +

npm install --save-dev json-loader

+ +

Next, edit the webpack configuration file to add the JSON loader:

+ +


+module.exports = {
+  devtool: 'eval-source-map',
+
+  entry:  __dirname + "/app/main.js",
+  output: {
+    path: __dirname + "/public",
+    filename: "bundle.js"
+  },
+
+  module: {
+    loaders: [
+      {
+        test: /\.json$/,
+        loader: "json"
+      }
+    ]
+  },
+
+  devServer: {
+    contentBase: "./public",
+    colors: true,
+    historyApiFallback: true,
+    inline: true
+  }
+}
+      

+ +

Finally, let's create a config.json file and require it inside the Greeter module. The source code for the new config.json file is shown below:

+


+{
+  "greetText": "Hi there and greetings from JSON!"
+}
+      

+ +

The updated Greeter.js:

+


+var config = require('./config.json');
+
+module.exports = function() {
+  var greet = document.createElement('div');
+  greet.textContent = config.greetText;
+  return greet;
+};
+      

+ + + +

Babel

+ +

Babel is a platform for JavaScript compilation and tooling. It's a powerful tool that, among other things, let you: +

+

+ +

Babel is a stand alone tool, but it can be used as a loader and pair very well with Webpack.

+ + + +

Installation and configuration

+ +

Babel is modular and distributed in different npm modules. The core functionality is available in the "babel-core" npm package, the integration with webpack is available through the "babel-loader" npm package, and for every type of feature and extensions you want to make available to your code, you will need to install a separate package (the most common are babel-preset-es2015 and babel-preset-react, for compiling ES6 and React's JSX, respectively).

+ +

To install all at once as development dependencies, you can use:

+ +

npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-react

+ +

Like any webpack loader, babel can be configured in the modules section of the webpack configuration file. You can see below the updated webpack.config.js for the sample project with the added babel loader.

+ + +


+module.exports = {
+  devtool: 'eval-source-map',
+
+  entry:  __dirname + "/app/main.js",
+  output: {
+    path: __dirname + "/public",
+    filename: "bundle.js"
+  },
+
+  module: {
+    loaders: [
+      {
+        test: /\.json$/,
+        loader: "json"
+      },
+      {
+        test: /\.js$/,
+        exclude: /node_modules/,
+        loader: 'babel',
+        query: {
+          presets: ['es2015','react']
+        }
+      }
+    ]
+  },
+
+  devServer: {
+    contentBase: "./public",
+    colors: true,
+    historyApiFallback: true,
+    inline: true
+  }
+}
+      

+ +

Now that your webpack configuration makes it possible to use ES6 modules and syntax, as well as JSX, let's refactor the sample project to make use of these features. Start by installing React and React-DOM:

+ +

npm install --save react react-dom

+ + +

Next, update the Greeter source file to use ES6 module definition and return a React component, as show below:

+ +


+import React, {Component} from 'react'
+import config from './config.json';
+
+class Greeter extends Component{
+  render() {
+    return (
+      <div>
+        {config.greetText}
+      </div>
+    );
+  }
+}
+
+export default Greeter
+    

+ +

Finally, you will update the main.js file to use ES6 modules definition and to render the greeter react component:

+ +


+import React from 'react';
+import {render} from 'react-dom';
+import Greeter from './Greeter';
+
+render(<Greeter />, document.getElementById('root'));
+      

+ + +

Babel configuration file

+ +

Babel can be entirely configured within webpack.config.js, but since it has many configuration settings, options and combinations, it can quickly get cumbersome to handle everything in the same file. For this reason, many developers opt to create a separate babel resource configuration - namely, a ".babelrc" file (with a leading dot).

+ +

The only babel-specific configuration we have in place so far is the presets definition - which may not justify the creation of a babel-specific configuration file. But since additional webpack and babel features will be covered in the following topics of this appendix, let's take the opportunity to create it right now. First, remove the presets configuration from the webpack.config.js file, leaving only the basic loader setup:

+ +


+module.exports = {
+  devtool: 'eval-source-map',
+
+  entry:  __dirname + "/app/main.js",
+  output: {
+    path: __dirname + "/public",
+    filename: "bundle.js"
+  },
+
+  module: {
+    loaders: [
+      {
+        test: /\.json$/,
+        loader: "json"
+      },
+      {
+        test: /\.js$/,
+        exclude: /node_modules/,
+        loader: 'babel'
+      }
+    ]
+  },
+
+  devServer: {...} // Omitted for brevity
+}
+      

+ +

In sequence, create a file named ".babelrc", which will contain the babel's presets configuration:

+


+{
+  "presets": ["react", "es2015"]
+}
+      

+ + +
+ +

Beyond JavaScript

+ +

One of Webpack's most unique characteristics is that it can treat every kind of file as a module - Not only your JavaScript code, but also CSS, fonts - with the appropriate loaders, all can be treated as modules. Webpack can follow @import and URL values in CSS through all dependency three and then then build, preprocess and bundle your assets.

+ + + +

Stylesheets

+ +

Webpack provides two loaders to deal with stylesheets: css-loader and style-loader. Each loader deals with different tasks: While the css-loader looks for @import and url statements and resolves them, the style-loader adds all the computed style rules into the page. Combined together, these loaders enable you to embed stylesheets into a Webpack JavaScript bundle.

+ +

To demonstrate, let's setup the css-loader and the style-loader on the sample project. Start by installing both css-loader and style-loader with npm:

+ +

npm install --save-dev style-loader css-loader

+ +

In sequence, update the webpack configuration file, as shown below:

+ +


+module.exports = {
+  devtool: 'eval-source-map',
+
+  entry:  __dirname + "/app/main.js",
+  output: {
+    path: __dirname + "/build",
+    filename: "bundle.js"
+  },
+
+  module: {
+    loaders: [
+      {
+        test: /\.json$/,
+        loader: "json"
+      },
+      {
+        test: /\.js$/,
+        exclude: /node_modules/,
+        loader: 'babel'
+      },
+      {
+        test: /\.css$/,
+        loader: 'style!css'
+      }
+    ]
+  },
+
+  devServer: {...}
+}
+      

+ +
+

Note: The exclamation point ("!") can be used in a loader configuration to chain different loaders to the same file types.

+
+ +

Next, create a new "main.css" file in your application folder. It will contain some simple rules to define better defaults for an application: +

+

+ +

The source code for the new main.css file would be something like this:

+ +


+html {
+  box-sizing: border-box;
+  -ms-text-size-adjust: 100%;
+  -webkit-text-size-adjust: 100%;
+}
+
+*, *:before, *:after {
+  box-sizing: inherit;
+}
+
+body {
+  margin: 0;
+  font-family: 'Helvetica Neue', Helvetica, Arial, sans-serif;
+}
+
+h1, h2, h3, h4, h5, h6, p, ul {
+  margin: 0;
+  padding: 0;
+}
+      

+ +

Finally, remember that Webpack starts on an entry file defined in the configuration file and build all the dependency three by following statements like import, require, url among others. This means that your main CSS file must also be imported somewhere in the application in order for webpack to "find" it. In the sample project, let's import the main.css from the main.js entry point:

+ +


+import React from 'react';
+import {render} from 'react-dom';
+import Greeter from './Greeter';
+
+import './main.css';
+
+render(<Greeter />, document.getElementById('root'));
+      

+ +
+

Note: By default, your css rules will be bundled together with the JavaScript file - It wont generate a separate css bundled file. This is great during development, and later in this appendix you will learn how to setup Webpack to create a separate css file for production.

+
+ +

CSS Modules

+ +

In the past few years, JavaScript development has changed significantly with new language features, better tooling and established best practices (such as modules).

+ +

Modules let the developer break the code down into small, clean and independent units with explicitly declared dependencies. Backed by an optimization tool, the dependency management and load order are automatically resolved.

+ +

But while JavaScript development evolved, most stylesheets are still monolithic and full of global declarations that make new implementations and maintenance overly difficult and complex.

+ +

A recent project called CSS modules aim to bring all these advantages to CSS. With CSS modules, all class names and animation names are scoped locally by default.Webpack embraced the CSS modules proposal from the very beginning, it's built in the CSS loader - all you have to do is activate it by passing the "modules" query string. With this feature enabled, you will be able to export class names from CSS into the consuming component code, locally scoped (so you don't need to worry about having many classes with the same name across different components).

+ +

Let's see this in practice in the sample application. Edit the webpack.config.js to enable CSS Modules (as shown below).

+ +


+module.exports = {
+  devtool: 'eval-source-map',
+
+  entry:  __dirname + "/app/main.js",
+  output: {...},
+
+  module: {
+    loaders: [
+      {
+        test: /\.json$/,
+        loader: "json"
+      },
+      {
+        test: /\.js$/,
+        exclude: /node_modules/,
+        loader: 'babel'
+      },
+      {
+        test: /\.css$/,
+        loader: 'style!css?modules'
+      }
+    ]
+  },
+
+  devServer: {...}
+}
+      

+ +

Next, let's create a CSS file (with style rules that will be used exclusively in the Greeter component) and import those rules in the Greeter.js React module. The new greeter.css file is shown below:

+ +


+.root {
+  background-color: #eee;
+  padding: 10px;
+  border: 3px solid #ccc;
+}
+      

+ +

The updated Greeter.js will look like this:

+ +


+import React, {Component} from 'react';
+import config from './config.json';
+import styles from './Greeter.css';
+
+class Greeter extends Component{
+  render() {
+    return (
+      <div className={styles.root}>
+        {config.greetText}
+      </div>
+    );
+  }
+}
+
+export default Greeter
+      

+ +

Notice in the code above how the css classes were imported into a variable (styles) and are individually applied to a JSX element.

+ +

Also notice that any other component with it's own separate CSS module can also use the same class names without interference: Even highly common style names such as "root", "header", "footer", just to name a few, can now be used safely in local scope.

+ +

CSS modules is a huge theme, with many more features available. Getting deeper in CSS Modules is out of the scope of this appendix, but you can learn more on the official documentation on GitHub.

+ + +

CSS Processors

+ +

CSS Preprocessors such as Sass and Less are extensions to the original CSS format. They let you write CSS using features that don't exist in CSS like variables, nesting, mixins, inheritance etc. In a concept akin to writing JavaScript ES6 with JSX and letting Babel compile the code to regular JavaScript, CSS processors use a program to convert the special features of the languages into plain CSS that browsers can understand.

+ +

As you may imagine, you can use Loaders to have Webpack take care of this process. There are Webpack loaders available for most commonly used CSS preprocessors: +

+

+ +

A new trend for a more flexible CSS workflow is the usage of PostCSS. Instead of having a complete, fixed set of CSS language extensions, PostCSS is actually a tool for CSS transformation: It let's you connect individual plugins that applies different transformations on your CSS. You can learn more about PostCSS and the available plugins in the project's site.

+ +

To exemplify, let's setup the PostCSS loader with the autoprefixer plugin (which adds vendor prefixes to your CSS) - The use PostCSS with auto prefixing combined with CSS modules is a powerful combination for React projects. Start by installing the PostCSS and the Autoprefixer plugin using npm:

+ + +

npm install --save-dev postcss-loader autoprefixer

+ +

Next, add postcss as a new loader for CSS file formats and create a new section on your webpack configuration to setup which postcss plugins you want to use (in this case, only the Autoprefixer):

+ +


+module.exports = {
+  devtool: 'eval-source-map',
+  entry: __dirname + "/app/main.js",
+  output: {...},
+
+  module: {
+    loaders: [
+      {
+        test: /\.json$/,
+        loader: "json"
+      },
+      {
+        test: /\.js$/,
+        exclude: /node_modules/,
+        loader: 'babel'
+      },
+      {
+        test: /\.css$/,
+        loader: 'style!css?modules!postcss'
+      }
+    ]
+  },
+
+  postcss: [
+    require('autoprefixer')
+  ],
+
+  devServer: {...}
+}
+      

+ + +
+ + +

Plugins

+ +

Webpack can be extended through plugins. In Webpack, plugins have the ability to inject themselves into the build process to introduce custom behaviors.

+ +

Loaders and plugins are commonly confused with each other, but they are completely different things. Roughly speaking, loaders deal with each source file, one at a time, as they are "loaded" by webpack during the build process. Plugins in the other hand do not operate on individual source files: they influence the build process as a whole.

+ +

Webpack comes with many built-in plugins, but there are lots of third party plugins available.

+ +

In this topic we will investigate some of the most used and that have the most impact in development experience plugins.

+ + + +

Using Plugins

+ +

To use a plugin, install it using npm (if it's not built-in), import the plugin in the webpack configuration file and add an instance of the plugin object to an "plugins" array.

+ +

To exemplify, let's get started with a very simple built-in plugin: the bannerPlugin. Its purpose is to add any given string to the top of the generated bundle file (useful, for example, to add copyright notices to your project's bundled JavaScript.).

+ +

Since it's a built-in plugin, we can simply import the whole "webpack" module, and add a new "plugins" array. You can see below the updated webpack.config.js with the bannerPlugin setup.

+ +


+var webpack = require('webpack');
+
+module.exports = {
+  devtool: 'eval-source-map',
+  entry:  __dirname + "/app/main.js",
+  output: {...},
+
+  module: {
+    loaders: [
+      { test: /\.json$/, loader: "json" },
+      { test: /\.js$/, exclude: /node_modules/, loader: 'babel' },
+      { test: /\.css$/, loader: 'style!css?modules!postcss' }
+    ]
+  },
+  postcss: [
+    require('autoprefixer')
+  ],
+
+  plugins: [
+    new webpack.BannerPlugin("Copyright Flying Unicorns inc.")
+  ],
+
+  devServer: {...}
+}
+  

+ + +

With this plugin, the bundled JavaScript file would look something like this:

+ + + + + + +

HtmlWebpackPlugin

+ +

Among third party webpack plugins, one of the most useful is the HtmlWebpackPlugin.

+ +

The plugin will generate the final HTML5 file for you and include all your webpack bundles. This is especially useful for production builds (covered in next topics), where hashes that change on every compilation are added to bundle filenames (It may sound small, but it can simplify the project structure and save developer's time and effort).

+ +

Start by installing the HtmlWebpackPlugin using npm:

+ +

npm install --save-dev html-webpack-plugin

+ +

Next, you will have to do some modifications in the project structure:

+ +
    +
  1. Remove the public folder. Since the HTML5 page will be automatically generated, the index.html file you created manually in the public folder can be deleted. Furthermore, since you're also bundling CSS with Webpack, the whole public folder won't be necessary anymore. You can go ahead and remove the public folder entirely.
  2. +
  3. Create a template HTML file. Instead of manually creating the final HTML page that will contain the application, you will create a template html file in the "app" folder. The template page will contain all the custom title, head tags and any other html elements you need, and during the build process the html-webpack-plugin will use this template as the basis for the generated html page, automatically injecting all necessary css, js, manifest and favicon files into the markup. The file will be named "index.tmpl.html", and its source code is shown below: +
    
    +<!DOCTYPE html>
    +<html lang="en">
    +  <head>
    +    <meta charset="utf-8">
    +    <title>Webpack Sample Project</title>
    +  </head>
    +  <body>
    +    <div id='root'>
    +    </div>
    +  </body>
    +</html>
    +          
    +
  4. +
  5. Update the webpack configuration: Setup the HTMLWebpackPlugin and a new build folder. Require the html-webpack-plugin package and add an instance to the plugins array. Also, since the "public" folder is gone, you will need to update the output setting to build and serve the bundled files from a different folder - commonly a "build" folder: +
    
    +var webpack = require('webpack');
    +var HtmlWebpackPlugin = require('html-webpack-plugin');
    +
    +module.exports = {
    +  devtool: 'eval-source-map',
    +
    +  entry:  __dirname + "/app/main.js",
    +  output: {
    +    path: __dirname + "/build",
    +    filename: "bundle.js"
    +  },
    +
    +  module: {
    +    loaders: [
    +      { test: /\.json$/, loader: "json" },
    +      { test: /\.js$/, exclude: /node_modules/, loader: 'babel' },
    +      { test: /\.css$/, loader: 'style!css?modules!postcss' }
    +    ]
    +  },
    +  postcss: [
    +    require('autoprefixer')
    +  ],
    +
    +  plugins: [
    +    new HtmlWebpackPlugin({
    +      template: __dirname + "/app/index.tmpl.html"
    +    })
    +  ],
    +
    +  devServer: {
    +    colors: true,
    +    historyApiFallback: true,
    +    inline: true
    +  }
    +}
    +          
    +
  6. +
+ +
+

Note: The build folder wont be created until we make a production deploy configuration. While in development, all the bundled files and the generated HTML will be served from memory.

+
+ + + +

Hot Module Replacement

+ +

One characteristic for which Webpack is renowned for is Hot Module Replacement. Hot Module Replacement (or HMR for short) gives the ability to tweak your components in real time - any changes in the CSS and JS get reflected in the browser instantly without refreshing the page. In other words, thecurrent application state persistseven when you change something in the underlying code.

+ +

Enabling HMR in Webpack is simple, you will need to make two configurations: +

    +
  1. Add the HotModuleReplacementPlugin to webpack's configuration.
  2. +
  3. Add the "hot" parameter to the Webpack Dev Server configuration.
  4. +
+

+ +

What's complicated is that your JavaScript modules won't be automatically eligible for hot replacement. Webpack provides an API which you need to implement in your JavaScript modules in order to allow them to be hot replaceable. Although this API isn't difficult to use, there is a more practical way: Using Babel.

+ +

As you've seen, Babel woks together with Webpack and its job is to transform JavaScript files. Currently, in the sample project, it's configured to transform JSX into plain JavaScript calls and ES6 code into JavaScript that browsers can understand today. With the use of a Babel plugin, it is possible to use Webpack to make an additional transformation and add all needed code into your React components to make them hot-replaceable.

+ +

This whole setup does sound convoluted and confusing, so to put it straight: +

+

+ +

Let's update the sample project you've been working on to enable automatic React components hot replacement. Starting with the Webpack configuration, shown below:

+ +


+var webpack = require('webpack');
+var HtmlWebpackPlugin = require('html-webpack-plugin');
+
+module.exports = {
+  devtool: 'eval-source-map',
+  entry: __dirname + "/app/main.js",
+  output: {
+    path: __dirname + "/build",
+    filename: "bundle.js"
+  },
+
+  module: {
+    loaders: [
+      { test: /\.json$/, loader: "json" },
+      { test: /\.js$/, exclude: /node_modules/, loader: 'babel' },
+      { test: /\.css$/, loader: 'style!css?modules!postcss' }
+    ]
+  },
+  postcss: [
+    require('autoprefixer')
+  ],
+
+  plugins: [
+    new HtmlWebpackPlugin({
+      template: __dirname + "/app/index.tmpl.html"
+    }),
+    new webpack.HotModuleReplacementPlugin()
+  ],
+
+  devServer: {
+    colors: true,
+    historyApiFallback: true,
+    inline: true,
+    hot: true
+  }
+}
+      

+ +

Next, let's take care of Babel. Install the required Babel plugins with npm:

+ +

npm install --save-dev babel-plugin-react-transform react-transform-hmr

+ +

Then, edit the .babelrc configuration file to setup the plugins:

+ +


+{
+  "presets": ["react", "es2015"],
+  "env": {
+    "development": {
+    "plugins": [["react-transform", {
+       "transforms": [{
+         "transform": "react-transform-hmr",
+         // if you use React Native, pass "react-native" instead:
+         "imports": ["react"],
+         // this is important for Webpack HMR:
+         "locals": ["module"]
+       }]
+       // note: you can put more transforms into array
+       // this is just one of them!
+     }]]
+    }
+  }
+}
+      

+ +

Try running the server again and make some tweaks in the Greeter module - changes will be reflected instantly on the browser without refreshing.

+ + + +
+ +

Building for production

+ +

So far you've created a complete development environment using Webpack to bundle and process your project's files. For a production-ready build, you will want some additional processing in you bundle file, including some characteristics like optimization and minification, caching and separation from css and JavaScript files.

+ +

In the Pro React's basic React boilerplate, both development and build configurations were set on a single configuration file (webpack.config.js). For projects with more complete or complex setups, splitting the webpack configuration in multiple files is a good practice to keep everything more organized. In your sample project, create a new file named "webpack.production.config.js" and fill it with some basic setup.

+ +

This is the very basic configuration needed for your project. Notice that it's very similar to the original Webpack development configuration (webpack.config.js), with stripped devtool, devServer and Hot Module Replacement configurations:

+ +


+var webpack = require('webpack');
+var HtmlWebpackPlugin = require('html-webpack-plugin');
+
+module.exports = {
+  entry: __dirname + "/app/main.js",
+  output: {
+    path: __dirname + "/build",
+    filename: "bundle.js"
+  },
+
+  module: {
+    loaders: [
+      {
+        test: /\.json$/,
+        loader: "json"
+      },
+      {
+        test: /\.js$/,
+        exclude: /node_modules/,
+        loader: 'babel'
+      },
+      {
+        test: /\.css$/,
+        loader: 'style!css?modules!postcss'
+      }
+    ]
+  },
+  postcss: [
+    require('autoprefixer')
+  ],
+
+  plugins: [
+    new HtmlWebpackPlugin({
+      template: __dirname + "/app/index.tmpl.html"
+    }),
+  ],
+
+}
+      

+ +

In sequence, edit the package.json file to create a new build task, which will run Webpack in production environment and assign the newly created configuration file:

+ +


+{
+  "name": "webpack-sample-project",
+  "version": "1.0.0",
+  "description": "Sample webpack project",
+  "scripts": {
+    "start": "webpack-dev-server --progress",
+    "build": "NODE_ENV=production webpack --config ./webpack.production.config.js --progress"
+  },
+  "author": "Cássio Zen",
+  "license": "ISC",
+  "devDependencies": {...},
+  "dependencies": {...}
+}
+      

+ + + + + +

Optimization Plugins

+ +

Webpack comes with some very useful optimization plugins for generating a production-ready build. Many others were made by the community and are available through npm. All the desired characteristics of a production build mentioned above can be achieved through the use of the following Webpack plugins: +

+

+ +

Let's add all those plugins to our newly created webpack.production.config.js file. Both OccurenceOrder and UglifyJS plugins are built-in, so you will only need to install and require the ExtractText plugin:

+ +

npm install --save-dev extract-text-webpack-plugin

+ +

The updated webpack.production.config.js will look like this:

+ +


+var webpack = require('webpack');
+var HtmlWebpackPlugin = require('html-webpack-plugin');
+var ExtractTextPlugin = require('extract-text-webpack-plugin');
+
+module.exports = {
+  entry: __dirname + "/app/main.js",
+  output: {
+    path: __dirname + "/build",
+    filename: "bundle.js"
+  },
+
+  module: {
+    loaders: [
+      {
+        test: /\.json$/,
+        loader: "json"
+      },
+      {
+        test: /\.js$/,
+        exclude: /node_modules/,
+        loader: 'babel'
+      },
+      {
+        test: /\.css$/,
+        loader: ExtractTextPlugin.extract('style', 'css?modules!postcss')
+      }
+    ]
+  },
+  postcss: [
+    require('autoprefixer')
+  ],
+
+  plugins: [
+    new HtmlWebpackPlugin({
+      template: __dirname + "/app/index.tmpl.html"
+    }),
+    new webpack.optimize.OccurenceOrderPlugin(),
+    new webpack.optimize.UglifyJsPlugin(),
+    new ExtractTextPlugin("style.css")
+  ]
+}
+      

+ +

Caching

+ +

Modern Internet infrastructure embraces caching everywhere (At CDNs, ISPs, networking equipment, web browsers...), and one simple and effective way to leverage long-term caching in this infrastructure is making sure that your file names are unique and based on their content (that is, if the file content changes, the file name should change too). This way, remote clients can keep their own copy of the content and only request a new one when it's a different file name.

+ +

Webpack can add hashes for the bundled files to their filename, simply by adding special string combinations such as [name], [id] and [hash] to the output file name configuration. The updated Webpack production config using hashes on both the JavaScript and CSS bundled files is shown below:

+ +


+var webpack = require('webpack');
+var HtmlWebpackPlugin = require('html-webpack-plugin');
+var ExtractTextPlugin = require('extract-text-webpack-plugin');
+
+module.exports = {
+  entry: __dirname + "/app/main.js",
+  output: {
+    path: __dirname + "/build",
+    filename: "[name]-[hash].js"
+  },
+
+  module: {
+    loaders: [
+      {
+        test: /\.json$/,
+        loader: "json"
+      },
+      {
+        test: /\.js$/,
+        exclude: /node_modules/,
+        loader: 'babel'
+      },
+      {
+        test: /\.css$/,
+        loader: ExtractTextPlugin.extract('style', 'css?modules!postcss')
+      }
+    ]
+  },
+  postcss: [
+    require('autoprefixer')
+  ],
+
+  plugins: [
+    new HtmlWebpackPlugin({
+      template: __dirname + "/app/index.tmpl.html"
+    }),
+    new webpack.optimize.OccurenceOrderPlugin(),
+    new webpack.optimize.UglifyJsPlugin(),
+    new ExtractTextPlugin("[name]-[hash].css")
+  ]
+}
+      

+ +
+ +

Summary

+ +

Webpack is an amazing tool for processing and bundling together all of your project modules. It is the de facto tool in the React community, and in this appendix you learned how to properly configure it and how to use loaders and plugins to create a better development experience.

+
+
+ + + + + + + + + diff --git a/materials/appendixA/main.js b/materials/appendixA/main.js new file mode 100644 index 0000000..7594729 --- /dev/null +++ b/materials/appendixA/main.js @@ -0,0 +1,82 @@ +var navVisible = false; +$('#menu').click(function(e){ + if(navVisible){ + navVisible = false; + $('nav').removeClass('open'); + } else { + navVisible = true; + $('nav').addClass('open'); + } +}); + +$('main').click(function(e){ + if(navVisible){ + navVisible = false; + $('nav').removeClass('open'); + } +}); + +var resizing = false; +$(window).on('resize', function(){ + if( !resizing ) { + window.requestAnimationFrame(moveNavigation); + resizing = true; + } +}); + + +function moveNavigation(){ + if($(window).width()>1023){ + $('nav').removeClass('open'); + navVisible = false; + + } + resizing = false; +} + + + +// Cache selectors +var lastId, + menu = $("#menu-items"), + // All list items + menuItems = menu.find("a"), + // Anchors corresponding to menu items + scrollItems = menuItems.map(function(){ + var item = $($(this).attr("href")); + if (item.length) { return item; } + }); + +// Bind click handler to menu items +// so we can get a fancy scroll animation +menuItems.click(function(e){ + var href = $(this).attr("href"), + offsetTop = href === "#" ? 0 : $(href).offset().top+1; + $('html, body').stop().animate({ + scrollTop: offsetTop + }, 300); + e.preventDefault(); +}); + +// Bind to scroll +$(window).scroll(function(){ + // Get container scroll position + var fromTop = $(this).scrollTop(); + + // Get id of current scroll item + var cur = scrollItems.map(function(){ + if ($(this).offset().top < fromTop + 100) + return this; + }); + // Get the id of the current element + cur = cur[cur.length-1]; + var id = cur && cur.length ? cur[0].id : ""; + + if (lastId !== id) { + lastId = id; + // Set/remove active class + menuItems + .parent().removeClass("active") + .end().filter("[href=#"+id+"]").parent().addClass("active"); + } +}); diff --git a/materials/appendixA/styles.css b/materials/appendixA/styles.css new file mode 100644 index 0000000..3472173 --- /dev/null +++ b/materials/appendixA/styles.css @@ -0,0 +1,333 @@ +/* + * 1. apply a natural box layout model to all elements, + * but allowing components to change + * 2. Prevent iOS and IE text size adjust after device orientation + * change, without disabling user zoom. + */ +html { + box-sizing: border-box; + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100%; +} +*, *:before, *:after { + box-sizing: inherit; +} + +/* + * Remove default margin and set default font family to sans-serif. + */ +body { + margin: 0; +} + + +/* + * Address style set to `bolder` in Firefox, Safari, and Chrome. + */ +strong { + font-weight: bold; +} + +/* + * Remove inner padding and border in Firefox + */ +::-moz-focus-inner { + padding: 0; + border: 0; +} + +/* + * 1. For responsive web development, makes sure images respect the bounds + * of a fluid container. + * 2. The image's aspect ratio is preserved even if it has an inline height set. + * 3. Fixes images within links gaining a border in IE 10. + */ +img { + max-width: 100%; + height: auto; + border: 0; +} + +/* + * Custom Styles + */ + + h1 { + font-family: 'Montserrat', "Lucida Grande","Lucida Sans Unicode","Lucida Sans",Geneva,Verdana,sans-serif; + font-weight: 700; + font-style: normal; + font-size: 34px; + line-height: 1.15; + margin-top: 25px; + } + +h2 { + font-family: 'Montserrat', "Lucida Grande","Lucida Sans Unicode","Lucida Sans",Geneva,Verdana,sans-serif; + font-weight: 700; + font-style: normal; + font-size: 28px; + margin-top: 45px; +} + +h3 { + font-family: 'Montserrat', "Lucida Grande","Lucida Sans Unicode","Lucida Sans",Geneva,Verdana,sans-serif; + font-weight: 700; + font-style: normal; + font-size: 23px; + color: #222222; + margin-top: 45px; +} + +h4 { + font-family: 'Montserrat', "Lucida Grande","Lucida Sans Unicode","Lucida Sans",Geneva,Verdana,sans-serif; + font-weight: 700; + font-style: normal; + font-size: 18px; + color: #333333; + margin-top: 45px; +} + +hr { + margin-top: 52px; + margin-bottom: 45px; + display: block; + border: 0; + text-align: center; + box-sizing: content-box; + height: 0; +} + +hr:before { + font-family: Georgia,Cambria,"Times New Roman",Times,serif; + font-weight: 400; + font-style: italic; + font-size: 28px; + letter-spacing: 0.6em; + content: '...'; + display: inline-block; + margin-left: 0.6em; + color: rgba(0,0,0,0.6); + position: relative; + top: -30px; +} + +p, li{ + font-family: 'Neuton', Georgia,Cambria,"Times New Roman",Times,serif; + font-weight: 400; + font-style: normal; + font-size: 18px; + line-height: 1.3; +} + +header { + display: none; + height: 40px; + position: relative; +} + +header button { + border: none; + background: none; + color: #fff; + font-size: 25px; + width: 32px; + padding: 0; + position: absolute; + top: 54%; + transform: translateY(-50%); +} +header button:focus {outline:0;} + +header button svg { + fill: #ffffff; +} + +header span{ + display: block; + position: absolute; + top: 25%; + transform: translateY(-50%); + left: 50%; + transform: translateX(-50%); + font-family: 'Montserrat', "Lucida Grande","Lucida Sans Unicode","Lucida Sans",Geneva,Verdana,sans-serif; + font-weight: 400; + font-style: normal; + font-size: 16px; + color: #fff; + white-space: nowrap; +} + +main { + width: calc(100% - 270px); + margin-left: 270px; +} + +#content { + max-width: 800px; + margin: auto; + padding: 1px 10px 10px 10px; +} + +nav { + position: fixed; + width: 270px; + background-color: #f2f2f2; + height: 100%; + padding: 10px; + overflow-y: scroll; + border-right: solid 2px #e0e0e0; +} + +@media only screen +and (max-width : 1023px) { + header { + display: block; + position: fixed; + width: 100%; + background-color: #f3bb22; + padding-left: 8px; + z-index: 10; + } + + nav { + margin-top: 40px; + transform: translateX(-100%); + transition: transform .5s; + z-index: 9; + } + + nav.open { + transform: translateX(0) + } + + main { + margin-left: 0px; + width: 100%; + } + + #content { + max-width: 800px; + margin: auto; + padding: 40px 10px 10px 10px; + } + + /* Force table to not be like tables anymore */ + table, thead, tbody, th, td, tr { + display: block; + } + + /* Hide table headers (but not display: none;, for accessibility) */ + thead tr { + position: absolute; + top: -9999px; + left: -9999px; + } + + tr { border: 1px solid #ccc; } + + td { + /* Behave like a "row" */ + border: none; + border-bottom: 1px solid #eee; + position: relative; + } + + td:before { + /* Now like a table header */ + position: absolute; + /* Top/left values mimic padding */ + top: 6px; + left: 6px; + width: 45%; + padding-right: 10px; + white-space: nowrap; + } + +} + +nav #menu-items { + padding: 10px; +} + +nav a { + color: #555; + text-decoration: none; +} + +nav a:hover { + color: #888; + text-decoration: underline; +} + +nav img { + margin: 10px 0 0 50px; + +} + +nav h1 { + font-size: 18px; + text-align: center; + margin-top: 10px; +} + +nav ul { + padding-left: 5px; +} + +nav li { + list-style-type: none; + font-family: 'Montserrat', "Lucida Grande","Lucida Sans Unicode","Lucida Sans",Geneva,Verdana,sans-serif; + font-size: 14px; +} + +nav li.active a{ + color: #993333; + font-weight: bold; +} + +nav li ul li{ + font-size: 0.85em; + color: #333; +} + +nav li ul li:last-child{ + margin-bottom: 10px; +} + +img { + margin: 10px 0; +} + +pre { + font-size: 13px; +} + +table { + border-top: solid 1px #000; + border-bottom: solid 1px #000; +} + +table p { + margin: 5px; +} + +th { + border-bottom: solid 1px #000; +} + +.code-caption { + font-style: italic; +} + +.note { + margin: 2px 0 2px 0; + border-top: solid 2px #999; + border-bottom: solid 2px #999; + padding: 5px 10px; + margin: 25px 10px; +} + +.note p { + font-family: 'Montserrat', "Lucida Grande","Lucida Sans Unicode","Lucida Sans",Geneva,Verdana,sans-serif; + font-size: 15px; +} diff --git a/materials/appendixB.pdf b/materials/appendixB.pdf new file mode 100644 index 0000000..d8de5bb Binary files /dev/null and b/materials/appendixB.pdf differ diff --git a/materials/ch06-alt-redux.pdf b/materials/ch06-alt-redux.pdf new file mode 100644 index 0000000..35203fb Binary files /dev/null and b/materials/ch06-alt-redux.pdf differ diff --git a/materials/index.html b/materials/index.html index eac629e..5d96227 100755 --- a/materials/index.html +++ b/materials/index.html @@ -1,93 +1,105 @@ - - - - - - -Pro React - Online Materials - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- -
- - - - - - -
-
- -
-
- -

Online Materials

-

-

Book Source Code

-

Appendice A: WebPack Coming soon

-

Appendice B: JavaScript ES2015 Coming soon

-

Appendice C: Functional JavaScript Coming soon

-
-
- -
-
- - - - - - - - + + + + + + +Pro React - Online Materials + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ +
+ + + + + + +
+
+ +
+
+ +

Online Materials

+

+

Book Source Code

+

Alternative Chapter 6 (Using Redux instead of Flux) PDF (Beta)

+

Appendix A: WebPack PDF | Web

+

Appendix B: JavaScript ES2015 PDF

+

Appendix C: Functional JavaScript Coming soon

+ +
+
+ +
+
+ + + + + + + + + diff --git a/preview.html b/preview.html index 8e4ddf4..ce1901e 100644 --- a/preview.html +++ b/preview.html @@ -28,6 +28,7 @@ + diff --git a/sample/8.png b/sample/8.png new file mode 100644 index 0000000..ebcc447 Binary files /dev/null and b/sample/8.png differ