diff --git a/CHANGELOG.md b/CHANGELOG.md index bc67dbc8c..df35a3ab5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,12 +12,12 @@ ## Commits - [commit](http://github.com/electrode-io/electrode/commit/5b55a8dbdeed46752a3fa47a58e7df24fd53bf07) add config for mocha tests with es6 -- [commit](http://github.com/electrode-io/electrode/commit/b2cf439c20794e54acb37f772edda375b30e701b) format gulpefile.js +- [commit](http://github.com/electrode-io/electrode/commit/b2cf439c20794e54acb37f772edda375b30e701b) format clap.js - [commit](http://github.com/electrode-io/electrode/commit/6b3d49054c738c1f12d681cfc78ae74fe1ee31c8) ignore lerna no updating error - [commit](http://github.com/electrode-io/electrode/commit/df369da6eff15744a56083d732d01f0699d4cdc5) update front facing README - [commit](http://github.com/electrode-io/electrode/commit/b848a3a0342e62d2fb217a31eeb3a7615bb5000d) archetype-react-component: [minor][chore]move configs to component dev (#356) - [commit](http://github.com/electrode-io/electrode/commit/87a6fb358da0199fd5f6f25c485621ec619fedc2) archetype-react-app-dev: [patch] add config for mocha tests with es6 (#373) -- [commit](http://github.com/electrode-io/electrode/commit/f51c1f7aa2f80566b63d6437dbe415ac0e55ef0a) archetype-react-app: [minor][chore] Modify gulp task based on flag (#371) +- [commit](http://github.com/electrode-io/electrode/commit/f51c1f7aa2f80566b63d6437dbe415ac0e55ef0a) archetype-react-app: [minor][chore] Modify clap task based on flag (#371) - [commit](http://github.com/electrode-io/electrode/commit/829ff161b60c58591726066f13e20bb2a07c6408) archetype-react-app: [patch][chore] format code - [commit](http://github.com/electrode-io/electrode/commit/6a85b4b72052464e3676c5bbf6f128a6e72feefa) archetype-react-app: [patch] use babel to optimize modules for PROD - [commit](http://github.com/electrode-io/electrode/commit/a184fff313d41758efcbd7db8d5b095495435fc0) archetype-react-app: [patch][chore] prettier format all code (#378) @@ -25,7 +25,7 @@ - [commit](http://github.com/electrode-io/electrode/commit/62b19038de1d715c6c09cc314ff73cecdaf93fae) archetype-react-app: [patch] log loading custom webpack config (#382) - [commit](http://github.com/electrode-io/electrode/commit/ed62e36d5a86925a62209d1eff1b8f8ebbbec8bc) (multiple): [patch][chore] update engines to node 8 (#379) - [commit](http://github.com/electrode-io/electrode/commit/b6284abb52a8055be8406ee71b042d1815631473) generator-electrode: [patch][bug] Add default classNames to components (#376) -- [commit](http://github.com/electrode-io/electrode/commit/d81593a99f1bf324fae6c83f597db74e7dbc462a) generator-electrode: [minor][chore] Set ES6 flag in gulpfile. (#374) +- [commit](http://github.com/electrode-io/electrode/commit/d81593a99f1bf324fae6c83f597db74e7dbc462a) generator-electrode: [minor][chore] Set ES6 flag in clap.js. (#374) - [commit](http://github.com/electrode-io/electrode/commit/da5e945b8f39ff5a6f5c64ef28bf2cb09afc5df9) generator-electrode: [patch][bug] Write all files before installing (#383) # 6/13/2017 @@ -56,7 +56,7 @@ - [commit](http://github.com/electrode-io/electrode/commit/c2111967faf138e28a244483a0abe96a4402793d) archetype-react-app: [patch] FIX DeprecationWarning: loaderUtils.parseQuery() received a non-strin… (#347) - [commit](http://github.com/electrode-io/electrode/commit/77f518601db3d0f96e29227adbb90f6755abd9f9) generator-electrode: Fix typo (#348) - [commit](http://github.com/electrode-io/electrode/commit/a61e45832b67ac9c4bfad58895cb1ec9c32498be) archetype-react-app: Add Prettier and precommit hook packages (#349) -- [commit](http://github.com/electrode-io/electrode/commit/b3c007a40258aabc32fc57cf99c53ddc8e2aa640) archetype-react-app: [patch] FIX gulp lint as it skips src/server files (#353) +- [commit](http://github.com/electrode-io/electrode/commit/b3c007a40258aabc32fc57cf99c53ddc8e2aa640) archetype-react-app: [patch] FIX clap lint as it skips src/server files (#353) - [commit](http://github.com/electrode-io/electrode/commit/2f16584b726b67407d97d5410ae7775ea1f98612) archetype-react-app: [patch] A Webpack plugin to optimize / minimize CSS assets. (#355) - [commit](http://github.com/electrode-io/electrode/commit/2155b4e4b01de078d7185c16dfbc1786533ff490) update docs links in README - [commit](http://github.com/electrode-io/electrode/commit/1066459dbcb1ac8159c06db01eefe84332e04359) archetype-react-app: [patch] fix webpack simple-progress output (#364) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index baf84dd3f..d697c5fc4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -8,10 +8,10 @@ There are [few guidelines](#contributing-guidelines) that we request contributor This repo uses [Lerna] as a top level setup. -- Install `gulp` command +- Install `clap` command ```bash -$ npm install -g gulp-cli +$ npm install -g xclap-cli ``` - Fork and clone the repo at @@ -28,7 +28,7 @@ Run: ```bash $ npm install $ npm run bootstrap -$ gulp samples-local +$ clap samples-local ``` - Now you can go to the `samples` folder, pick or create any samples, develop and test your changes over there. @@ -38,7 +38,7 @@ For example, run the `universal-react-node` samples in `dev` mode: ```bash $ cd samples/universal-react-node $ npm install -$ gulp dev +$ clap dev ``` After running above, you should see a similar text as `Hapi.js server running at http://m-C02SL0GSG8WM.local:3000` in command line. @@ -48,7 +48,7 @@ And when you open the browser at `http://localhost:3000`, you should see a large You can also run in `hot` mode. However, `hot` mode is still experimental and there are issues. ```bash -$ gulp hot +$ clap hot ``` ## Contributing Guidelines diff --git a/docs/chapter1/advanced/powerful-electrode-tools/electrode-explorer.md b/docs/chapter1/advanced/powerful-electrode-tools/electrode-explorer.md index dd8e3e136..2da9b95a1 100644 --- a/docs/chapter1/advanced/powerful-electrode-tools/electrode-explorer.md +++ b/docs/chapter1/advanced/powerful-electrode-tools/electrode-explorer.md @@ -12,116 +12,119 @@ ## Prerequisites -* node: ">=4.2.0" -* npm: ">=3.0.0" -* Github access token +- node: ">=4.2.0" +- npm: ">=3.0.0" +- Github access token ## Overview This is a central place where you can view -* demos of all the components under the organizations you specified -* documentation of your components -* dependencies your components have \(dependencies\) -* other components/applications that depend on your components \(usages\) +- demos of all the components under the organizations you specified +- documentation of your components +- dependencies your components have (dependencies) +- other components/applications that depend on your components (usages) There are two ways the components can update dynamically: -1. Add GitHub hooks to send POST requests to `/api/update/{org}/{repoName}` when a new tag is created -2. Enable `./server/poll` plugin to set up cron job that sends the POST requests every day +1. Add GitHub hooks to send POST requests to `/api/update/{org}/{repoName}` when a new tag is created +2. Enable `./server/poll` plugin to set up cron job that sends the POST requests every day -It's recommended to use Method \#1 to see updates in near real time. +It's recommended to use Method #1 to see updates in near real time. -After the server receives the POST request, it will fetch the `package.json`file under `{yourGithubUrl}/{org}/{repoName}`, update [data/orgs.json](https://github.com/electrode-io/electrode-explorer/blob/master/data/orgs.json) and `data/{org}/{repoName}.json`files. If there is a newer version, it will try to download the new component through npm \([scripts/install-module.sh](https://github.com/electrode-io/electrode-explorer/blob/master/scripts/install-module.sh)\) after a waiting period, babel transpile, and webpack the demo module \([scripts/post-install-module.sh](https://github.com/electrode-io/electrode-explorer/blob/master/scripts/post-install-module.sh)\). +After the server receives the POST request, it will fetch the `package.json`file under `{yourGithubUrl}/{org}/{repoName}`, update [data/orgs.json](https://github.com/electrode-io/electrode-explorer/blob/master/data/orgs.json) and `data/{org}/{repoName}.json`files. If there is a newer version, it will try to download the new component through npm ([scripts/install-module.sh](https://github.com/electrode-io/electrode-explorer/blob/master/scripts/install-module.sh)) after a waiting period, babel transpile, and webpack the demo module ([scripts/post-install-module.sh](https://github.com/electrode-io/electrode-explorer/blob/master/scripts/post-install-module.sh)). To make the server update immediately or force an update, add a url parameter to the POST request,`/api/update/{org}/{repoName}?updateNow=1`. -This post processing script works well with all electrode components \(meaning components using our [archetype](https://github.com/electrode-io/electrode-archetype-react-component)\). If you have non-electrode components, you can modify your [scripts/post-install-module.sh](https://github.com/electrode-io/electrode-explorer/blob/master/scripts/post-install-module.sh) to babel transpile and bundle your demo files. +This post processing script works well with all electrode components (meaning components using our [archetype](https://github.com/electrode-io/electrode-archetype-react-component)). If you have non-electrode components, you can modify your [scripts/post-install-module.sh](https://github.com/electrode-io/electrode-explorer/blob/master/scripts/post-install-module.sh) to babel transpile and bundle your demo files. ## Config - // config/default.json - { - "plugins": { - "./server/poll": { - "options": { - "enable": true - } - } - }, - - "githubApi": { - "version": "3.0.0", - "pathPrefix": "/api/v3", - "protocol": "https", - "host": "github.com" - }, - - "ORGS": [ - // org/user names under which components will be included in the explorer - // for example, put ["xxx", "yyy"] to include every repo under github.com/xxx and github.com/yyy - ], - - "REPOS_USAGE_INCLUDE": [ - // consumers need to contain one of these substrings to be included in usages - // for example, put ["react"] so consumers named /*react*/ will be included in usages - ], - - "REPOS_USAGE_EXCLUDE": [ - // consumers containing any of these substrings won't be included in usages - // for example, put ["training"] so consumers named /*training*/ will be excluded in usages - ], - - "MODULE_PREFIXES_INCLUDE": [ - // only module names beginning with one of these strings will be included in dependencies - // for example, put ["react"] so only modules with name starting with "react" will be included in dependencies - ], - - "NPM_WAITING_TIME": 300000, // wait for 5 minutes before `npm install` - - "GHACCESS_TOKEN_NAME": "GHACCESS_TOKEN" // github token variable name, your token would be accessible via `process.env["GHACCESS_TOKEN"]`} +```js +// config/default.json +{ + "plugins": { + "./server/poll": { + "options": { + "enable": true + } + } + }, + + "githubApi": { + "version": "3.0.0", + "pathPrefix": "/api/v3", + "protocol": "https", + "host": "github.com" + }, + + "ORGS": [ + // org/user names under which components will be included in the explorer + // for example, put ["xxx", "yyy"] to include every repo under github.com/xxx and github.com/yyy + ], + + "REPOS_USAGE_INCLUDE": [ + // consumers need to contain one of these substrings to be included in usages + // for example, put ["react"] so consumers named /*react*/ will be included in usages + ], + + "REPOS_USAGE_EXCLUDE": [ + // consumers containing any of these substrings won't be included in usages + // for example, put ["training"] so consumers named /*training*/ will be excluded in usages + ], + + "MODULE_PREFIXES_INCLUDE": [ + // only module names beginning with one of these strings will be included in dependencies + // for example, put ["react"] so only modules with name starting with "react" will be included in dependencies + ], + + "NPM_WAITING_TIME": 300000, // wait for 5 minutes before `npm install` + + "GHACCESS_TOKEN_NAME": "GHACCESS_TOKEN" // github token variable name, your token would be accessible via `process.env["GHACCESS_TOKEN"]` +} +``` ## Start server First install dependencies -``` +```bash $ npm install ``` Export github access token or set it as an environment variable -``` +```bash export GHACCESS_TOKEN=YOUR_GITHUB_TOKEN ``` For development mode -``` -$ gulp dev +```bash +$ clap dev ``` or -``` -GHACCESS_TOKEN=YOUR_GITHUB_TOKEN gulp dev +```bash +GHACCESS_TOKEN=YOUR_GITHUB_TOKEN clap dev ``` For production mode -``` -$ gulp build +```bash +$ clap build ``` and -``` +```bash NODE_ENV=production node . ``` or -``` +```bash GHACCESS_TOKEN=YOUR_GITHUB_TOKEN NODE_ENV=production node . ``` @@ -134,4 +137,3 @@ Since this is an Electrode application, it can be deployed the same way as any o ## Learn more Wish to learn more? Check our [wiki](https://github.com/electrode-io/electrode-explorer/wiki) page! - diff --git a/docs/chapter1/advanced/you-can-view-an-example-bundleanalyzetsv-output-using-the-electrode-boilerplate-code.md b/docs/chapter1/advanced/you-can-view-an-example-bundleanalyzetsv-output-using-the-electrode-boilerplate-code.md index 3545a5322..091c70fbf 100644 --- a/docs/chapter1/advanced/you-can-view-an-example-bundleanalyzetsv-output-using-the-electrode-boilerplate-code.md +++ b/docs/chapter1/advanced/you-can-view-an-example-bundleanalyzetsv-output-using-the-electrode-boilerplate-code.md @@ -2,52 +2,47 @@ ### Maximum Performance Out of the Box -In our [Getting Started](/chapter1.md) section, we introduced you to our Yeoman Electrode [Generator](https://github.com/electrode-io/electrode#yeoman-generator) and we constructed an impressive application with the built in technologies that the simple `yo electrode` command gave us \(read our Getting Started: [What's Inside](/chapter1/quick-start/whats-inside.md) to learn more\): +In our [Getting Started](/chapter1.md) section, we introduced you to our Yeoman Electrode [Generator](https://github.com/electrode-io/electrode#yeoman-generator) and we constructed an impressive application with the built in technologies that the simple `yo electrode` command gave us (read our Getting Started: [What's Inside](/chapter1/quick-start/whats-inside.md) to learn more): -* [React](https://facebook.github.io/react/index.html) +- [React](https://facebook.github.io/react/index.html) -* [Redux](http://redux.js.org/docs/basics/UsageWithReact.html) +- [Redux](http://redux.js.org/docs/basics/UsageWithReact.html) -* [React Router](https://github.com/ReactTraining/react-router/tree/master/docs) +- [React Router](https://github.com/ReactTraining/react-router/tree/master/docs) -* [CSS Modules](https://github.com/css-modules/css-modules) +- [CSS Modules](https://github.com/css-modules/css-modules) -* [Universal rendering](https://medium.com/@mjackson/universal-javascript-4761051b7ae9#.xjxr5yj5z) +- [Universal rendering](https://medium.com/@mjackson/universal-javascript-4761051b7ae9#.xjxr5yj5z) -* [Webpack](https://webpack.github.io/docs/motivation.html) +- [Webpack](https://webpack.github.io/docs/motivation.html) -* [Webpack Isomorphic Loader](https://github.com/jchip/isomorphic-loader) +- [Webpack Isomorphic Loader](https://github.com/jchip/isomorphic-loader) -* [Babel](https://babeljs.io/) +- [Babel](https://babeljs.io/) -* [ESLint](http://eslint.org/) +- [ESLint](http://eslint.org/) -* [Mocha](https://mochajs.org/)+[Enzyme](https://github.com/airbnb/enzyme)+[TravisCI](https://travis-ci.org/) +- [Mocha](https://mochajs.org/)+[Enzyme](https://github.com/airbnb/enzyme)+[TravisCI](https://travis-ci.org/) -* [Gulp](http://gulpjs.com/) +- [Yeoman](http://yeoman.io/) -* [Yeoman](http://yeoman.io/) +- [History](https://www.npmjs.com/package/history) -* [History](https://www.npmjs.com/package/history) +- [Bluebird](http://bluebirdjs.com/docs/why-promises.html) -* [Bluebird](http://bluebirdjs.com/docs/why-promises.html) +- [Electrode Confippet](https://github.com/electrode-io/electrode-confippet) -* [Electrode Confippet](https://github.com/electrode-io/electrode-confippet) +- [Electrode-Server](https://github.com/electrode-io/electrode-server) -* [Electrode-Server](https://github.com/electrode-io/electrode-server) - -* [Electrode-Docgen](https://github.com/electrode-io/electrode-docgen) +- [Electrode-Docgen](https://github.com/electrode-io/electrode-docgen) This is the beginning foundation of the [Electrode Boilerplate](/chapter1/advanced/you-can-view-an-example-bundleanalyzetsv-output-using-the-electrode-boilerplate-code.md). You have learned in the [Stand Alone Modules](/chapter1/advanced/stand-alone-modules.md) section that each of the Electrode modules are agnostic and can be used individually to enhance one specific area of your application. However, integrated together, you have a supercharged application; one that is capable of handling the complex problems we face at WalmartLabs and reach maximum efficiency and performance. This boilerplate includes the [Electrode Generator](/chapter1/quick-start/whats-inside.md) and it also has the following stand alone modules and tools built in for peak optimization out-of-the-box: -* [Above the Fold Rendering](/chapter1/advanced/stand-alone-modules/above-the-fold-rendering.md) -* [Server Side Render Cache + Profiling](/chapter1/advanced/stand-alone-modules/server-side-render-caching-+-profiling.md) -* [Stateless CSRF Validation](/chapter1/advanced/stand-alone-modules/stateless-csrf-validation.md) -* [Electrode Redux Router Engine](/chapter1/advanced/stand-alone-modules/redux-router-engine.md) -* [Electrode Bundle Analyzer](/chapter1/advanced/powerful-electrode-tools/bundle-analyzer.md) -* [Electrify](/chapter1/advanced/powerful-electrode-tools/electrify.md) - - - +- [Above the Fold Rendering](/chapter1/advanced/stand-alone-modules/above-the-fold-rendering.md) +- [Server Side Render Cache + Profiling](/chapter1/advanced/stand-alone-modules/server-side-render-caching-+-profiling.md) +- [Stateless CSRF Validation](/chapter1/advanced/stand-alone-modules/stateless-csrf-validation.md) +- [Electrode Redux Router Engine](/chapter1/advanced/stand-alone-modules/redux-router-engine.md) +- [Electrode Bundle Analyzer](/chapter1/advanced/powerful-electrode-tools/bundle-analyzer.md) +- [Electrify](/chapter1/advanced/powerful-electrode-tools/electrify.md) diff --git a/docs/chapter1/intermediate/build-a-progressive-web-app.md b/docs/chapter1/intermediate/build-a-progressive-web-app.md index bbc0f919f..b113b77e6 100644 --- a/docs/chapter1/intermediate/build-a-progressive-web-app.md +++ b/docs/chapter1/intermediate/build-a-progressive-web-app.md @@ -1,6 +1,6 @@ # Build a Progressive Web App -"A Progressive Web App \(PWA\) uses modern web capabilities to deliver an app-like user experience." – [Progressive Web Apps](https://developers.google.com/web/progressive-web-apps/) +"A Progressive Web App (PWA) uses modern web capabilities to deliver an app-like user experience." – [Progressive Web Apps](https://developers.google.com/web/progressive-web-apps/) PWAs are incredibly powerful and provide functionalities like offline first, push notifications, background sync, GPU rendering, 60FPS scrolling and add to home screen for a native-like app experience. @@ -10,7 +10,7 @@ PWAs are based on [Service Workers](https://developers.google.com/web/fundamenta ### Low friction of distribution -If your progressive web app is online, it's already accessible for Chrome on Android \(and other mobile\). Your customers won't have to download an "app" from the App Store. 65.5% of US smartphone users don't download any new apps each month. PWAs eliminate the need to go to the app store, search for the app, click Install, wait for the download, then open the app. Each of these steps loses 20% of potential users. +If your progressive web app is online, it's already accessible for Chrome on Android (and other mobile). Your customers won't have to download an "app" from the App Store. 65.5% of US smartphone users don't download any new apps each month. PWAs eliminate the need to go to the app store, search for the app, click Install, wait for the download, then open the app. Each of these steps loses 20% of potential users. From a developer's point of view, you don't need to rely on the Play Store to publish your app! Push new changes to your web app, and the service worker will take care of updating the app shell. @@ -20,7 +20,7 @@ For example: for an e-commerce business, PWA offers our customers a more frictio ### Faster mobile experience -Web Apps built with Electrode + PWA will be significantly faster. Also, these websites enable an offline mode, allowing customers to continue browsing in areas with poor wireless reception \(for example, on public transit\). Given the fact that faster websites have higher conversion rates, websites built with PWA could result in increased revenue. +Web Apps built with Electrode + PWA will be significantly faster. Also, these websites enable an offline mode, allowing customers to continue browsing in areas with poor wireless reception (for example, on public transit). Given the fact that faster websites have higher conversion rates, websites built with PWA could result in increased revenue. ### Personalized push notifications @@ -32,7 +32,7 @@ In the first section, we are going to make your previously built Electrode app i _If you are starting out with a new PWA, just answer "Y" to the following question_ -``` +```bash $ yo electrode # ... answer questions ... # Would you like to make a Progressive Web App? (Y/n) @@ -45,14 +45,14 @@ _Follow Prerequisites and skip to _[_Push Notifications_](/chapter1/intermediate We need certain API keys for push notifications. To generate these values, visit -1. [Firebase](https://console.firebase.google.com/) and create a new project. Click on the settings icon and open `Project settings`. Navigate to the `CLOUD MESSAGING` tab and note down your `Server key` and the `Sender ID`. -2. In the `client/images` directory, add the [logo 192x192](https://github.com/electrode-io/electrode/blob/d4142ee0c938cbf973a429ee8467052aa4e1c9be/samples/universal-react-node/client/images/logo-192x192.png) and [logo 72x72](https://github.com/electrode-io/electrode/blob/d4142ee0c938cbf973a429ee8467052aa4e1c9be/samples/universal-react-node/client/images/logo-72x72.png) icon images. We'll use these logos for the `Add to Homescreen` banner and push notifications. +1. [Firebase](https://console.firebase.google.com/) and create a new project. Click on the settings icon and open `Project settings`. Navigate to the `CLOUD MESSAGING` tab and note down your `Server key` and the `Sender ID`. +2. In the `client/images` directory, add the [logo 192x192](https://github.com/electrode-io/electrode/blob/d4142ee0c938cbf973a429ee8467052aa4e1c9be/samples/universal-react-node/client/images/logo-192x192.png) and [logo 72x72](https://github.com/electrode-io/electrode/blob/d4142ee0c938cbf973a429ee8467052aa4e1c9be/samples/universal-react-node/client/images/logo-72x72.png) icon images. We'll use these logos for the `Add to Homescreen` banner and push notifications. ### Generating a Service Worker Generating a service worker in an electrode app is as simple as adding a config file. Navigate to`/config`and create a new`sw-config.js`: -``` +```js module.exports = { cache: { cacheId: "", @@ -78,7 +78,7 @@ This will generate a `sw.js` in the `dist` folder when you build the app. We need to create a server plugin to access`dist/sw.js`. Create a file called `server/plugins/pwa/index.js`, and add the following code: -``` +```js "use strict"; exports.register = function (server, options, next) { server.route({ @@ -96,13 +96,13 @@ exports.register.attributes = { Also, add the following to `plugins` inside `config/default.json`: -``` +```js "pwa": { "module": "./server/plugins/pwa" } ``` To register the service worker on the browser, create a file called `sw-registration.js` inside the `client` directory and add the following code: -``` +```js module.exports = () => { // Exit early if the navigator isn't available if (typeof navigator === "undefined") { @@ -160,7 +160,7 @@ module.exports = () => { Import it in `client/app.jsx`: -``` +```js require.ensure(["./sw-registration"], (require) => { require("./sw-registration")(); }, "sw-registration"); @@ -168,18 +168,18 @@ require.ensure(["./sw-registration"], (require) => { We achieved a couple of things here: -1. "Offline First" with the cache property. +1. "Offline First" with the cache property. - Precache your static assets generated by webpack using the staticFileGlobs property. Or, use the runtimeCaching property to cache specific react routes in `routes.jsx`. + Precache your static assets generated by webpack using the staticFileGlobs property. Or, use the runtimeCaching property to cache specific react routes in `routes.jsx`. -2. "Add to Home" with the manifest property. +2. "Add to Home" with the manifest property. - After visiting your website, users will get a prompt \(if the user has visited your site at least twice, with at least five minutes between visits\) to add your application to their homescreen. `manifest`gives you control over how your web app is installed on user's home screen with `short_name`, `title`and `logo` properties. + After visiting your website, users will get a prompt (if the user has visited your site at least twice, with at least five minutes between visits) to add your application to their homescreen. `manifest`gives you control over how your web app is installed on user's home screen with `short_name`, `title`and `logo` properties. Build your app and start the server with -``` -$ gulp pwa +```bash +$ clap pwa ``` **Note: Service worker currently does not work with webpack-dev-server. You need to build first and then run the server.** @@ -190,13 +190,13 @@ Navigate to `http://localhost:3000`, open `Developer tools`, and click on the `A Go ahead and click on the `Offline` checkbox in the Developer tools. Terminate your server. Refresh your web page. -**NOTE: The **`Add to Homescreen` **banner will pop up only on Android devices with Chrome 42+. To simulate the banner on your desktop Chrome, navigate to **`Developer tools` **-> **`Applications` **-> **`Manifest` **and click on **`Add to homescreen`**.** +**NOTE: The **`Add to Homescreen` **banner will pop up only on Android devices with Chrome 42+. To simulate the banner on your desktop Chrome, navigate to **`Developer tools` **-> **`Applications` **-> **`Manifest` **and click on **`Add to homescreen`**.** ### Push notifications {#push-notifications} The [Push API](https://developer.mozilla.org/en-US/docs/Web/API/Push_API) requires a registered service worker so it can send notifications in the background when the web application isn't running. We already have our Service Worker generated with the help of `sw-config.js`. We only need to add a `Push` event to it. Create a new file `sw-events.js` inside the `client` directory and add the following to it: -``` +```js /* eslint-env serviceworker */ import icon from "./images/logo-192x192.png"; @@ -220,7 +220,7 @@ Check out the [Adding Push Notifications to a Web App](https://developers.google Now we need to add this file to our Webpack bundle by referencing it in the `cache property` of `sw-config.js`: -``` +```js module.exports = { cache: { importScripts: ['./sw-events.js'] @@ -232,202 +232,204 @@ Now we have a registered service worker installed, activated and ready to accept Navigate to `client/components/home.jsx` and replace it with: - /* eslint-disable react/no-did-mount-set-state */ - /* global navigator */ - - import React, {PropTypes} from "react"; - import {connect} from "react-redux"; - import {toggleCheck, incNumber, decNumber} from "../actions"; - - class Home extends React.Component { - constructor() { - super(); - this.state = { - // Whether ServiceWorkers are supported - supported: false, - // Did something fail? - error: null, - // Waiting on the service worker to be ready - loading: true, - // Whether we"ve got a push notification subscription - subscribed: false, - // The actual subscription itself - subscription: null, - title: "", - body: "" - }; - this.sendNotification = this.sendNotification.bind(this); - this.handleInputChange = this.handleInputChange.bind(this); - this.subscribe = this.subscribe.bind(this); - } - componentDidMount() { - if ("serviceWorker" in navigator) { - navigator.serviceWorker.ready.then((registration) => { - // Check for any existing subscriptions - registration.pushManager.getSubscription().then((subscription) => { - // No current subscription, let the user subscribe - if (!subscription) { - this.setState({ - loading: false, - subscribed: false, - supported: true - }); - } else { - this.setState({ - subscription, - subscribed: true, - loading: false, - supported: true - }); - } - }) - .catch((error) => { - this.setState({loading: false, error}); +```js +/* eslint-disable react/no-did-mount-set-state */ +/* global navigator */ + +import React, {PropTypes} from "react"; +import {connect} from "react-redux"; +import {toggleCheck, incNumber, decNumber} from "../actions"; + +class Home extends React.Component { + constructor() { + super(); + this.state = { + // Whether ServiceWorkers are supported + supported: false, + // Did something fail? + error: null, + // Waiting on the service worker to be ready + loading: true, + // Whether we"ve got a push notification subscription + subscribed: false, + // The actual subscription itself + subscription: null, + title: "", + body: "" + }; + this.sendNotification = this.sendNotification.bind(this); + this.handleInputChange = this.handleInputChange.bind(this); + this.subscribe = this.subscribe.bind(this); + } + componentDidMount() { + if ("serviceWorker" in navigator) { + navigator.serviceWorker.ready.then((registration) => { + // Check for any existing subscriptions + registration.pushManager.getSubscription().then((subscription) => { + // No current subscription, let the user subscribe + if (!subscription) { + this.setState({ + loading: false, + subscribed: false, + supported: true }); - }) - .catch((error) => { - this.setState({loading: false, error}); - }); - } else { - // ServiceWorkers are not supported, let the user know. - this.setState({loading: false, supported: false}); - } - } - subscribe() { - navigator.serviceWorker.ready.then((registration) => { - registration.pushManager.subscribe({ userVisibleOnly: true }) - .then((subscription) => { - this.setState({subscription, subscribed: true}); - }) - .catch((error) => { - this.setState({error}); + } else { + this.setState({ + subscription, + subscribed: true, + loading: false, + supported: true }); + } + }) + .catch((error) => { + this.setState({loading: false, error}); }); - } - handleInputChange(event) { - this.setState({ - [event.target.name]: event.target.value - }); - } - sendNotification() { - const {title, body} = this.state; - // you can add badge, icon images in the options. - const options = {body}; - navigator.serviceWorker.ready.then((registration) => { - registration.showNotification(title, options); + }) + .catch((error) => { + this.setState({loading: false, error}); + }); + } else { + // ServiceWorkers are not supported, let the user know. + this.setState({loading: false, supported: false}); + } + } + subscribe() { + navigator.serviceWorker.ready.then((registration) => { + registration.pushManager.subscribe({ userVisibleOnly: true }) + .then((subscription) => { + this.setState({subscription, subscribed: true}); + }) + .catch((error) => { + this.setState({error}); }); - } - render() { - const props = this.props; - const {checked, value} = props; - const { - error, - loading, - supported, - subscribed, - subscription - } = this.state; - - if (!loading && !supported) { - return ( -
Sorry, service workers are not supported in this browser.
- ); - } - if (error) { - return ( -
Woops! Looks like there was an error: - - {error.name}: {error.message} - -
- ); - } - if (loading) { - return (
Checking push notification subscription status...
); - } - if (!subscribed) { - return ( -
Click below to subscribe to push notifications - -
- ); - } - - const API_KEY = "AIzaSyDAL_a1Hswn8QRRICDlh5PIIbEbFN7Aih0"; - const GCM_ENDPOINT = "https://android.googleapis.com/gcm/send"; - const endpointSections = subscription.endpoint.split("/"); - const subscriptionId = endpointSections[endpointSections.length - 1]; - const curlCommand = `curl --header "Authorization: key=${API_KEY}" - --header Content-Type:"application/json" ${GCM_ENDPOINT} -d - "{\\"registration_ids\\":[\\"${subscriptionId}\\"]}"`; - - return ( + }); + } + handleInputChange(event) { + this.setState({ + [event.target.name]: event.target.value + }); + } + sendNotification() { + const {title, body} = this.state; + // you can add badge, icon images in the options. + const options = {body}; + navigator.serviceWorker.ready.then((registration) => { + registration.showNotification(title, options); + }); + } + render() { + const props = this.props; + const {checked, value} = props; + const { + error, + loading, + supported, + subscribed, + subscription + } = this.state; + + if (!loading && !supported) { + return ( +
Sorry, service workers are not supported in this browser.
+ ); + } + if (error) { + return ( +
Woops! Looks like there was an error: + + {error.name}: {error.message} + +
+ ); + } + if (loading) { + return (
Checking push notification subscription status...
); + } + if (!subscribed) { + return ( +
Click below to subscribe to push notifications + +
+ ); + } + + const API_KEY = "AIzaSyDAL_a1Hswn8QRRICDlh5PIIbEbFN7Aih0"; + const GCM_ENDPOINT = "https://android.googleapis.com/gcm/send"; + const endpointSections = subscription.endpoint.split("/"); + const subscriptionId = endpointSections[endpointSections.length - 1]; + const curlCommand = `curl --header "Authorization: key=${API_KEY}" + --header Content-Type:"application/json" ${GCM_ENDPOINT} -d + "{\\"registration_ids\\":[\\"${subscriptionId}\\"]}"`; + + return ( +
+

Hello {"Electrode"}

+
+

Managing States with Redux

+
-

Hello {"Electrode"}

-
-

Managing States with Redux

- -
- -  {value}  - -
-
-
-

Push Notifications with Service Workers

- Fill the form below and click on send for a push notification. - - - - -
- -

Subscription Endpoint

- {this.state.subscription.endpoint} -

Curl Command

- {curlCommand} + +  {value}  +
- ); - } - } +
+
+

Push Notifications with Service Workers

+ Fill the form below and click on send for a push notification. + + + + +
+ +

Subscription Endpoint

+ {this.state.subscription.endpoint} +

Curl Command

+ {curlCommand} +
+ ); + } +} - Home.propTypes = { - checked: PropTypes.bool, - value: PropTypes.number.isRequired - }; +Home.propTypes = { + checked: PropTypes.bool, + value: PropTypes.number.isRequired +}; - const mapStateToProps = (state) => { - return { - checked: state.checkBox.checked, value: state.number.value - }; - }; - - const mapDispatchToProps = (dispatch) => { - return { - onChangeCheck: () => { - dispatch(toggleCheck()); - }, - onIncrease: () => { - dispatch(incNumber()); - }, - onDecrease: () => { - dispatch(decNumber()); - } - }; - }; +const mapStateToProps = (state) => { + return { + checked: state.checkBox.checked, value: state.number.value + }; +}; - export default connect(mapStateToProps, mapDispatchToProps)(Home); +const mapDispatchToProps = (dispatch) => { + return { + onChangeCheck: () => { + dispatch(toggleCheck()); + }, + onIncrease: () => { + dispatch(incNumber()); + }, + onDecrease: () => { + dispatch(decNumber()); + } + }; +}; + +export default connect(mapStateToProps, mapDispatchToProps)(Home); +``` Make sure you update the `API_KEY` with the one you previously generated in [Prerequisites](http://www.electrode.io/docs/service_workers.html#prerequisites). -`navigator.serviceWorker.ready` is a promise that will resolve once a service worker is registered, and it returns a reference to the active [ServiceWorkerRegistration](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration). The showNotification\(\) method of the ServiceWorkerRegistration interface creates a notification and returns a Promise that resolves to a [NotificationEvent](https://developer.mozilla.org/en-US/docs/Web/API/NotificationEvent). +`navigator.serviceWorker.ready` is a promise that will resolve once a service worker is registered, and it returns a reference to the active [ServiceWorkerRegistration](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerRegistration). The showNotification() method of the ServiceWorkerRegistration interface creates a notification and returns a Promise that resolves to a [NotificationEvent](https://developer.mozilla.org/en-US/docs/Web/API/NotificationEvent). We also need to update `sw-config.js` with the `sender_id`, so the final `sw-config.js` should look like: -``` +```js module.exports = { cache: { cacheId: "electrode", @@ -450,8 +452,8 @@ module.exports = { Rebuild your app and run the server with -``` -$ gulp pwa +```bash +$ clap pwa ``` With all the code in place, we are ready to see push notifications in action. @@ -459,4 +461,3 @@ With all the code in place, we are ready to see push notifications in action. Navigate to `http://localhost:3000`. Accept the permission for subscribing and you will see a curl command rendered on the page. You can either run the curl command from terminal to see the push notification or fill out the form and click on the `Send` button to trigger it! For more Electrode PWA code examples checkout [electrode-pwa-examples](https://github.com/electrode-samples/electrode-pwa-examples/tree/master/examples) repo. - diff --git a/docs/chapter1/intermediate/build-with-material-ui.md b/docs/chapter1/intermediate/build-with-material-ui.md index fc8a1dad6..b22ff26bc 100644 --- a/docs/chapter1/intermediate/build-with-material-ui.md +++ b/docs/chapter1/intermediate/build-with-material-ui.md @@ -8,25 +8,25 @@ ### Prerequisites -Make sure you have installed NodeJS >= 4.x and npm >= 3.x, and [gulp](http://gulpjs.com/). +Make sure you have installed NodeJS >= 4.x and npm >= 3.x, and [xclap-cli]. -``` +```bash $ node -v v6.6.0 $ npm -v 3.10.3 -$ npm install -g gulp +$ npm install -g xclap-cli ``` ### Check it out To try out this ready made sample app, use git to clone the repo: -``` +```bash $ git clone https://github.com/electrode-io/electrode.git $ cd electrode/samples/universal-material-ui $ npm install -$ gulp dev +$ clap dev ``` Now navigate your browser to `http://localhost:3000` to see the sample app with material-ui components. @@ -39,9 +39,9 @@ This app was created with the following steps. The first part of the process is to generate an Electrode Universal App using the [Yeoman](http://yeoman.io/) generator. Follow the steps below: -1. First, generate the Electrode Universal App with the following commands: +1. First, generate the Electrode Universal App with the following commands: -``` +```bash $ npm install -g yo generator-electrode $ mkdir react-sample-material-ui $ cd react-sample-material-ui @@ -49,28 +49,28 @@ $ yo electrode # ... answer questions and wait for app to be generated and npm install completed ... ``` -1. `Run gulp dev` in the newly generated app -2. Navigate to `http://localhost:3000` to make sure the app is working. +1. Run `clap dev` in the newly generated app +2. Navigate to `http://localhost:3000` to make sure the app is working. ### Add material-ui The second part of the process is to add material-ui dependencies. Follow the steps below: -1. Stop the app and install material-ui dependencies: `$ npm install material-ui react-tap-event-plugin --save` +1. Stop the app and install material-ui dependencies: `$ npm install material-ui react-tap-event-plugin --save` -2. Restart `gulp dev` and reload browser to make sure things are still working. +2. Restart `clap dev` and reload browser to make sure things are still working. -3. Add material-ui's required font, _Roboto_, to `server/plugins/webapp/index.html` +3. Add material-ui's required font, _Roboto_, to `server/plugins/webapp/index.html` -4. Update `client/styles/base.css` with styles for material-ui. +4. Update `client/styles/base.css` with styles for material-ui. -5. Test your material-ui component by adding a [RaisedButton](http://www.material-ui.com/#/components/raised-button) to `client/components/home.jsx` +5. Test your material-ui component by adding a [RaisedButton](http://www.material-ui.com/#/components/raised-button) to `client/components/home.jsx` -6. Watch [webpack-dev-server](https://webpack.github.io/docs/webpack-dev-server.html) update your bundle and refresh your browser to see the changes. +6. Watch [webpack-dev-server](https://webpack.github.io/docs/webpack-dev-server.html) update your bundle and refresh your browser to see the changes. -7. Add `global.navigator.userAgent` to `server/index.js`, as required by material-ui for [Server Rendering](http://www.material-ui.com/#/get-started/server-rendering). +7. Add `global.navigator.userAgent` to `server/index.js`, as required by material-ui for [Server Rendering](http://www.material-ui.com/#/get-started/server-rendering). -8. Watch [webpack-dev-server](https://webpack.github.io/docs/webpack-dev-server.html) update your bundle and refresh your browser to see the changes. +8. Watch [webpack-dev-server](https://webpack.github.io/docs/webpack-dev-server.html) update your bundle and refresh your browser to see the changes. ### Add material-ui Examples @@ -82,7 +82,8 @@ First we have to add the resolution for an [issue in material-ui](https://github Add the following code to `client/app.jsx` -``` + +```js import injectTapEventPlugin from "react-tap-event-plugin"; window.webappStart = () => { @@ -95,29 +96,29 @@ window.webappStart = () => { First add the IconMenu [AppBar example](http://www.material-ui.com/#/components/app-bar) by following the steps below. -1. Copy the source from the example into `client/components/AppBarExampleIconMenu.jsx` -2. Replace the `Hello Electrode` and the RaisedButton content in `client/components/home.jsx` with ``; -3. Watch [webpack-dev-server](https://webpack.github.io/docs/webpack-dev-server.html) update your bundle and refresh your browser to see the changes. -4. If the AppBar shows up, click on the right menu button. You should see a menu pop up. +1. Copy the source from the example into `client/components/AppBarExampleIconMenu.jsx` +2. Replace the `Hello Electrode` and the RaisedButton content in `client/components/home.jsx` with ``; +3. Watch [webpack-dev-server](https://webpack.github.io/docs/webpack-dev-server.html) update your bundle and refresh your browser to see the changes. +4. If the AppBar shows up, click on the right menu button. You should see a menu pop up. #### BottomNavigation example Next, add the [BottomNavigation example](http://www.material-ui.com/#/components/bottom-navigation): -1. Copy the source from the example into `client/components/BottomNavigationExampleSimple.jsx` -2. Import the component in `client/components/home.jsx` and add it to `render` after the `AppBarExampleIconMenu` - component. -3. Watch [webpack-dev-server](https://webpack.github.io/docs/webpack-dev-server.html) update your bundle and refresh your browser to see the changes. -4. You should see AppBar and BottomNavigation show up. You should be able to interact with the buttons on the BottomNavigation component. +1. Copy the source from the example into `client/components/BottomNavigationExampleSimple.jsx` +2. Import the component in `client/components/home.jsx` and add it to `render` after the `AppBarExampleIconMenu` + component. +3. Watch [webpack-dev-server](https://webpack.github.io/docs/webpack-dev-server.html) update your bundle and refresh your browser to see the changes. +4. You should see AppBar and BottomNavigation show up. You should be able to interact with the buttons on the BottomNavigation component. #### Card example In this section we add the[Card example](http://www.material-ui.com/#/components/card). -1. Copy the source from the Card example into `client/components/CardExampleWithAvatar.jsx` -2. Import the component in `client/components/home.jsx` and add it to `render` after the `AppBarExampleIconMenu` component. -3. Watch [webpack-dev-server](https://webpack.github.io/docs/webpack-dev-server.html) update your bundle and refresh your browser to see the changes. -4. You should see Card show up, but with broken images. +1. Copy the source from the Card example into `client/components/CardExampleWithAvatar.jsx` +2. Import the component in `client/components/home.jsx` and add it to `render` after the `AppBarExampleIconMenu` component. +3. Watch [webpack-dev-server](https://webpack.github.io/docs/webpack-dev-server.html) update your bundle and refresh your browser to see the changes. +4. You should see Card show up, but with broken images. > You can replace the image URLs with full URLs by adding `http://www.material-ui.com/` to them to fix the broken images, but we will explore isomorphic images next. @@ -127,40 +128,32 @@ Electrode core comes with isomorphic images support built in using[isomorphic-lo Create a directory called -1. `client/images `and copy the following images there: - * `http://www.material-ui.com/images/nature-600-337.jpg` - * `http://www.material-ui.com/images/jsa-128.jpg `\(Or your own favorite 128x128 Avatar image\) - * In my sample, I use `jchip-128.jpg `as my avatar. -2. In`client/components/CardExampleWithAvatar.jsx`, import the images: - - ``` - import natureJpg from "../images/nature-600-337.jpg"; - import avatarJpg from "../images/jsa-128.jpg"; - ``` +1. `client/images`and copy the following images there: + - `http://www.material-ui.com/images/nature-600-337.jpg` + - `http://www.material-ui.com/images/jsa-128.jpg`(Or your own favorite 128x128 Avatar image) + - In my sample, I use `jchip-128.jpg`as my avatar. +2. In`client/components/CardExampleWithAvatar.jsx`, import the images: -3. Replace the URLs for`avatar`and`CarMedia`as follows: + import natureJpg from "../images/nature-600-337.jpg"; + import avatarJpg from "../images/jsa-128.jpg"; - ``` - ... - avatar={avatarJpg} - ... - src={natureJpg} +3. Replace the URLs for`avatar`and`CarMedia`as follows: - ``` +```js + ... + avatar={avatarJpg} + ... + src={natureJpg} +``` -4. In `server/index.js`, activate [isomorphic-loader](https://github.com/electrode-io/isomorphic-loader)'s `extend-require` by changing the last line to: +4. In `server/index.js`, activate [isomorphic-loader](https://github.com/electrode-io/isomorphic-loader)'s `extend-require` by changing the last line to: - ``` - supports.isomorphicExtendRequire().then(() => { - require("electrode-server")(config, [staticPathsDecor()]); - }); - ``` +```js +supports.isomorphicExtendRequire().then(() => { + require("electrode-server")(config, [staticPathsDecor()]); +}); +``` -5. Watch [webpack-dev-server](https://webpack.github.io/docs/webpack-dev-server.html) update your bundle and refresh your browser to see the changes. +5. Watch [webpack-dev-server](https://webpack.github.io/docs/webpack-dev-server.html) update your bundle and refresh your browser to see the changes. > Note that you will see the message `Warning: Unknown prop onTouchTap on