├── .editorconfig ├── .eslintrc ├── .gitignore ├── .npmignore ├── .travis.yml ├── LICENSE.txt ├── README.md ├── demo ├── dist │ ├── index.html │ ├── index.js │ └── main.css ├── index.html ├── index.jsx └── main.scss ├── dist └── DadJoke.js ├── karma.conf.js ├── package-lock.json ├── package.json ├── src ├── DadJoke.jsx ├── components │ └── react-dadjoke.jsx └── index.js ├── test └── client │ ├── main.js │ ├── spec │ └── components │ │ └── react-dadjoke.spec.jsx │ └── test.html ├── webpack.config.js ├── webpack.dist.config.js └── webpack.standalone.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | charset = utf-8 9 | trim_trailing_whitespace = true 10 | insert_final_newline = true 11 | max_line_length = 100 12 | 13 | [*.md] 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "babel-eslint", 3 | "extends": "airbnb", 4 | "globals": { 5 | "__DEV__": true 6 | }, 7 | "env": { 8 | "browser": true, 9 | "node": true, 10 | "jasmine": true 11 | }, 12 | "rules": { 13 | "react/jsx-curly-spacing": [2, {"when": "always"}], 14 | "template-curly-spacing": ["error", "always"], 15 | "object-curly-spacing": ["error", "always", { 16 | "arraysInObjects": false, 17 | "objectsInObjects": false, 18 | }], 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | # Cruft 2 | *.sublime-workspace 3 | .DS_Store 4 | .AppleDouble 5 | .LSOverride 6 | Icon 7 | ._* 8 | .Spotlight-V100 9 | .Trashes 10 | Thumbs.db 11 | ehthumbs.db 12 | Desktop.ini 13 | $RECYCLE.BIN/ 14 | .tmp 15 | npm-debug.log* 16 | 17 | # Code / build 18 | coverage 19 | node_modules 20 | bower_components 21 | demo 22 | test 23 | karma* 24 | webpack* 25 | .eslint* 26 | .editor* 27 | .travis* 28 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | 3 | node_js: 4 | - "6.10" 5 | - "7.10" 6 | - "8.0" 7 | 8 | notifications: 9 | email: "mark@markrabey.com" 10 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Opentrace 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | [![Travis Status][trav_img]][trav_site] [![npm version](https://badge.fury.io/js/react-dadjoke.svg)](https://badge.fury.io/js/react-dadjoke) 2 | 3 | # react-dadjoke 4 | React component for displaying random dad jokes 5 | 6 | ## Install 7 | ```shell 8 | npm install react-dadjoke --save 9 | ``` 10 | 11 | ## Live Demo 12 | * Basic Example 13 | 14 | ## Usage 15 | Enter usage details here. 16 | 17 | ## License 18 | [MIT](http://mit-license.org) Copyright (c) 2017 Mark Rabey 19 | 20 | [trav_img]: https://api.travis-ci.org/Opentrace/react-dadjoke.svg 21 | [trav_site]: https://travis-ci.org/Opentrace/react-dadjoke 22 | -------------------------------------------------------------------------------- /demo/dist/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | React Dad Joke 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | Fork me on GitHub 19 |
20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /demo/dist/main.css: -------------------------------------------------------------------------------- 1 | /* 2 | 3 | Atom One Dark by Daniel Gamage 4 | Original One Dark Syntax theme from https://github.com/atom/one-dark-syntax 5 | 6 | base: #282c34 7 | mono-1: #abb2bf 8 | mono-2: #818896 9 | mono-3: #5c6370 10 | hue-1: #56b6c2 11 | hue-2: #61aeee 12 | hue-3: #c678dd 13 | hue-4: #98c379 14 | hue-5: #e06c75 15 | hue-5-2: #be5046 16 | hue-6: #d19a66 17 | hue-6-2: #e6c07b 18 | 19 | */ 20 | .hljs { 21 | display: block; 22 | overflow-x: auto; 23 | padding: 0.5em; 24 | color: #abb2bf; 25 | background: #282c34; } 26 | 27 | .hljs-comment, 28 | .hljs-quote { 29 | color: #5c6370; 30 | font-style: italic; } 31 | 32 | .hljs-doctag, 33 | .hljs-keyword, 34 | .hljs-formula { 35 | color: #c678dd; } 36 | 37 | .hljs-section, 38 | .hljs-name, 39 | .hljs-selector-tag, 40 | .hljs-deletion, 41 | .hljs-subst { 42 | color: #e06c75; } 43 | 44 | .hljs-literal { 45 | color: #56b6c2; } 46 | 47 | .hljs-string, 48 | .hljs-regexp, 49 | .hljs-addition, 50 | .hljs-attribute, 51 | .hljs-meta-string { 52 | color: #98c379; } 53 | 54 | .hljs-built_in, 55 | .hljs-class .hljs-title { 56 | color: #e6c07b; } 57 | 58 | .hljs-attr, 59 | .hljs-variable, 60 | .hljs-template-variable, 61 | .hljs-type, 62 | .hljs-selector-class, 63 | .hljs-selector-attr, 64 | .hljs-selector-pseudo, 65 | .hljs-number { 66 | color: #d19a66; } 67 | 68 | .hljs-symbol, 69 | .hljs-bullet, 70 | .hljs-link, 71 | .hljs-meta, 72 | .hljs-selector-id, 73 | .hljs-title { 74 | color: #61aeee; } 75 | 76 | .hljs-emphasis { 77 | font-style: italic; } 78 | 79 | .hljs-strong { 80 | font-weight: bold; } 81 | 82 | .hljs-link { 83 | text-decoration: underline; } 84 | 85 | /*# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIndlYnBhY2s6Ly8vLi9ub2RlX21vZHVsZXMvaGlnaGxpZ2h0LmpzL3N0eWxlcy9hdG9tLW9uZS1kYXJrLmNzcyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7Ozs7Ozs7O0VBa0JFO0FBQ0Y7RUFDRSxlQUFlO0VBQ2YsaUJBQWlCO0VBQ2pCLGVBQWU7RUFDZixlQUFlO0VBQ2Ysb0JBQW9CLEVBQUU7O0FBRXhCOztFQUVFLGVBQWU7RUFDZixtQkFBbUIsRUFBRTs7QUFFdkI7OztFQUdFLGVBQWUsRUFBRTs7QUFFbkI7Ozs7O0VBS0UsZUFBZSxFQUFFOztBQUVuQjtFQUNFLGVBQWUsRUFBRTs7QUFFbkI7Ozs7O0VBS0UsZUFBZSxFQUFFOztBQUVuQjs7RUFFRSxlQUFlLEVBQUU7O0FBRW5COzs7Ozs7OztFQVFFLGVBQWUsRUFBRTs7QUFFbkI7Ozs7OztFQU1FLGVBQWUsRUFBRTs7QUFFbkI7RUFDRSxtQkFBbUIsRUFBRTs7QUFFdkI7RUFDRSxrQkFBa0IsRUFBRTs7QUFFdEI7RUFDRSwyQkFBMkIsRUFBRSIsImZpbGUiOiJtYWluLmNzcyIsInNvdXJjZXNDb250ZW50IjpbIi8qXG5cbkF0b20gT25lIERhcmsgYnkgRGFuaWVsIEdhbWFnZVxuT3JpZ2luYWwgT25lIERhcmsgU3ludGF4IHRoZW1lIGZyb20gaHR0cHM6Ly9naXRodWIuY29tL2F0b20vb25lLWRhcmstc3ludGF4XG5cbmJhc2U6ICAgICMyODJjMzRcbm1vbm8tMTogICNhYmIyYmZcbm1vbm8tMjogICM4MTg4OTZcbm1vbm8tMzogICM1YzYzNzBcbmh1ZS0xOiAgICM1NmI2YzJcbmh1ZS0yOiAgICM2MWFlZWVcbmh1ZS0zOiAgICNjNjc4ZGRcbmh1ZS00OiAgICM5OGMzNzlcbmh1ZS01OiAgICNlMDZjNzVcbmh1ZS01LTI6ICNiZTUwNDZcbmh1ZS02OiAgICNkMTlhNjZcbmh1ZS02LTI6ICNlNmMwN2JcblxuKi9cbi5obGpzIHtcbiAgZGlzcGxheTogYmxvY2s7XG4gIG92ZXJmbG93LXg6IGF1dG87XG4gIHBhZGRpbmc6IDAuNWVtO1xuICBjb2xvcjogI2FiYjJiZjtcbiAgYmFja2dyb3VuZDogIzI4MmMzNDsgfVxuXG4uaGxqcy1jb21tZW50LFxuLmhsanMtcXVvdGUge1xuICBjb2xvcjogIzVjNjM3MDtcbiAgZm9udC1zdHlsZTogaXRhbGljOyB9XG5cbi5obGpzLWRvY3RhZyxcbi5obGpzLWtleXdvcmQsXG4uaGxqcy1mb3JtdWxhIHtcbiAgY29sb3I6ICNjNjc4ZGQ7IH1cblxuLmhsanMtc2VjdGlvbixcbi5obGpzLW5hbWUsXG4uaGxqcy1zZWxlY3Rvci10YWcsXG4uaGxqcy1kZWxldGlvbixcbi5obGpzLXN1YnN0IHtcbiAgY29sb3I6ICNlMDZjNzU7IH1cblxuLmhsanMtbGl0ZXJhbCB7XG4gIGNvbG9yOiAjNTZiNmMyOyB9XG5cbi5obGpzLXN0cmluZyxcbi5obGpzLXJlZ2V4cCxcbi5obGpzLWFkZGl0aW9uLFxuLmhsanMtYXR0cmlidXRlLFxuLmhsanMtbWV0YS1zdHJpbmcge1xuICBjb2xvcjogIzk4YzM3OTsgfVxuXG4uaGxqcy1idWlsdF9pbixcbi5obGpzLWNsYXNzIC5obGpzLXRpdGxlIHtcbiAgY29sb3I6ICNlNmMwN2I7IH1cblxuLmhsanMtYXR0cixcbi5obGpzLXZhcmlhYmxlLFxuLmhsanMtdGVtcGxhdGUtdmFyaWFibGUsXG4uaGxqcy10eXBlLFxuLmhsanMtc2VsZWN0b3ItY2xhc3MsXG4uaGxqcy1zZWxlY3Rvci1hdHRyLFxuLmhsanMtc2VsZWN0b3ItcHNldWRvLFxuLmhsanMtbnVtYmVyIHtcbiAgY29sb3I6ICNkMTlhNjY7IH1cblxuLmhsanMtc3ltYm9sLFxuLmhsanMtYnVsbGV0LFxuLmhsanMtbGluayxcbi5obGpzLW1ldGEsXG4uaGxqcy1zZWxlY3Rvci1pZCxcbi5obGpzLXRpdGxlIHtcbiAgY29sb3I6ICM2MWFlZWU7IH1cblxuLmhsanMtZW1waGFzaXMge1xuICBmb250LXN0eWxlOiBpdGFsaWM7IH1cblxuLmhsanMtc3Ryb25nIHtcbiAgZm9udC13ZWlnaHQ6IGJvbGQ7IH1cblxuLmhsanMtbGluayB7XG4gIHRleHQtZGVjb3JhdGlvbjogdW5kZXJsaW5lOyB9XG5cblxuXG4vLyBXRUJQQUNLIEZPT1RFUiAvL1xuLy8gLi9ub2RlX21vZHVsZXMvaGlnaGxpZ2h0LmpzL3N0eWxlcy9hdG9tLW9uZS1kYXJrLmNzcyJdLCJzb3VyY2VSb290IjoiIn0=*/ -------------------------------------------------------------------------------- /demo/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | React Dad Joke 9 | 10 | 11 | 12 | 13 | 14 | 15 | 18 | Fork me on GitHub 19 |
20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /demo/index.jsx: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | import React from 'react'; 3 | import ReactDOM from 'react-dom'; 4 | import Highlight from 'react-highlight'; 5 | import 'highlight.js/styles/atom-one-dark.css'; 6 | 7 | import DadJoke from 'DadJoke'; 8 | import { 9 | Jumbotron, 10 | PageHeader, 11 | Panel 12 | } from 'react-bootstrap'; 13 | 14 | import './main.scss'; 15 | 16 | const usage = `import React from 'react'; 17 | import DadJoke from 'react-dadjoke'; 18 | 19 | const MyComponent = () => ( 20 |
21 | ... 22 | 23 | ... 24 |
25 | );` 26 | 27 | const Demo = () => ( 28 |
29 | 30 |
31 |

React Dad Joke

32 |

Add the most hilarious jokes to your app or web site!

33 |
34 |
35 | 36 |
37 |
38 | 39 | Basic Example 40 | 41 | <DadJoke /> }> 42 | 43 | 44 |
45 | 46 |
47 | 48 | Installation 49 | 50 | Install with npm: npm install --save react-dadjoke. 51 |
52 | 53 |
54 | 55 | Usage 56 | 57 | 58 | { usage } 59 | 60 |
61 | 62 |
63 | 64 | Display as image 65 | 66 | <DadJoke img /> }> 67 | 68 | 69 |
70 | 71 |
72 | 73 | Display with refresh button 74 | 75 | <DadJoke refreshButton /> }> 76 | 77 | 78 |
79 | 80 |
81 | 82 | Display a specific joke 83 | 84 | <DadJoke jokeID="haahVKZDtrc" /> }> 85 | 86 | 87 |
88 | 89 |
90 | 91 | Optional Props 92 | 93 |
    94 |
  • 95 | className(string) adds to wrapping div or img. 96 | Default: .dad-joke 97 |
  • 98 | 99 |
  • 100 | jokeID(string) specify a joke to display 101 |
  • 102 | 103 |
  • 104 | img(boolean) display an image instead of text 105 |
  • 106 | 107 |
  • 108 | refreshButton(boolean) display a refresh button 109 |
  • 110 | 111 |
  • 112 | refreshButtonClassName 113 | (string) adds classes(es) to the button. 114 | Default: .dad-joke__refresh-button 115 |
  • 116 |
117 |
118 |
119 |
120 | ); 121 | 122 | ReactDOM.render(, document.getElementById('content')); 123 | -------------------------------------------------------------------------------- /demo/main.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MarkRabey/react-dadjoke/16985f1cd4d89a317bc81eb7d4de101b7850d035/demo/main.scss -------------------------------------------------------------------------------- /dist/DadJoke.js: -------------------------------------------------------------------------------- 1 | module.exports=function(e){function t(n){if(r[n])return r[n].exports;var o=r[n]={i:n,l:!1,exports:{}};return e[n].call(o.exports,o,o.exports,t),o.l=!0,o.exports}var r={};return t.m=e,t.c=r,t.d=function(e,r,n){t.o(e,r)||Object.defineProperty(e,r,{configurable:!1,enumerable:!0,get:n})},t.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return t.d(r,"a",r),r},t.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},t.p="",t(t.s=14)}([function(e,t,r){"use strict";function n(e){return"[object Array]"===j.call(e)}function o(e){return"[object ArrayBuffer]"===j.call(e)}function s(e){return"undefined"!=typeof FormData&&e instanceof FormData}function i(e){return"undefined"!=typeof ArrayBuffer&&ArrayBuffer.isView?ArrayBuffer.isView(e):e&&e.buffer&&e.buffer instanceof ArrayBuffer}function a(e){return"string"==typeof e}function u(e){return"number"==typeof e}function c(e){return void 0===e}function f(e){return null!==e&&"object"==typeof e}function p(e){return"[object Date]"===j.call(e)}function l(e){return"[object File]"===j.call(e)}function d(e){return"[object Blob]"===j.call(e)}function h(e){return"[object Function]"===j.call(e)}function m(e){return f(e)&&h(e.pipe)}function g(e){return"undefined"!=typeof URLSearchParams&&e instanceof URLSearchParams}function y(e){return e.replace(/^\s*/,"").replace(/\s*$/,"")}function v(){return("undefined"==typeof navigator||"ReactNative"!==navigator.product)&&("undefined"!=typeof window&&"undefined"!=typeof document)}function b(e,t){if(null!==e&&void 0!==e)if("object"==typeof e||n(e)||(e=[e]),n(e))for(var r=0,o=e.length;r=200&&e<300}};a.headers={common:{Accept:"application/json, text/plain, */*"}},o.forEach(["delete","get","head"],function(e){a.headers[e]={}}),o.forEach(["post","put","patch"],function(e){a.headers[e]=o.merge(i)}),e.exports=a},function(e,t,r){"use strict";var n=r(5);e.exports=function(e,t,r,o,s){var i=new Error(e);return n(i,t,r,o,s)}},function(e,t,r){"use strict";e.exports=function(e,t){return function(){for(var r=new Array(arguments.length),n=0;n=300&&e.statusCode<400){if(++this._redirectCount>this._options.maxRedirects)return this.emit("error",new Error("Max redirects exceeded."));var r,n=this._options.headers;if(307!==e.statusCode&&!(this._options.method in l)){this._options.method="GET",this._bufferedWrites=[];for(r in n)/^content-/i.test(r)&&delete n[r]}if(!this._isRedirect)for(r in n)/^host$/i.test(r)&&delete n[r];var s=o.resolve(this._currentUrl,t);c("redirecting to",s),Object.assign(this._options,o.parse(s)),this._isRedirect=!0,this._performRequest()}else e.responseUrl=this._currentUrl,this.emit("response",e),delete this._options,delete this._bufferedWrites},n.prototype.abort=function(){this._currentRequest.abort()},n.prototype.flushHeaders=function(){this._currentRequest.flushHeaders()},n.prototype.setNoDelay=function(e){this._currentRequest.setNoDelay(e)},n.prototype.setSocketKeepAlive=function(e,t){this._currentRequest.setSocketKeepAlive(e,t)},n.prototype.setTimeout=function(e,t){this._currentRequest.setTimeout(e,t)},n.prototype.write=function(e,t,r){this._currentRequest.write(e,t,r),this._bufferedWrites.push({data:e,encoding:t})},n.prototype.end=function(e,t,r){this._currentRequest.end(e,t,r),e&&this._bufferedWrites.push({data:e,encoding:t})},Object.keys(f).forEach(function(e){var r=p[e]=e.substr(0,e.length-1),i=f[e],a=t[r]=Object.create(i);a.request=function(r,i){return"string"==typeof r?(r=o.parse(r),r.maxRedirects=t.maxRedirects):r=Object.assign({maxRedirects:t.maxRedirects,protocol:e},r),s.equal(r.protocol,e,"protocol mismatch"),c("options",r),new n(r,i)},a.get=function(e,t){var r=a.request(e,t);return r.end(),r}})},function(e,t){e.exports=require("url")},function(e,t,r){function n(e){var r,n=0;for(r in e)n=(n<<5)-n+e.charCodeAt(r),n|=0;return t.colors[Math.abs(n)%t.colors.length]}function o(e){function r(){if(r.enabled){var e=r,n=+new Date,o=n-(c||n);e.diff=o,e.prev=c,e.curr=n,c=n;for(var s=new Array(arguments.length),i=0;i 5 | * @license MIT 6 | */ 7 | e.exports=function(e){return null!=e&&(r(e)||n(e)||!!e._isBuffer)}},function(e,t,r){"use strict";function n(e){this.defaults=e,this.interceptors={request:new i,response:new i}}var o=r(1),s=r(0),i=r(44),a=r(45),u=r(47),c=r(48);n.prototype.request=function(e){"string"==typeof e&&(e=s.merge({url:arguments[0]},arguments[1])),e=s.merge(o,this.defaults,{method:"get"},e),e.method=e.method.toLowerCase(),e.baseURL&&!u(e.url)&&(e.url=c(e.baseURL,e.url));var t=[a,void 0],r=Promise.resolve(e);for(this.interceptors.request.forEach(function(e){t.unshift(e.fulfilled,e.rejected)}),this.interceptors.response.forEach(function(e){t.push(e.fulfilled,e.rejected)});t.length;)r=r.then(t.shift(),t.shift());return r},s.forEach(["delete","get","head","options"],function(e){n.prototype[e]=function(t,r){return this.request(s.merge(r||{},{method:e,url:t}))}}),s.forEach(["post","put","patch"],function(e){n.prototype[e]=function(t,r,n){return this.request(s.merge(n||{},{method:e,url:t,data:r}))}}),e.exports=n},function(e,t,r){"use strict";var n=r(0);e.exports=function(e,t){n.forEach(e,function(r,n){n!==t&&n.toUpperCase()===t.toUpperCase()&&(e[t]=r,delete e[n])})}},function(e,t,r){"use strict";var n=r(0),o=r(4),s=r(6),i=r(27),a=r(28),u=r(2),c="undefined"!=typeof window&&window.btoa&&window.btoa.bind(window)||r(29);e.exports=function(e){return new Promise(function(t,f){var p=e.data,l=e.headers;n.isFormData(p)&&delete l["Content-Type"];var d=new XMLHttpRequest,h="onreadystatechange",m=!1;if("undefined"==typeof window||!window.XDomainRequest||"withCredentials"in d||a(e.url)||(d=new window.XDomainRequest,h="onload",m=!0,d.onprogress=function(){},d.ontimeout=function(){}),e.auth){var g=e.auth.username||"",y=e.auth.password||"";l.Authorization="Basic "+c(g+":"+y)}if(d.open(e.method.toUpperCase(),s(e.url,e.params,e.paramsSerializer),!0),d.timeout=e.timeout,d[h]=function(){if(d&&(4===d.readyState||m)&&(0!==d.status||d.responseURL&&0===d.responseURL.indexOf("file:"))){var r="getAllResponseHeaders"in d?i(d.getAllResponseHeaders()):null,n=e.responseType&&"text"!==e.responseType?d.response:d.responseText,s={data:n,status:1223===d.status?204:d.status,statusText:1223===d.status?"No Content":d.statusText,headers:r,config:e,request:d};o(t,f,s),d=null}},d.onerror=function(){f(u("Network Error",e,null,d)),d=null},d.ontimeout=function(){f(u("timeout of "+e.timeout+"ms exceeded",e,"ECONNABORTED",d)),d=null},n.isStandardBrowserEnv()){var v=r(30),b=(e.withCredentials||a(e.url))&&e.xsrfCookieName?v.read(e.xsrfCookieName):void 0;b&&(l[e.xsrfHeaderName]=b)}if("setRequestHeader"in d&&n.forEach(l,function(e,t){void 0===p&&"content-type"===t.toLowerCase()?delete l[t]:d.setRequestHeader(t,e)}),e.withCredentials&&(d.withCredentials=!0),e.responseType)try{d.responseType=e.responseType}catch(t){if("json"!==e.responseType)throw t}"function"==typeof e.onDownloadProgress&&d.addEventListener("progress",e.onDownloadProgress),"function"==typeof e.onUploadProgress&&d.upload&&d.upload.addEventListener("progress",e.onUploadProgress),e.cancelToken&&e.cancelToken.promise.then(function(e){d&&(d.abort(),f(e),d=null)}),void 0===p&&(p=null),d.send(p)})}},function(e,t,r){"use strict";var n=r(0);e.exports=function(e){var t,r,o,s={};return e?(n.forEach(e.split("\n"),function(e){o=e.indexOf(":"),t=n.trim(e.substr(0,o)).toLowerCase(),r=n.trim(e.substr(o+1)),t&&(s[t]=s[t]?s[t]+", "+r:r)}),s):s}},function(e,t,r){"use strict";var n=r(0);e.exports=n.isStandardBrowserEnv()?function(){function e(e){var t=e;return r&&(o.setAttribute("href",t),t=o.href),o.setAttribute("href",t),{href:o.href,protocol:o.protocol?o.protocol.replace(/:$/,""):"",host:o.host,search:o.search?o.search.replace(/^\?/,""):"",hash:o.hash?o.hash.replace(/^#/,""):"",hostname:o.hostname,port:o.port,pathname:"/"===o.pathname.charAt(0)?o.pathname:"/"+o.pathname}}var t,r=/(msie|trident)/i.test(navigator.userAgent),o=document.createElement("a");return t=e(window.location.href),function(r){var o=n.isString(r)?e(r):r;return o.protocol===t.protocol&&o.host===t.host}}():function(){return function(){return!0}}()},function(e,t,r){"use strict";function n(){this.message="String contains an invalid character"}function o(e){for(var t,r,o=String(e),i="",a=0,u=s;o.charAt(0|a)||(u="=",a%1);i+=u.charAt(63&t>>8-a%1*8)){if((r=o.charCodeAt(a+=.75))>255)throw new n;t=t<<8|r}return i}var s="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";n.prototype=new Error,n.prototype.code=5,n.prototype.name="InvalidCharacterError",e.exports=o},function(e,t,r){"use strict";var n=r(0);e.exports=n.isStandardBrowserEnv()?function(){return{write:function(e,t,r,o,s,i){var a=[];a.push(e+"="+encodeURIComponent(t)),n.isNumber(r)&&a.push("expires="+new Date(r).toGMTString()),n.isString(o)&&a.push("path="+o),n.isString(s)&&a.push("domain="+s),!0===i&&a.push("secure"),document.cookie=a.join("; ")},read:function(e){var t=document.cookie.match(new RegExp("(^|;\\s*)("+e+")=([^;]*)"));return t?decodeURIComponent(t[3]):null},remove:function(e){this.write(e,"",Date.now()-864e5)}}}():function(){return{write:function(){},read:function(){return null},remove:function(){}}}()},function(e,t,r){"use strict";var n=r(0),o=r(4),s=r(6),i=r(7),a=r(8),u=r(9).http,c=r(9).https,f=r(10),p=r(42),l=r(43),d=r(2),h=r(5);e.exports=function(e){return new Promise(function(t,r){var m,g=e.data,y=e.headers,v=!1;if(y["User-Agent"]||y["user-agent"]||(y["User-Agent"]="axios/"+l.version),g&&!n.isStream(g)){if(Buffer.isBuffer(g));else if(n.isArrayBuffer(g))g=new Buffer(new Uint8Array(g));else{if(!n.isString(g))return r(d("Data after transformation must be a string, an ArrayBuffer, a Buffer, or a Stream",e));g=new Buffer(g,"utf-8")}y["Content-Length"]=g.length}var b=void 0;if(e.auth){b=(e.auth.username||"")+":"+(e.auth.password||"")}var w=f.parse(e.url),x=w.protocol||"http:";if(!b&&w.auth){var _=w.auth.split(":");b=(_[0]||"")+":"+(_[1]||"")}b&&delete y.Authorization;var k="https:"===x,j=k?e.httpsAgent:e.httpAgent,E={hostname:w.hostname,port:w.port,path:s(w.path,e.params,e.paramsSerializer).replace(/^\?/,""),method:e.method,headers:y,agent:j,auth:b},R=e.proxy;if(!R){var C=x.slice(0,-1)+"_proxy",O=process.env[C]||process.env[C.toUpperCase()];if(O){var S=f.parse(O);if(R={host:S.hostname,port:S.port},S.auth){var A=S.auth.split(":");R.auth={username:A[0],password:A[1]}}}}if(R&&(E.hostname=R.host,E.host=R.host,E.headers.host=w.hostname+(w.port?":"+w.port:""),E.port=R.port,E.path=x+"//"+w.hostname+(w.port?":"+w.port:"")+E.path,R.auth)){var T=new Buffer(R.auth.username+":"+R.auth.password,"utf8").toString("base64");E.headers["Proxy-Authorization"]="Basic "+T}var q;0===e.maxRedirects?q=k?a:i:(e.maxRedirects&&(E.maxRedirects=e.maxRedirects),q=k?c:u);var B=q.request(E,function(n){if(!v){clearTimeout(m),m=null;var s=n;switch(n.headers["content-encoding"]){case"gzip":case"compress":case"deflate":s=s.pipe(p.createUnzip()),delete n.headers["content-encoding"]}var i=n.req||B,a={status:n.statusCode,statusText:n.statusMessage,headers:n.headers,config:e,request:i};if("stream"===e.responseType)a.data=s,o(t,r,a);else{var u=[];s.on("data",function(t){u.push(t),e.maxContentLength>-1&&Buffer.concat(u).length>e.maxContentLength&&r(d("maxContentLength size of "+e.maxContentLength+" exceeded",e,null,i))}),s.on("error",function(t){v||r(h(t,e,null,i))}),s.on("end",function(){var n=Buffer.concat(u);"arraybuffer"!==e.responseType&&(n=n.toString("utf8")),a.data=n,o(t,r,a)})}}});B.on("error",function(t){v||r(h(t,e,null,B))}),e.timeout&&!m&&(m=setTimeout(function(){B.abort(),r(d("timeout of "+e.timeout+"ms exceeded",e,"ECONNABORTED",B)),v=!0},e.timeout)),e.cancelToken&&e.cancelToken.promise.then(function(e){v||(B.abort(),r(e),v=!0)}),n.isStream(g)?g.pipe(B):B.end(g)})}},function(e,t){e.exports=require("assert")},function(e,t){e.exports=require("stream")},function(e,t,r){"undefined"!=typeof process&&"renderer"===process.type?e.exports=r(35):e.exports=r(37)},function(e,t,r){function n(){return!("undefined"==typeof window||!window.process||"renderer"!==window.process.type)||("undefined"!=typeof document&&document.documentElement&&document.documentElement.style&&document.documentElement.style.WebkitAppearance||"undefined"!=typeof window&&window.console&&(window.console.firebug||window.console.exception&&window.console.table)||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/firefox\/(\d+)/)&&parseInt(RegExp.$1,10)>=31||"undefined"!=typeof navigator&&navigator.userAgent&&navigator.userAgent.toLowerCase().match(/applewebkit\/(\d+)/))}function o(e){var r=this.useColors;if(e[0]=(r?"%c":"")+this.namespace+(r?" %c":" ")+e[0]+(r?"%c ":" ")+"+"+t.humanize(this.diff),r){var n="color: "+this.color;e.splice(1,0,n,"color: inherit");var o=0,s=0;e[0].replace(/%[a-zA-Z%]/g,function(e){"%%"!==e&&(o++,"%c"===e&&(s=o))}),e.splice(s,0,n)}}function s(){return"object"==typeof console&&console.log&&Function.prototype.apply.call(console.log,console,arguments)}function i(e){try{null==e?t.storage.removeItem("debug"):t.storage.debug=e}catch(e){}}function a(){var e;try{e=t.storage.debug}catch(e){}return!e&&"undefined"!=typeof process&&"env"in process&&(e=process.env.DEBUG),e}t=e.exports=r(11),t.log=s,t.formatArgs=o,t.save=i,t.load=a,t.useColors=n,t.storage="undefined"!=typeof chrome&&void 0!==chrome.storage?chrome.storage.local:function(){try{return window.localStorage}catch(e){}}(),t.colors=["lightseagreen","forestgreen","goldenrod","dodgerblue","darkorchid","crimson"],t.formatters.j=function(e){try{return JSON.stringify(e)}catch(e){return"[UnexpectedJSONParseError]: "+e.message}},t.enable(a())},function(e,t){function r(e){if(e=String(e),!(e.length>100)){var t=/^((?:\d+)?\.?\d+) *(milliseconds?|msecs?|ms|seconds?|secs?|s|minutes?|mins?|m|hours?|hrs?|h|days?|d|years?|yrs?|y)?$/i.exec(e);if(t){var r=parseFloat(t[1]);switch((t[2]||"ms").toLowerCase()){case"years":case"year":case"yrs":case"yr":case"y":return r*f;case"days":case"day":case"d":return r*c;case"hours":case"hour":case"hrs":case"hr":case"h":return r*u;case"minutes":case"minute":case"mins":case"min":case"m":return r*a;case"seconds":case"second":case"secs":case"sec":case"s":return r*i;case"milliseconds":case"millisecond":case"msecs":case"msec":case"ms":return r;default:return}}}}function n(e){return e>=c?Math.round(e/c)+"d":e>=u?Math.round(e/u)+"h":e>=a?Math.round(e/a)+"m":e>=i?Math.round(e/i)+"s":e+"ms"}function o(e){return s(e,c,"day")||s(e,u,"hour")||s(e,a,"minute")||s(e,i,"second")||e+" ms"}function s(e,t,r){if(!(e0)return r(e);if("number"===s&&!1===isNaN(e))return t.long?o(e):n(e);throw new Error("val is not a non-empty string or a valid number. val="+JSON.stringify(e))}},function(e,t,r){function n(){return"colors"in t.inspectOpts?Boolean(t.inspectOpts.colors):c.isatty(p)}function o(e){var r=this.namespace;if(this.useColors){var n=this.color,o=" [3"+n+";1m"+r+" ";e[0]=o+e[0].split("\n").join("\n"+o),e.push("[3"+n+"m+"+t.humanize(this.diff)+"")}else e[0]=(new Date).toUTCString()+" "+r+" "+e[0]}function s(){return l.write(f.format.apply(f,arguments)+"\n")}function i(e){null==e?delete process.env.DEBUG:process.env.DEBUG=e}function a(){return process.env.DEBUG}function u(e){e.inspectOpts={};for(var r=Object.keys(t.inspectOpts),n=0;n", 25 | "license": "MIT", 26 | "dependencies": { 27 | "axios": "^0.16.2", 28 | "prop-types": "^15.5.10", 29 | "react": "^15.6.1", 30 | "react-bootstrap": "^0.31.0", 31 | "react-dom": "^15.6.1", 32 | "react-highlight": "^0.10.0" 33 | }, 34 | "devDependencies": { 35 | "autoprefixer": "^7.1.2", 36 | "babel-core": "^6.25.0", 37 | "babel-eslint": "^7.2.3", 38 | "babel-loader": "^7.1.1", 39 | "babel-plugin-transform-class-properties": "^6.24.1", 40 | "babel-preset-es2015": "^6.24.1", 41 | "babel-preset-react": "^6.24.1", 42 | "babel-preset-stage-0": "^6.24.1", 43 | "copy-webpack-plugin": "^4.0.1", 44 | "css-loader": "^0.28.4", 45 | "eslint": "^3.19.0", 46 | "eslint-config-airbnb": "^15.0.2", 47 | "eslint-loader": "^1.9.0", 48 | "eslint-plugin-import": "^2.6.1", 49 | "eslint-plugin-jsx-a11y": "^5.1.1", 50 | "eslint-plugin-react": "^7.1.0", 51 | "eslint_d": "^5.0.0", 52 | "extract-text-webpack-plugin": "^2.1.2", 53 | "jasmine-core": "^2.6.4", 54 | "jasmine-react-matchers": "^1.0.2", 55 | "karma": "^1.7.0", 56 | "karma-chrome-launcher": "^2.2.0", 57 | "karma-cli": "^1.0.1", 58 | "karma-jasmine": "^1.1.0", 59 | "karma-sourcemap-loader": "^0.3.7", 60 | "karma-webpack": "^2.0.3", 61 | "mock-promises": "^0.8.2", 62 | "node-sass": "^4.5.3", 63 | "postcss-loader": "^2.0.6", 64 | "promise-mock": "^1.1.1", 65 | "react-addons-test-utils": "^15.6.0", 66 | "sass-loader": "^6.0.6", 67 | "style-loader": "^0.18.2", 68 | "webpack": "^3.0.0", 69 | "webpack-dev-server": "^2.5.0" 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/DadJoke.jsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import axios from 'axios'; 4 | 5 | const BASE_API_URL = 'https://icanhazdadjoke.com'; 6 | 7 | export default class DadJoke extends React.Component { 8 | constructor(props) { 9 | super(props); 10 | this.state = { 11 | joke: null, 12 | }; 13 | this.loadJoke = this.loadJoke.bind(this); 14 | } 15 | 16 | componentDidMount() { 17 | this.loadJoke(); 18 | } 19 | 20 | loadJoke() { 21 | let url = BASE_API_URL; 22 | 23 | if (this.props.jokeID) { 24 | url += `/j/${ this.props.jokeID }`; 25 | } 26 | axios.get(url, { 27 | headers: { 28 | Accept: 'application/json', 29 | }, 30 | }).then((res) => { 31 | this.setState({ joke: { id: res.data.id, text: res.data.joke }}); 32 | }); 33 | } 34 | 35 | render() { 36 | const { className, img, refreshButton, refreshButtonClassName } = this.props; 37 | const { joke } = this.state; 38 | if (!joke) { 39 | return
; 40 | } 41 | return ( 42 | img ? 43 | { : 44 |
45 |
46 | { joke.text } 47 |
48 | { 49 | refreshButton && 50 | 51 | } 52 |
53 | ); 54 | } 55 | } 56 | 57 | DadJoke.propTypes = { 58 | className: PropTypes.string, 59 | jokeID: PropTypes.string, 60 | img: PropTypes.bool, 61 | refreshButton: PropTypes.bool, 62 | refreshButtonClassName: PropTypes.string, 63 | }; 64 | 65 | DadJoke.defaultProps = { 66 | className: 'dad-joke', 67 | jokeID: null, 68 | img: false, 69 | refreshButton: false, 70 | refreshButtonClassName: 'dad-joke__refresh-button', 71 | }; 72 | -------------------------------------------------------------------------------- /src/components/react-dadjoke.jsx: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import PropTypes from "prop-types"; 3 | import axios from "axios"; 4 | 5 | const BASE_API_URL = "https://icanhazdadjoke.com"; 6 | 7 | export default class DadJoke extends React.Component { 8 | constructor(props) { 9 | super(props); 10 | this.state = { 11 | joke: null 12 | }; 13 | this.loadJoke = this.loadJoke.bind(this); 14 | } 15 | 16 | componentDidMount() { 17 | this.loadJoke(); 18 | } 19 | 20 | loadJoke() { 21 | let url = BASE_API_URL; 22 | 23 | if (this.props.jokeID) { 24 | url += `/j/${ this.props.jokeID }`; 25 | } 26 | axios.get(url, { 27 | headers: { 28 | "Accept": "application/json" 29 | } 30 | }).then((res) => { 31 | this.setState({ joke: { id: res.data.id, text: res.data.joke }}); 32 | }); 33 | } 34 | 35 | render() { 36 | const { className, img, refreshButton, refreshButtonClassName } = this.props; 37 | const { joke } = this.state; 38 | if (!joke) { 39 |
; 40 | } 41 | return ( 42 | img ? 43 | : 44 |
45 | { joke.text } 46 | { 47 | refreshButton && 48 | 49 | } 50 |
51 | ); 52 | } 53 | } 54 | 55 | DadJoke.propTypes = { 56 | className: PropTypes.string, 57 | jokeID: PropTypes.string, 58 | img: PropTypes.bool, 59 | refreshButton: PropTypes.bool, 60 | refreshButtonClassName: PropTypes.string 61 | }; 62 | 63 | DadJoke.defaultProps = { 64 | className: "dad-joke", 65 | jokeID: null, 66 | img: false, 67 | refreshButton: false, 68 | refreshButtonClassName: "dad-joke__refresh-button" 69 | }; 70 | -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | DadJoke: 3 | require("./components/react-dadjoke") 4 | }; 5 | -------------------------------------------------------------------------------- /test/client/main.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Test setup for client-side tests. 3 | * 4 | * Intended for: 5 | * - Karma tests: `builder run test-frontend` 6 | * - Browser tests: `http://localhost:3000/test/client/test.html` 7 | */ 8 | /*globals window:false*/ 9 | const chai = require("chai"); 10 | const sinonChai = require("sinon-chai"); 11 | 12 | // -------------------------------------------------------------------------- 13 | // Chai / Sinon / Mocha configuration. 14 | // -------------------------------------------------------------------------- 15 | // Exports 16 | window.expect = chai.expect; 17 | 18 | // Plugins 19 | chai.use(sinonChai); 20 | 21 | // Mocha (part of static include). 22 | window.mocha.setup({ 23 | ui: "bdd", 24 | bail: false 25 | }); 26 | 27 | // -------------------------------------------------------------------------- 28 | // Bootstrap 29 | // -------------------------------------------------------------------------- 30 | // Use webpack to include all app code _except_ the entry point so we can get 31 | // code coverage in the bundle, whether tested or not. 32 | const srcReq = require.context("src", true, /\.jsx?$/); 33 | srcReq.keys().map(srcReq); 34 | 35 | // Use webpack to infer and `require` tests automatically. 36 | const testsReq = require.context(".", true, /\.spec.jsx?$/); 37 | testsReq.keys().map(testsReq); 38 | 39 | // Only start mocha in browser. 40 | if (!window.__karma__) { 41 | window.mocha.run(); 42 | } 43 | -------------------------------------------------------------------------------- /test/client/spec/components/react-dadjoke.spec.jsx: -------------------------------------------------------------------------------- 1 | /** 2 | * Client tests 3 | */ 4 | import React from "react"; 5 | import Component from "src/components/react-dadjoke"; 6 | import TestUtils from "react-addons-test-utils"; 7 | 8 | describe("components/react-dadjoke", () => { 9 | 10 | it("has expected content with deep render"); 11 | 12 | it("has expected content with shallow render"); 13 | }); 14 | -------------------------------------------------------------------------------- /test/client/test.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Frontend Tests 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const path = require('path'); 3 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 4 | const autoprefixer = require('autoprefixer'); 5 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 6 | 7 | module.exports = { 8 | entry: './demo/index.jsx', 9 | output: { 10 | path: path.join(__dirname, './demo/dist'), 11 | filename: 'index.js' 12 | }, 13 | module: { 14 | loaders: [ 15 | { 16 | test: /\.s?css$/, 17 | loader: ExtractTextPlugin.extract({ 18 | fallback: 'style-loader', 19 | use: [{ 20 | loader: 'css-loader', 21 | options: { 22 | sourceMap: true 23 | } 24 | }, { 25 | loader: 'sass-loader', 26 | options: { 27 | includePaths: [path.resolve(__dirname, './src'), path.resolve(__dirname, './demo')] 28 | } 29 | }, { 30 | loader: 'postcss-loader', 31 | options: { 32 | plugins: [autoprefixer({ browsers: ['last 2 versions'] })] 33 | } 34 | }] 35 | }), 36 | }, 37 | { 38 | test: /\.jsx?$/, 39 | exclude: /(node_modules|bower_components)/, 40 | loaders: [ 41 | 'babel-loader?cacheDirectory&presets[]=react,presets[]=es2015,presets[]=stage-0', 42 | 'eslint-loader', 43 | ], 44 | }, 45 | ], 46 | }, 47 | plugins: [ 48 | new ExtractTextPlugin({ filename: 'main.css', allChunks: true }), 49 | new CopyWebpackPlugin([ 50 | {from: 'demo/index.html'}, 51 | ]), 52 | new webpack.optimize.UglifyJsPlugin(), 53 | new webpack.DefinePlugin({ 54 | 'process.env.NODE_ENV': JSON.stringify('production') 55 | }), 56 | ], 57 | resolve: { 58 | extensions: ['.js', '.json', '.jsx'], 59 | modules: ['src', 'node_modules'] 60 | }, 61 | }; 62 | -------------------------------------------------------------------------------- /webpack.dist.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const path = require('path'); 3 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 4 | const config = require('./webpack.config'); 5 | 6 | config.entry = './src/DadJoke.jsx'; 7 | config.output = { 8 | path: path.join(__dirname, './dist'), 9 | filename: 'DadJoke.js', 10 | library: 'DadJoke', 11 | libraryTarget: 'commonjs2', 12 | }; 13 | config.externals = { 14 | react: 'react', 15 | }; 16 | config.target = 'node'; 17 | config.plugins = [ 18 | new ExtractTextPlugin({filename: 'DadJoke.css', allChunks: true }), 19 | new webpack.optimize.UglifyJsPlugin(), 20 | new webpack.DefinePlugin({ 21 | 'process.env.NODE_ENV': JSON.stringify('production') 22 | }), 23 | ]; 24 | 25 | module.exports = config; 26 | -------------------------------------------------------------------------------- /webpack.standalone.config.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const path = require('path'); 3 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 4 | const config = require('./webpack.dist.config'); 5 | 6 | // Complete 7 | const conf1 = Object.assign({}, config); 8 | conf1.output = Object.assign({}, conf1.output, { 9 | path: path.join(__dirname, './dist/standalone'), 10 | libraryTarget: 'umd', 11 | }); 12 | conf1.externals = { 13 | react: 'react', 14 | }; 15 | conf1.target = 'web'; 16 | 17 | // Minified 18 | const conf2 = Object.assign({}, conf1); 19 | conf2.output = Object.assign({}, conf2.output, { 20 | filename: 'DadJoke.min.js', 21 | }); 22 | conf2.plugins = [ 23 | new ExtractTextPlugin('DadJoke.min.css', {allChunks: true}), 24 | new webpack.DefinePlugin({ 25 | 'process.env': { 26 | NODE_ENV: JSON.stringify('production'), 27 | }, 28 | }), 29 | new webpack.optimize.UglifyJsPlugin({ 30 | output: { 31 | comments: false, 32 | }, 33 | compress: { 34 | warnings: false, 35 | }, 36 | }), 37 | ]; 38 | 39 | module.exports = [conf1, conf2]; 40 | --------------------------------------------------------------------------------