add react-express-mysql application sample
Signed-off-by: Anca Iordache <anca.iordache@docker.com>
This commit is contained in:
		
							
								
								
									
										36
									
								
								samples/react-express-mysql/backend/Dockerfile
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										36
									
								
								samples/react-express-mysql/backend/Dockerfile
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| # if you're doing anything beyond your local machine, please pin this to a specific version at https://hub.docker.com/_/node/ | ||||
| FROM node:10 | ||||
|  | ||||
| RUN mkdir -p /opt/app | ||||
|  | ||||
| # set our node environment, either development or production | ||||
| # defaults to production, compose overrides this to development on build and run | ||||
| ARG NODE_ENV=production | ||||
| ENV NODE_ENV $NODE_ENV | ||||
|  | ||||
| # default to port 80 for node, and 9229 and 9230 (tests) for debug | ||||
| ARG PORT=80 | ||||
| ENV PORT $PORT | ||||
| EXPOSE $PORT 9229 9230 | ||||
|  | ||||
| # you'll likely want the latest npm, reguardless of node version, for speed and fixes | ||||
| RUN npm i npm@latest -g | ||||
|  | ||||
| # install dependencies first, in a different location for easier app bind mounting for local development | ||||
| WORKDIR /opt | ||||
| COPY package.json package-lock.json* ./ | ||||
| RUN npm install && npm cache clean --force | ||||
| ENV PATH /opt/node_modules/.bin:$PATH | ||||
|  | ||||
| # check every 30s to ensure this service returns HTTP 200 | ||||
| HEALTHCHECK --interval=30s CMD node healthcheck.js | ||||
|  | ||||
| # copy in our source code last, as it changes the most | ||||
| WORKDIR /opt/app | ||||
| COPY . /opt/app | ||||
|  | ||||
| # if you want to use npm start instead, then use `docker run --init in production` | ||||
| # so that signals are passed properly. Note the code in index.js is needed to catch Docker signals | ||||
| # using node here is still more graceful stopping then npm with --init afaik | ||||
| # I still can't come up with a good production way to run with npm and graceful shutdown | ||||
| CMD [ "node", "index.js" ] | ||||
							
								
								
									
										21
									
								
								samples/react-express-mysql/backend/LICENSE
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										21
									
								
								samples/react-express-mysql/backend/LICENSE
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| MIT License | ||||
|  | ||||
| Copyright (c) 2015-2017 Bret Fisher | ||||
|  | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
| in the Software without restriction, including without limitation the rights | ||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copies of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
|  | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
|  | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| SOFTWARE. | ||||
							
								
								
									
										86
									
								
								samples/react-express-mysql/backend/README.md
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										86
									
								
								samples/react-express-mysql/backend/README.md
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,86 @@ | ||||
| ## Node + Docker Hello World, for Showing Good Defaults for Using Node.js in Docker | ||||
|  | ||||
| > This tries to be a "good defaults" example of using Node.js in Docker for local development and shipping to production with all the bells, whistles, and best practices. Issues/PR welcome. | ||||
|  | ||||
| ### Local Development Features | ||||
|  | ||||
|  - **Dev as close to prod as you can**. docker-compose builds a local development image that is just like production image except for the below dev-only features needed in image. Goal is to have dev env be as close to test and prod as possible while still giving all the nice tools to make you a happy dev. | ||||
|  - **Prevent needing node/npm on host**. Installs `node_modules` outside app root in container so local development won't run into a problem of bind-mounting over it with local source code. This means it will run `npm install` once on container build and you don't need to run npm on host or on each docker run. It will re-run on build if you change `package.json`. | ||||
|  - **One line startup**. Uses `docker-compose up` for single-line build and run of local development server. | ||||
|  - **Edit locally while code runs in container**. docker-compose uses proper bind-mounts of host source code into container so you can edit locally while running code in Linux container. | ||||
|  - **Use nodemon in container**. docker-compose uses nodemon for development for auto-restarting node in container when you change files on host. | ||||
|  - **Enable debug from host to container**. opens the inspect port 9229 for using host-based debugging like chrome tools or VS Code. Nodemon enables `--inspect` by default in docker-compose. | ||||
|  - **Provides VSCode debug configs and tasks for tests**. for Visual Studio Code fans, `.vscode` directory has the goods, thanks to @JPLemelin. | ||||
|  - **Small image and quick re-builds**. `COPY` in `package.json` and run `npm install` **before** `COPY` in your source code. This saves big on build time and keep container lean. | ||||
|  - **Bind-mount package.json**. This allows adding packages in realtime without rebuilding images. e.g. `dce node npm install --save <package name>` | ||||
|  | ||||
|  | ||||
| ### Production-minded Features | ||||
|  | ||||
|  - **Use Docker build-in healthchecks**. uses Dockerfile `HEALTHCHECK` with `/healthz` route to help Docker know if your container is running properly (example always returns 200, but you get the idea). | ||||
|  - **Proper NODE_ENV use**. Defaults to `NODE_ENV=production` in Dockerfile and overrides to `development` in docker-compose for local dev. | ||||
|  - **Don't add dev dependencies into production image**. Proper `NODE_ENV` use means dev dependencies won't be installed in container by default. Using docker-compose will build with them by default. | ||||
|  - **Enables proper SIGTERM/SIGINT for graceful exit**. Defaults to `node index.js` rather then npm for allowing graceful shutdown of node. npm doesn't pass SIGTERM/SIGINT properly (you can't ctrl-c when running `docker run` in foreground). To get `node index.js` to graceful exit, extra signal-catching code is needed. The `Dockerfile` and `index.js` document the options and links to known issues. | ||||
|  - **Use docker-stack.yml example for Docker Swarm deployments**. | ||||
|  | ||||
|  | ||||
| ### Assumptions | ||||
|  | ||||
|  - You have Docker and Docker-Compose installed (Docker for Mac, Docker for Windows, get.docker.com and manual Compose installed for Linux). | ||||
|  - You want to use Docker for local development (i.e. never need to install node/npm on host) and have dev and prod Docker images be as close as possible. | ||||
|  - You don't want to loose fidelity in your dev workflow. You want a easy environment setup, using local editors, node debug/inspect, local code repo, while node server runs in a container. | ||||
|  - You use `docker-compose` for local development only (docker-compose was never intended to be a production deployment tool anyway). | ||||
|  - The `docker-compose.yml` is not meant for `docker stack deploy` in Docker Swarm, it's meant for happy local development. Use `docker-stack.yml` for Swarm. | ||||
|  | ||||
|   | ||||
| ### Getting Started | ||||
|  | ||||
| If this was your Node.js app, to start local development you would: | ||||
|  | ||||
|  - Running `docker-compose up` is all you need. It will: | ||||
|  - Build custom local image enabled for development (nodemon, `NODE_ENV=development`). | ||||
|  - Start container from that image with ports 80 and 9229 open (on localhost). | ||||
|  - Starts with `nodemon` to restart node on file change in host pwd. | ||||
|  - Mounts the pwd to the app dir in container. | ||||
|  - If you need other services like databases, just add to compose file and they'll be added to the custom Docker network for this app on `up`. | ||||
|  - Compose should detect if you need to rebuild due to changed package.json or Dockerfile, but `docker-compose build` works for manually building. | ||||
|  - Be sure to use `docker-compose down` to cleanup after your done dev'ing. | ||||
|  | ||||
| If you wanted to add a package while docker-compose was running your app: | ||||
|  - `docker-compose exec node npm install --save <package name>` | ||||
|  - This installs it inside the running container. | ||||
|  - Nodemon will detect the change and restart. | ||||
|  - `--save` will add it to the package.json for next `docker-compose build` | ||||
|  | ||||
| To execute the unit-tests, you would: | ||||
|  - Execute `docker-compose exec node npm test`, It will: | ||||
|  - Run a process `npm test` in the container node. | ||||
|  - You can use the *vscode* to debug unit-tests with config `Docker Test (Attach 9230 --inspect)`, It will: | ||||
|    - Start a debugging process in the container and wait-for-debugger, this is done by *vscode tasks* | ||||
|    - It will also kill previous debugging process if existing. | ||||
|  | ||||
| ### Other Resources | ||||
|  | ||||
|  - https://blog.hasura.io/an-exhaustive-guide-to-writing-dockerfiles-for-node-js-web-apps-bbee6bd2f3c4 | ||||
|  | ||||
| MIT License,  | ||||
|  | ||||
| Copyright (c) 2015-2018 Bret Fisher | ||||
|  | ||||
| Permission is hereby granted, free of charge, to any person obtaining a copy | ||||
| of this software and associated documentation files (the "Software"), to deal | ||||
| in the Software without restriction, including without limitation the rights | ||||
| to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | ||||
| copies of the Software, and to permit persons to whom the Software is | ||||
| furnished to do so, subject to the following conditions: | ||||
|  | ||||
| The above copyright notice and this permission notice shall be included in all | ||||
| copies or substantial portions of the Software. | ||||
|  | ||||
| THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||||
| IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||||
| FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||||
| AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||||
| LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | ||||
| OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE | ||||
| SOFTWARE. | ||||
							
								
								
									
										21
									
								
								samples/react-express-mysql/backend/healthcheck.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										21
									
								
								samples/react-express-mysql/backend/healthcheck.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| var http = require("http"); | ||||
|  | ||||
| var options = { | ||||
|   timeout: 2000, | ||||
|   host: 'localhost', | ||||
|   port: process.env.PORT || 8080, | ||||
|   path: '/healthz' // must be the same as HEALTHCHECK in Dockerfile | ||||
| }; | ||||
|  | ||||
| var request = http.request(options, (res) => { | ||||
|   console.info('STATUS: ' + res.statusCode); | ||||
|   process.exitCode = (res.statusCode === 200) ? 0 : 1; | ||||
|   process.exit(); | ||||
| }); | ||||
|  | ||||
| request.on('error', function(err) { | ||||
|   console.error('ERROR', err); | ||||
|   process.exit(1); | ||||
| }); | ||||
|  | ||||
| request.end(); | ||||
							
								
								
									
										78
									
								
								samples/react-express-mysql/backend/index.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										78
									
								
								samples/react-express-mysql/backend/index.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,78 @@ | ||||
| // simple node web server that displays hello world | ||||
| // optimized for Docker image | ||||
|  | ||||
| var express = require('express'); | ||||
| // this example uses express web framework so we know what longer build times | ||||
| // do and how Dockerfile layer ordering matters. If you mess up Dockerfile ordering | ||||
| // you'll see long build times on every code change + build. If done correctly, | ||||
| // code changes should be only a few seconds to build locally due to build cache. | ||||
|  | ||||
| var morgan = require('morgan'); | ||||
| // morgan provides easy logging for express, and by default it logs to stdout | ||||
| // which is a best practice in Docker. Friends don't let friends code their apps to | ||||
| // do app logging to files in containers. | ||||
|  | ||||
| // Constants | ||||
| const PORT = process.env.PORT || 8080; | ||||
| // if you're not using docker-compose for local development, this will default to 8080 | ||||
| // to prevent non-root permission problems with 80. Dockerfile is set to make this 80 | ||||
| // because containers don't have that issue :) | ||||
|  | ||||
| // Appi | ||||
| var app = express(); | ||||
|  | ||||
| app.use(morgan('common')); | ||||
|  | ||||
| app.get('/', function (req, res) { | ||||
|   res.send('Hello Docker World\n'); | ||||
| }); | ||||
|  | ||||
| app.get('/healthz', function (req, res) { | ||||
| 	// do app logic here to determine if app is truly healthy | ||||
| 	// you should return 200 if healthy, and anything else will fail | ||||
| 	// if you want, you should be able to restrict this to localhost (include ipv4 and ipv6) | ||||
|   res.send('I am happy and healthy\n'); | ||||
| }); | ||||
|  | ||||
| var server = app.listen(PORT, function () { | ||||
|   console.log('Webserver is ready'); | ||||
| }); | ||||
|  | ||||
|  | ||||
| // | ||||
| // need this in docker container to properly exit since node doesn't handle SIGINT/SIGTERM | ||||
| // this also won't work on using npm start since: | ||||
| // https://github.com/npm/npm/issues/4603 | ||||
| // https://github.com/npm/npm/pull/10868 | ||||
| // https://github.com/RisingStack/kubernetes-graceful-shutdown-example/blob/master/src/index.js | ||||
| // if you want to use npm then start with `docker run --init` to help, but I still don't think it's | ||||
| // a graceful shutdown of node process | ||||
| // | ||||
|  | ||||
| // quit on ctrl-c when running docker in terminal | ||||
| process.on('SIGINT', function onSigint () { | ||||
| 	console.info('Got SIGINT (aka ctrl-c in docker). Graceful shutdown ', new Date().toISOString()); | ||||
|   shutdown(); | ||||
| }); | ||||
|  | ||||
| // quit properly on docker stop | ||||
| process.on('SIGTERM', function onSigterm () { | ||||
|   console.info('Got SIGTERM (docker container stop). Graceful shutdown ', new Date().toISOString()); | ||||
|   shutdown(); | ||||
| }) | ||||
|  | ||||
| // shut down server | ||||
| function shutdown() { | ||||
|   server.close(function onServerClosed (err) { | ||||
|     if (err) { | ||||
|       console.error(err); | ||||
|       process.exitCode = 1; | ||||
| 		} | ||||
| 		process.exit(); | ||||
|   }) | ||||
| } | ||||
| // | ||||
| // need above in docker container to properly exit | ||||
| // | ||||
|  | ||||
| module.exports = app; | ||||
							
								
								
									
										3305
									
								
								samples/react-express-mysql/backend/package-lock.json
									
									
									
										generated
									
									
									
										Executable file
									
								
							
							
						
						
									
										3305
									
								
								samples/react-express-mysql/backend/package-lock.json
									
									
									
										generated
									
									
									
										Executable file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										29
									
								
								samples/react-express-mysql/backend/package.json
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										29
									
								
								samples/react-express-mysql/backend/package.json
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| { | ||||
|   "name": "node-docker-good-defaults", | ||||
|   "private": true, | ||||
|   "version": "2.0.0", | ||||
|   "description": "Node.js Hello world app using docker features for easy docker-compose local dev and solid production defaults", | ||||
|   "author": "Bret Fisher <bret@bretfisher.com>", | ||||
|   "main": "index.js", | ||||
|   "scripts": { | ||||
|     "start": "node index.js", | ||||
|     "dev-docker": "../node_modules/nodemon/bin/nodemon.js --debug=5858", | ||||
|     "dev-host": "nodemon --debug=5858", | ||||
|     "start-watch": "nodemon index.js --inspect=0.0.0.0:9229", | ||||
|     "start-wait-debuger": "nodemon index.js --inspect-brk=0.0.0.0:9229", | ||||
|     "test": "cross-env NODE_ENV=test PORT=8081 mocha --timeout 10000 --exit --inspect=0.0.0.0:9230", | ||||
|     "test-watch": "nodemon --exec \"npm test\"", | ||||
|     "test-wait-debuger": "cross-env NODE_ENV=test PORT=8081 mocha --no-timeouts --exit --inspect-brk=0.0.0.0:9230" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "express": "^4.16.3", | ||||
|     "morgan": "^1.8.1" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "chai": "^4.1.2", | ||||
|     "chai-http": "^4.0.0", | ||||
|     "cross-env": "^5.1.4", | ||||
|     "mocha": "^5.0.5", | ||||
|     "nodemon": "^1.17.5" | ||||
|   } | ||||
| } | ||||
							
								
								
									
										32
									
								
								samples/react-express-mysql/backend/test/sample.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										32
									
								
								samples/react-express-mysql/backend/test/sample.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| const app = require('../index'); | ||||
|  | ||||
| const chai = require('chai'); | ||||
| const chaiHttp = require('chai-http'); | ||||
|  | ||||
| chai.use(chaiHttp); | ||||
| chai.should(); | ||||
|  | ||||
| describe('API /healthz', () => { | ||||
|     it('it should return 200', (done) => { | ||||
|         chai.request(app) | ||||
|             .get('/healthz') | ||||
|             .end((err, res) => { | ||||
|                 res.should.have.status(200); | ||||
|                 done(); | ||||
|             }); | ||||
|     }); | ||||
| }); | ||||
|  | ||||
| describe('API /', () => { | ||||
|     it('it should return Welcome message', (done) => { | ||||
|         chai.request(app) | ||||
|             .get('/') | ||||
|             .end((err, res) => { | ||||
|                 res.should.have.status(200); | ||||
|                 res.should.to.be.html; | ||||
|                 res.text.should.be.equal("Hello Docker World\n"); | ||||
|                 done(); | ||||
|             }); | ||||
|     }); | ||||
| }); | ||||
|  | ||||
							
								
								
									
										1
									
								
								samples/react-express-mysql/db/password.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								samples/react-express-mysql/db/password.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| db-btf5q | ||||
							
								
								
									
										46
									
								
								samples/react-express-mysql/docker-compose.yaml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								samples/react-express-mysql/docker-compose.yaml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| version: "3.7" | ||||
| services: | ||||
|   backend: | ||||
|     build: | ||||
|       args: | ||||
|       - NODE_ENV=development | ||||
|       context: backend | ||||
|     command: ../node_modules/.bin/nodemon --inspect=0.0.0.0:9229 | ||||
|     environment: | ||||
|     - NODE_ENV=development | ||||
|     ports: | ||||
|     - 8080:80 | ||||
|     - 9229:9229 | ||||
|     - 9230:9230 | ||||
|     volumes: | ||||
|     - ./backend:/opt/app:delegated | ||||
|     - ./backend/package.json:/opt/package.json | ||||
|     - ./backend/package-lock.json:/opt/package-lock.json | ||||
|     - back-notused:/opt/app/node_modules | ||||
|     depends_on:  | ||||
|       - db | ||||
|   db: | ||||
|     environment: | ||||
|       MYSQL_DATABASE: example | ||||
|       MYSQL_ROOT_PASSWORD_FILE: /run/secrets/db-password | ||||
|     image: mysql:5.7 | ||||
|     restart: always | ||||
|     secrets: | ||||
|     - db-password | ||||
|     volumes: | ||||
|     - db-data:/var/lib/mysql | ||||
|   frontend: | ||||
|     build: frontend | ||||
|     ports: | ||||
|     - 80:9000 | ||||
|     volumes: | ||||
|     - ./frontend:/project | ||||
|     - /project/node_modules | ||||
|     depends_on:  | ||||
|     - backend | ||||
| volumes: | ||||
|   back-notused: {} | ||||
|   db-data: {} | ||||
| secrets: | ||||
|   db-password: | ||||
|     file: db/password.txt | ||||
							
								
								
									
										23
									
								
								samples/react-express-mysql/frontend/.babelrc
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										23
									
								
								samples/react-express-mysql/frontend/.babelrc
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| { | ||||
|   "presets": [ | ||||
|     [ | ||||
|       "env", | ||||
|       { | ||||
|         "loose": true, | ||||
|         "modules": false | ||||
|       } | ||||
|     ], | ||||
|     "react" | ||||
|   ], | ||||
|   "plugins": [ | ||||
|     "react-hot-loader/babel", | ||||
|     "transform-runtime", | ||||
|     "transform-object-rest-spread", | ||||
|     "lodash" | ||||
|   ], | ||||
|   "env": { | ||||
|     "test": { | ||||
|       "plugins": ["transform-es2015-modules-commonjs"] | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										5
									
								
								samples/react-express-mysql/frontend/.browserslistrc
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										5
									
								
								samples/react-express-mysql/frontend/.browserslistrc
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| > 1% | ||||
| last 3 versions | ||||
| Firefox ESR | ||||
| Opera 12.1 | ||||
| IE >= 10 | ||||
							
								
								
									
										2
									
								
								samples/react-express-mysql/frontend/.dockerignore
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										2
									
								
								samples/react-express-mysql/frontend/.dockerignore
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| node_modules | ||||
| .happypack | ||||
							
								
								
									
										1
									
								
								samples/react-express-mysql/frontend/.eslintignore
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										1
									
								
								samples/react-express-mysql/frontend/.eslintignore
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1 @@ | ||||
| webpack/* | ||||
							
								
								
									
										36
									
								
								samples/react-express-mysql/frontend/.eslintrc
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										36
									
								
								samples/react-express-mysql/frontend/.eslintrc
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,36 @@ | ||||
| { | ||||
|   "extends": [ | ||||
|     "standard", | ||||
|     "standard-react", | ||||
|     "plugin:jsx-a11y/recommended" | ||||
|   ], | ||||
|   "env": { | ||||
|     "es6"     : true, | ||||
|     "browser" : true, | ||||
|     "node"    : true, | ||||
|     "jest"    : true | ||||
|   }, | ||||
|   "plugins": [ | ||||
|     "react", | ||||
|     "import" | ||||
|   ], | ||||
|   "parser": "babel-eslint", | ||||
|   "parserOptions": { | ||||
|     "sourceType": "module" | ||||
|   }, | ||||
|   "rules" : { | ||||
|     "no-eq-null" : 0, | ||||
|     "quotes": 0, | ||||
|     "eol-last": 0, | ||||
|     "semi": [2, "always"], | ||||
|     "key-spacing": [1, {"beforeColon": true, "afterColon": true, "mode": "minimum", "align": "colon"}], | ||||
|     "padded-blocks": [1, { "switches": "never", "classes" : "always"}], | ||||
|     "space-before-function-paren": ["error", "never"], | ||||
|     "indent": [1, 4] | ||||
|   }, | ||||
|   "globals" : { | ||||
|     "__DEV__"        : false, | ||||
|     "__filename"     : false, | ||||
|     "__dirname"      : false | ||||
|   } | ||||
| } | ||||
							
								
								
									
										4
									
								
								samples/react-express-mysql/frontend/.gitignore
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										4
									
								
								samples/react-express-mysql/frontend/.gitignore
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| node_modules | ||||
| .happypack | ||||
| build/* | ||||
| dist/* | ||||
							
								
								
									
										9
									
								
								samples/react-express-mysql/frontend/Dockerfile
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										9
									
								
								samples/react-express-mysql/frontend/Dockerfile
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| FROM node:10 | ||||
|  | ||||
| RUN mkdir /project | ||||
| WORKDIR /project | ||||
|  | ||||
| COPY . . | ||||
|  | ||||
| RUN yarn install | ||||
| CMD ["yarn", "run", "start"] | ||||
							
								
								
									
										12
									
								
								samples/react-express-mysql/frontend/Dockerfile.production
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										12
									
								
								samples/react-express-mysql/frontend/Dockerfile.production
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,12 @@ | ||||
| FROM node:10 as build | ||||
|  | ||||
| RUN mkdir /project | ||||
| WORKDIR /project | ||||
| COPY . . | ||||
| RUN yarn install | ||||
| RUN yarn run package | ||||
|  | ||||
| FROM nginx:1.13-alpine | ||||
|  | ||||
| COPY config/nginx.conf /etc/nginx/conf.d/default.conf | ||||
| COPY --from=build /project/dist /usr/share/nginx/html | ||||
							
								
								
									
										1
									
								
								samples/react-express-mysql/frontend/README.md
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										1
									
								
								samples/react-express-mysql/frontend/README.md
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1 @@ | ||||
| # Sample App | ||||
							
								
								
									
										9
									
								
								samples/react-express-mysql/frontend/config/nginx.conf
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										9
									
								
								samples/react-express-mysql/frontend/config/nginx.conf
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| server { | ||||
|     listen       9000; | ||||
|     server_name  localhost; | ||||
|  | ||||
|     location / { | ||||
|         root   /usr/share/nginx/html; | ||||
|         index  index.html index.htm; | ||||
|     } | ||||
| } | ||||
							
								
								
									
										15
									
								
								samples/react-express-mysql/frontend/jest.config.js
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										15
									
								
								samples/react-express-mysql/frontend/jest.config.js
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,15 @@ | ||||
| module.exports = { | ||||
|     "moduleFileExtensions": [ | ||||
|         "js", | ||||
|         "jsx", | ||||
|         "json" | ||||
|     ], | ||||
|     "moduleDirectories": [ | ||||
|         "node_modules", | ||||
|         "src" | ||||
|     ], | ||||
|     "moduleNameMapper": { | ||||
|         "^.+\\.(css|scss)$": "<rootDir>/test/mocks/styleMock.js", | ||||
|         "^.+\\.(jpg|jpeg|gif|png|svg|eot|ttf|woff|woff2|)$": "<rootDir>/test/mocks/imageMock.js" | ||||
|     } | ||||
| }; | ||||
							
								
								
									
										72
									
								
								samples/react-express-mysql/frontend/package.json
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										72
									
								
								samples/react-express-mysql/frontend/package.json
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,72 @@ | ||||
| { | ||||
|   "name": "react-app", | ||||
|   "version": "0.1.0", | ||||
|   "private": true, | ||||
|   "scripts": { | ||||
|     "clean": "rimraf ./dist/* && rimraf ./build/*", | ||||
|     "start": "cross-env NODE_ENV=development node webpack/dev-server.js", | ||||
|     "build": "cross-env NODE_ENV=development webpack --config webpack.config.js", | ||||
|     "package": "cross-env NODE_ENV=production webpack --config webpack.config.js", | ||||
|     "test": "cross-env NODE_ENV=test jest", | ||||
|     "lint:js": "eslint ./src" | ||||
|   }, | ||||
|   "dependencies": { | ||||
|     "express": "4.16.3", | ||||
|     "axios": "0.18.0", | ||||
|     "classnames": "2.2.5", | ||||
|     "lodash": "4.17.5", | ||||
|     "moment": "2.20.0", | ||||
|     "history": "4.7.2", | ||||
|     "react": "^16.8.6", | ||||
|     "react-dom": "^16.8.6", | ||||
|     "react-redux": "^5.1.1", | ||||
|     "react-router-dom": "^4.3.1", | ||||
|     "react-router-redux": "5.0.0-alpha.8", | ||||
|     "redux": "^3.7.2", | ||||
|     "redux-actions": "^2.6.5", | ||||
|     "redux-saga": "0.16.0", | ||||
|     "reselect": "3.0.1", | ||||
|     "query-string": "6.0.0" | ||||
|   }, | ||||
|   "devDependencies": { | ||||
|     "rimraf": "2.6.1", | ||||
|     "cross-env": "5.1.4", | ||||
|     "webpack": "4.5.0", | ||||
|     "webpack-cli": "3.3.1", | ||||
|     "webpack-dev-server": "3.1.3", | ||||
|     "html-webpack-plugin": "3.2.0", | ||||
|     "mini-css-extract-plugin": "0.4.0", | ||||
|     "react-hot-loader": "3.1.3", | ||||
|     "node-sass": "^4.11.0", | ||||
|     "babel-core": "6.26.0", | ||||
|     "babel-runtime": "6.26.0", | ||||
|     "babel-loader": "7.1.4", | ||||
|     "babel-preset-env": "^1.7.0", | ||||
|     "babel-eslint": "8.2.2", | ||||
|     "babel-preset-react": "6.24.1", | ||||
|     "babel-plugin-transform-runtime": "6.23.0", | ||||
|     "babel-plugin-transform-object-rest-spread": "6.26.0", | ||||
|     "babel-plugin-lodash": "3.3.2", | ||||
|     "css-loader": "^2.1.1", | ||||
|     "sass-loader": "6.0.7", | ||||
|     "style-loader": "0.20.3", | ||||
|     "file-loader": "1.1.11", | ||||
|     "postcss-loader": "2.1.3", | ||||
|     "autoprefixer": "8.2.0", | ||||
|     "cssnano": "4.1.10", | ||||
|     "identity-obj-proxy": "3.0.0", | ||||
|     "jest": "^20.0.4", | ||||
|     "jest-cli": "^20.0.4", | ||||
|     "babel-jest": "20.0.3", | ||||
|     "eslint": "4.19.1", | ||||
|     "eslint-config-standard": "^10.2.1", | ||||
|     "eslint-config-standard-react": "^5.0.0", | ||||
|     "eslint-loader": "^1.9.0", | ||||
|     "eslint-plugin-import": "^2.7.0", | ||||
|     "eslint-plugin-node": "^5.1.1", | ||||
|     "eslint-plugin-promise": "^3.3.0", | ||||
|     "eslint-plugin-react": "7.1.0", | ||||
|     "eslint-plugin-jsx-a11y": "6.0.2", | ||||
|     "eslint-plugin-standard": "3.0.1" | ||||
|   } | ||||
| } | ||||
							
								
								
									
										22
									
								
								samples/react-express-mysql/frontend/src/app/app.jsx
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										22
									
								
								samples/react-express-mysql/frontend/src/app/app.jsx
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| import * as React from "react" | ||||
| import { Switch } from "react-router-dom" | ||||
| import { renderRoutes } from "./routes" | ||||
|  | ||||
| import { ApplicationContainer } from "app/components/layout" | ||||
|  | ||||
| require("./core/styles/reset.css"); | ||||
| require("./core/styles/normalize.scss"); | ||||
| //require("./core/styles/main.scss"); | ||||
|  | ||||
| export class App extends React.Component { | ||||
|     render() { | ||||
|         return ( | ||||
|             <ApplicationContainer> | ||||
|                 <Switch> | ||||
|                     {renderRoutes()} | ||||
|                 </Switch> | ||||
|             </ApplicationContainer> | ||||
|         ) | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -0,0 +1,15 @@ | ||||
| import * as React from "react"; | ||||
|  | ||||
| export default class ApplicationContainer extends React.Component { | ||||
|  | ||||
|     render() { | ||||
|         return ( | ||||
|             <div className="main-container"> | ||||
|                 <div className="main-content"> | ||||
|                     {this.props.children} | ||||
|                 </div> | ||||
|             </div> | ||||
|         ); | ||||
|     } | ||||
|  | ||||
| } | ||||
							
								
								
									
										5
									
								
								samples/react-express-mysql/frontend/src/app/components/layout/index.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										5
									
								
								samples/react-express-mysql/frontend/src/app/components/layout/index.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,5 @@ | ||||
| import ApplicationContainer from "./ApplicationContainer"; | ||||
|  | ||||
| export { | ||||
|     ApplicationContainer, | ||||
| } | ||||
							
								
								
									
										396
									
								
								samples/react-express-mysql/frontend/src/app/core/styles/normalize.scss
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										396
									
								
								samples/react-express-mysql/frontend/src/app/core/styles/normalize.scss
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,396 @@ | ||||
| /*! normalize.css v2.1.0 | MIT License | git.io/normalize */ | ||||
|  | ||||
| // ========================================================================== | ||||
| // HTML5 display definitions | ||||
| // ========================================================================== | ||||
|  | ||||
| // | ||||
| // Correct `block` display not defined in IE 8/9. | ||||
| // | ||||
|  | ||||
| article, | ||||
| aside, | ||||
| details, | ||||
| figcaption, | ||||
| figure, | ||||
| footer, | ||||
| header, | ||||
| hgroup, | ||||
| main, | ||||
| nav, | ||||
| section, | ||||
| summary { | ||||
|   display: block; | ||||
| } | ||||
|  | ||||
| // | ||||
| // Correct `inline-block` display not defined in IE 8/9. | ||||
| // | ||||
|  | ||||
| audio, | ||||
| canvas, | ||||
| video { | ||||
|   display: inline-block; | ||||
| } | ||||
|  | ||||
| // | ||||
| // Prevent modern browsers from displaying `audio` without controls. | ||||
| // Remove excess height in iOS 5 devices. | ||||
| // | ||||
|  | ||||
| audio:not([controls]) { | ||||
|   display: none; | ||||
|   height: 0; | ||||
| } | ||||
|  | ||||
| // | ||||
| // Address styling not present in IE 8/9. | ||||
| // | ||||
|  | ||||
| [hidden] { | ||||
|   display: none; | ||||
| } | ||||
|  | ||||
| // ========================================================================== | ||||
| // Base | ||||
| // ========================================================================== | ||||
|  | ||||
| // | ||||
| // 1. Set default font family to sans-serif. | ||||
| // 2. Prevent iOS text size adjust after orientation change, without disabling | ||||
| //    user zoom. | ||||
| // | ||||
|  | ||||
| html { | ||||
|   font-family: sans-serif; // 1 | ||||
|   -webkit-text-size-adjust: 100%; // 2 | ||||
|   -ms-text-size-adjust: 100%; // 2 | ||||
| } | ||||
|  | ||||
| // | ||||
| // Remove default margin. | ||||
| // | ||||
|  | ||||
| body { | ||||
|   margin: 0; | ||||
| } | ||||
|  | ||||
| // ========================================================================== | ||||
| // Links | ||||
| // ========================================================================== | ||||
|  | ||||
| // | ||||
| // Address `outline` inconsistency between Chrome and other browsers. | ||||
| // | ||||
|  | ||||
| a:focus { | ||||
|   outline: thin dotted; | ||||
| } | ||||
|  | ||||
| // | ||||
| // Improve readability when focused and also mouse hovered in all browsers. | ||||
| // | ||||
|  | ||||
| a:active, | ||||
| a:hover { | ||||
|   outline: 0; | ||||
| } | ||||
|  | ||||
| // ========================================================================== | ||||
| // Typography | ||||
| // ========================================================================== | ||||
|  | ||||
| // | ||||
| // Address variable `h1` font-size and margin within `section` and `article` | ||||
| // contexts in Firefox 4+, Safari 5, and Chrome. | ||||
| // | ||||
|  | ||||
| h1 { | ||||
|   font-size: 2em; | ||||
|   margin: 0.67em 0; | ||||
| } | ||||
|  | ||||
| // | ||||
| // Address styling not present in IE 8/9, Safari 5, and Chrome. | ||||
| // | ||||
|  | ||||
| abbr[title] { | ||||
|   border-bottom: 1px dotted; | ||||
| } | ||||
|  | ||||
| // | ||||
| // Address style set to `bolder` in Firefox 4+, Safari 5, and Chrome. | ||||
| // | ||||
|  | ||||
| b, | ||||
| strong { | ||||
|   font-weight: bold; | ||||
| } | ||||
|  | ||||
| // | ||||
| // Address styling not present in Safari 5 and Chrome. | ||||
| // | ||||
|  | ||||
| dfn { | ||||
|   font-style: italic; | ||||
| } | ||||
|  | ||||
| // | ||||
| // Address differences between Firefox and other browsers. | ||||
| // | ||||
|  | ||||
| hr { | ||||
|   -moz-box-sizing: content-box; | ||||
|   box-sizing: content-box; | ||||
|   height: 0; | ||||
| } | ||||
|  | ||||
| // | ||||
| // Address styling not present in IE 8/9. | ||||
| // | ||||
|  | ||||
| mark { | ||||
|   background: #ff0; | ||||
|   color: #000; | ||||
| } | ||||
|  | ||||
| // | ||||
| // Correct font family set oddly in Safari 5 and Chrome. | ||||
| // | ||||
|  | ||||
| code, | ||||
| kbd, | ||||
| pre, | ||||
| samp { | ||||
|   font-family: monospace, serif; | ||||
|   font-size: 1em; | ||||
| } | ||||
|  | ||||
| // | ||||
| // Improve readability of pre-formatted text in all browsers. | ||||
| // | ||||
|  | ||||
| pre { | ||||
|   white-space: pre-wrap; | ||||
| } | ||||
|  | ||||
| // | ||||
| // Set consistent quote types. | ||||
| // | ||||
|  | ||||
| q { | ||||
|   quotes: "\201C" "\201D" "\2018" "\2019"; | ||||
| } | ||||
|  | ||||
| // | ||||
| // Address inconsistent and variable font size in all browsers. | ||||
| // | ||||
|  | ||||
| small { | ||||
|   font-size: 80%; | ||||
| } | ||||
|  | ||||
| // | ||||
| // Prevent `sub` and `sup` affecting `line-height` in all browsers. | ||||
| // | ||||
|  | ||||
| sub, | ||||
| sup { | ||||
|   font-size: 75%; | ||||
|   line-height: 0; | ||||
|   position: relative; | ||||
|   vertical-align: baseline; | ||||
| } | ||||
|  | ||||
| sup { | ||||
|   top: -0.5em; | ||||
| } | ||||
|  | ||||
| sub { | ||||
|   bottom: -0.25em; | ||||
| } | ||||
|  | ||||
| // ========================================================================== | ||||
| // Embedded content | ||||
| // ========================================================================== | ||||
|  | ||||
| // | ||||
| // Remove border when inside `a` element in IE 8/9. | ||||
| // | ||||
|  | ||||
| img { | ||||
|   border: 0; | ||||
| } | ||||
|  | ||||
| // | ||||
| // Correct overflow displayed oddly in IE 9. | ||||
| // | ||||
|  | ||||
| svg:not(:root) { | ||||
|   overflow: hidden; | ||||
| } | ||||
|  | ||||
| // ========================================================================== | ||||
| // Figures | ||||
| // ========================================================================== | ||||
|  | ||||
| // | ||||
| // Address margin not present in IE 8/9 and Safari 5. | ||||
| // | ||||
|  | ||||
| figure { | ||||
|   margin: 0; | ||||
| } | ||||
|  | ||||
| // ========================================================================== | ||||
| // Forms | ||||
| // ========================================================================== | ||||
|  | ||||
| // | ||||
| // Define consistent border, margin, and padding. | ||||
| // | ||||
|  | ||||
| fieldset { | ||||
|   border: 1px solid #c0c0c0; | ||||
|   margin: 0 2px; | ||||
|   padding: 0.35em 0.625em 0.75em; | ||||
| } | ||||
|  | ||||
| // | ||||
| // 1. Correct `color` not being inherited in IE 8/9. | ||||
| // 2. Remove padding so people aren't caught out if they zero out fieldsets. | ||||
| // | ||||
|  | ||||
| legend { | ||||
|   border: 0; // 1 | ||||
|   padding: 0; // 2 | ||||
| } | ||||
|  | ||||
| // | ||||
| // 1. Correct font family not being inherited in all browsers. | ||||
| // 2. Correct font size not being inherited in all browsers. | ||||
| // 3. Address margins set differently in Firefox 4+, Safari 5, and Chrome. | ||||
| // | ||||
|  | ||||
| button, | ||||
| input, | ||||
| select, | ||||
| textarea { | ||||
|   font-family: inherit; // 1 | ||||
|   font-size: 100%; // 2 | ||||
|   margin: 0; // 3 | ||||
| } | ||||
|  | ||||
| // | ||||
| // Address Firefox 4+ setting `line-height` on `input` using `!important` in | ||||
| // the UA stylesheet. | ||||
| // | ||||
|  | ||||
| button, | ||||
| input { | ||||
|   line-height: normal; | ||||
| } | ||||
|  | ||||
| // | ||||
| // Address inconsistent `text-transform` inheritance for `button` and `select`. | ||||
| // All other form control elements do not inherit `text-transform` values. | ||||
| // Correct `button` style inheritance in Chrome, Safari 5+, and IE 8+. | ||||
| // Correct `select` style inheritance in Firefox 4+ and Opera. | ||||
| // | ||||
|  | ||||
| button, | ||||
| select { | ||||
|   text-transform: none; | ||||
| } | ||||
|  | ||||
| // | ||||
| // 1. Avoid the WebKit bug in Android 4.0.* where (2) destroys native `audio` | ||||
| //    and `video` controls. | ||||
| // 2. Correct inability to style clickable `input` types in iOS. | ||||
| // 3. Improve usability and consistency of cursor style between image-type | ||||
| //    `input` and others. | ||||
| // | ||||
|  | ||||
| button, | ||||
| html input[type="button"], // 1 | ||||
| input[type="reset"], | ||||
| input[type="submit"] { | ||||
|   -webkit-appearance: button; // 2 | ||||
|   cursor: pointer; // 3 | ||||
| } | ||||
|  | ||||
| // | ||||
| // Re-set default cursor for disabled elements. | ||||
| // | ||||
|  | ||||
| button[disabled], | ||||
| html input[disabled] { | ||||
|   cursor: default; | ||||
| } | ||||
|  | ||||
| // | ||||
| // 1. Address box sizing set to `content-box` in IE 8/9. | ||||
| // 2. Remove excess padding in IE 8/9. | ||||
| // | ||||
|  | ||||
| input[type="checkbox"], | ||||
| input[type="radio"] { | ||||
|   box-sizing: border-box; // 1 | ||||
|   padding: 0; // 2 | ||||
| } | ||||
|  | ||||
| // | ||||
| // 1. Address `appearance` set to `searchfield` in Safari 5 and Chrome. | ||||
| // 2. Address `box-sizing` set to `border-box` in Safari 5 and Chrome | ||||
| //    (include `-moz` to future-proof). | ||||
| // | ||||
|  | ||||
| input[type="search"] { | ||||
|   -webkit-appearance: textfield; // 1 | ||||
|   -moz-box-sizing: content-box; | ||||
|   -webkit-box-sizing: content-box; // 2 | ||||
|   box-sizing: content-box; | ||||
| } | ||||
|  | ||||
| // | ||||
| // Remove inner padding and search cancel button in Safari 5 and Chrome | ||||
| // on OS X. | ||||
| // | ||||
|  | ||||
| input[type="search"]::-webkit-search-cancel-button, | ||||
| input[type="search"]::-webkit-search-decoration { | ||||
|   -webkit-appearance: none; | ||||
| } | ||||
|  | ||||
| // | ||||
| // Remove inner padding and border in Firefox 4+. | ||||
| // | ||||
|  | ||||
| button::-moz-focus-inner, | ||||
| input::-moz-focus-inner { | ||||
|   border: 0; | ||||
|   padding: 0; | ||||
| } | ||||
|  | ||||
| // | ||||
| // 1. Remove default vertical scrollbar in IE 8/9. | ||||
| // 2. Improve readability and alignment in all browsers. | ||||
| // | ||||
|  | ||||
| textarea { | ||||
|   overflow: auto; // 1 | ||||
|   vertical-align: top; // 2 | ||||
| } | ||||
|  | ||||
| // ========================================================================== | ||||
| // Tables | ||||
| // ========================================================================== | ||||
|  | ||||
| // | ||||
| // Remove most spacing between table cells. | ||||
| // | ||||
|  | ||||
| table { | ||||
|   border-collapse: collapse; | ||||
|   border-spacing: 0; | ||||
| } | ||||
							
								
								
									
										48
									
								
								samples/react-express-mysql/frontend/src/app/core/styles/reset.css
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										48
									
								
								samples/react-express-mysql/frontend/src/app/core/styles/reset.css
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,48 @@ | ||||
| /* http://meyerweb.com/eric/tools/css/reset/ | ||||
|    v2.0 | 20110126 | ||||
|    License: none (public domain) | ||||
| */ | ||||
|  | ||||
| html, body, div, span, applet, object, iframe, | ||||
| h1, h2, h3, h4, h5, h6, p, blockquote, pre, | ||||
| a, abbr, acronym, address, big, cite, code, | ||||
| del, dfn, em, img, ins, kbd, q, s, samp, | ||||
| small, strike, strong, sub, sup, tt, var, | ||||
| b, u, i, center, | ||||
| dl, dt, dd, ol, ul, li, | ||||
| fieldset, form, label, legend, | ||||
| table, caption, tbody, tfoot, thead, tr, th, td, | ||||
| article, aside, canvas, details, embed, | ||||
| figure, figcaption, footer, header, hgroup, | ||||
| menu, nav, output, ruby, section, summary, | ||||
| time, mark, audio, video { | ||||
|   margin: 0; | ||||
|   padding: 0; | ||||
|   border: 0; | ||||
|   font-size: 100%; | ||||
|   font: inherit; | ||||
|   vertical-align: baseline; | ||||
| } | ||||
| /* HTML5 display-role reset for older browsers */ | ||||
| article, aside, details, figcaption, figure, | ||||
| footer, header, hgroup, menu, nav, section { | ||||
|   display: block; | ||||
| } | ||||
| body { | ||||
|   line-height: 1; | ||||
| } | ||||
| ol, ul { | ||||
|   list-style: none; | ||||
| } | ||||
| blockquote, q { | ||||
|   quotes: none; | ||||
| } | ||||
| blockquote:before, blockquote:after, | ||||
| q:before, q:after { | ||||
|   content: ''; | ||||
|   content: none; | ||||
| } | ||||
| table { | ||||
|   border-collapse: collapse; | ||||
|   border-spacing: 0; | ||||
| } | ||||
							
								
								
									
										39
									
								
								samples/react-express-mysql/frontend/src/app/entry.jsx
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										39
									
								
								samples/react-express-mysql/frontend/src/app/entry.jsx
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| import * as React from "react"; | ||||
| import { render, unmountComponentAtNode } from "react-dom" | ||||
| import { AppContainer } from "react-hot-loader" | ||||
| import { Provider } from 'react-redux'; | ||||
| import { ConnectedRouter } from "react-router-redux" | ||||
| import { createBrowserHistory } from "history" | ||||
|  | ||||
| import { configureStore, sagaMiddleware } from "./store" | ||||
| import { runApplicationSagas } from "./sagas" | ||||
|  | ||||
| const history = createBrowserHistory(); | ||||
| const store = configureStore(history); | ||||
|  | ||||
| const getAppContainer = () => document.getElementById('app-container'); | ||||
|  | ||||
| const renderApp = () => { | ||||
|     const App = require('./app').App; | ||||
|     render( | ||||
|         <AppContainer> | ||||
|             <Provider store={store}> | ||||
|                 <ConnectedRouter history={history}> | ||||
|                     <App/> | ||||
|                 </ConnectedRouter> | ||||
|             </Provider> | ||||
|         </AppContainer> | ||||
|         , getAppContainer()); | ||||
| }; | ||||
|  | ||||
| if (__DEV__ && module.hot) { | ||||
|     const hotReloadApp = () => renderApp(); | ||||
|     module.hot.accept('./app', () => { | ||||
|         // Preventing the hot reloading error from react-router | ||||
|         unmountComponentAtNode(getAppContainer()); | ||||
|         hotReloadApp(); | ||||
|     }) | ||||
| } | ||||
|  | ||||
| // runApplicationSagas(sagaMiddleware); | ||||
| renderApp(); | ||||
							
								
								
									
										26
									
								
								samples/react-express-mysql/frontend/src/app/pages/home/HomePage.jsx
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										26
									
								
								samples/react-express-mysql/frontend/src/app/pages/home/HomePage.jsx
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,26 @@ | ||||
| import * as React from "react"; | ||||
| import { connect } from "react-redux"; | ||||
|  | ||||
| require("./home.scss"); | ||||
|  | ||||
| const mapStateToProps = (state, props) => { | ||||
|     return {}; | ||||
| }; | ||||
|  | ||||
| const mapDispatchToProps = (dispatch) => { | ||||
|     return {}; | ||||
| }; | ||||
|  | ||||
| class HomePage extends React.Component { | ||||
|  | ||||
|     render() { | ||||
|         return ( | ||||
|             <div className="home-page page"> | ||||
|                 <h1>My New React App</h1> | ||||
|             </div> | ||||
|         ) | ||||
|     } | ||||
|  | ||||
| } | ||||
|  | ||||
| export default connect(mapStateToProps, mapDispatchToProps)(HomePage) | ||||
							
								
								
									
										6
									
								
								samples/react-express-mysql/frontend/src/app/pages/home/home.scss
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										6
									
								
								samples/react-express-mysql/frontend/src/app/pages/home/home.scss
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,6 @@ | ||||
|  | ||||
|  | ||||
| .home-page { | ||||
|   background-color: blue; | ||||
|   color: red; | ||||
| } | ||||
							
								
								
									
										7
									
								
								samples/react-express-mysql/frontend/src/app/pages/home/index.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										7
									
								
								samples/react-express-mysql/frontend/src/app/pages/home/index.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| import * as React from "react"; | ||||
| import { Route } from "react-router-dom"; | ||||
| import HomePage from './HomePage'; | ||||
|  | ||||
| const route = <Route path="/" exact key="home" component={HomePage}/>; | ||||
|  | ||||
| export default route; | ||||
							
								
								
									
										10
									
								
								samples/react-express-mysql/frontend/src/app/reducers.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										10
									
								
								samples/react-express-mysql/frontend/src/app/reducers.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| import { combineReducers } from 'redux'; | ||||
| import { routerReducer } from 'react-router-redux'; | ||||
|  | ||||
| import whalesReducer from 'app/redux/whales'; | ||||
|  | ||||
| export const rootReducer = combineReducers({ | ||||
|     router: routerReducer, | ||||
|  | ||||
|     whales: whalesReducer, | ||||
| }); | ||||
							
								
								
									
										4
									
								
								samples/react-express-mysql/frontend/src/app/redux/whales/action-creators.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										4
									
								
								samples/react-express-mysql/frontend/src/app/redux/whales/action-creators.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,4 @@ | ||||
| import { createAction } from 'redux-actions'; | ||||
| import * as ActionTypes from "./action-types"; | ||||
|  | ||||
| export const fetchWhales = createAction(ActionTypes.FETCH_WHALES); | ||||
							
								
								
									
										4
									
								
								samples/react-express-mysql/frontend/src/app/redux/whales/action-types.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										4
									
								
								samples/react-express-mysql/frontend/src/app/redux/whales/action-types.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,4 @@ | ||||
|  | ||||
| const prefix = 'WHALES'; | ||||
|  | ||||
| export const FETCH_WHALES = `${prefix}/FETCH`; | ||||
							
								
								
									
										3
									
								
								samples/react-express-mysql/frontend/src/app/redux/whales/index.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										3
									
								
								samples/react-express-mysql/frontend/src/app/redux/whales/index.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| import Reducer from './reducer'; | ||||
|  | ||||
| export default Reducer; | ||||
							
								
								
									
										16
									
								
								samples/react-express-mysql/frontend/src/app/redux/whales/reducer.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										16
									
								
								samples/react-express-mysql/frontend/src/app/redux/whales/reducer.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,16 @@ | ||||
| import * as ActionTypes from "./action-types"; | ||||
| import { handleActions } from "redux-actions"; | ||||
|  | ||||
| const defaultState = { | ||||
|     list: [], | ||||
| }; | ||||
|  | ||||
| const handleFetchWhales = (state, {payload}) => { | ||||
|     return state; | ||||
| }; | ||||
|  | ||||
| const reducer = handleActions({ | ||||
|     [ActionTypes.FETCH_WHALES] : handleFetchWhales | ||||
| }, defaultState); | ||||
|  | ||||
| export default reducer; | ||||
							
								
								
									
										0
									
								
								samples/react-express-mysql/frontend/src/app/redux/whales/selectors.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										0
									
								
								samples/react-express-mysql/frontend/src/app/redux/whales/selectors.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
								
								
									
										10
									
								
								samples/react-express-mysql/frontend/src/app/routes.jsx
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										10
									
								
								samples/react-express-mysql/frontend/src/app/routes.jsx
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| import * as React from "react"; | ||||
| import Home from "./pages/home" | ||||
|  | ||||
| const routes = [ | ||||
|     Home, | ||||
| ]; | ||||
|  | ||||
| export const renderRoutes = () => { | ||||
|     return routes; | ||||
| }; | ||||
							
								
								
									
										9
									
								
								samples/react-express-mysql/frontend/src/app/sagas.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										9
									
								
								samples/react-express-mysql/frontend/src/app/sagas.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| //import { templatesSaga } from "./data/templates/sagas"; | ||||
| //import { appWizardSaga } from "./data/app-wizard/sagas"; | ||||
|  | ||||
| const startupSagas = [ | ||||
| ]; | ||||
|  | ||||
| export const runApplicationSagas = (sagaMiddleware) => { | ||||
|     startupSagas.forEach(sagaMiddleware.run); | ||||
| }; | ||||
							
								
								
									
										37
									
								
								samples/react-express-mysql/frontend/src/app/store.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										37
									
								
								samples/react-express-mysql/frontend/src/app/store.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,37 @@ | ||||
| import { routerMiddleware } from 'react-router-redux'; | ||||
| import { createStore, applyMiddleware, compose } from 'redux'; | ||||
| import createSagaMiddleware from "redux-saga"; | ||||
| import { rootReducer } from "./reducers"; | ||||
|  | ||||
| export const sagaMiddleware = createSagaMiddleware(); | ||||
|  | ||||
| export const configureStore = (history, initialState = {}) => { | ||||
|  | ||||
|     const middlewares = [ | ||||
|         routerMiddleware(history), | ||||
|         sagaMiddleware | ||||
|     ]; | ||||
|  | ||||
|     const enhancers = [ | ||||
|         applyMiddleware(...middlewares), | ||||
|     ]; | ||||
|  | ||||
|     if(__DEV__) { | ||||
|         const devToolEnhancer = () => { | ||||
|             return typeof window === 'object' && typeof window.devToolsExtension !== 'undefined' | ||||
|                 ? window.devToolsExtension() : f => f; | ||||
|         }; | ||||
|         enhancers.push(devToolEnhancer()) | ||||
|     } | ||||
|  | ||||
|     const store = createStore(rootReducer, initialState, compose(...enhancers)); | ||||
|  | ||||
|     if(__DEV__ && module.hot) { | ||||
|         module.hot.accept('./reducers', () => { | ||||
|             const nextReducer = require('./reducers').default; | ||||
|             store.replaceReducer(nextReducer); | ||||
|         }) | ||||
|     } | ||||
|  | ||||
|     return store; | ||||
| }; | ||||
							
								
								
									
										10
									
								
								samples/react-express-mysql/frontend/src/index.ejs
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										10
									
								
								samples/react-express-mysql/frontend/src/index.ejs
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| <!DOCTYPE html> | ||||
| <html> | ||||
|   <head> | ||||
|     <meta charset="UTF-8"> | ||||
|     <title>Sample application</title> | ||||
|   </head> | ||||
|   <body> | ||||
|     <div id="app-container"></div> | ||||
|   </body> | ||||
| </html> | ||||
							
								
								
									
										3
									
								
								samples/react-express-mysql/frontend/src/test/mocks/imageMock.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										3
									
								
								samples/react-express-mysql/frontend/src/test/mocks/imageMock.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,3 @@ | ||||
| // Return an empty string or other mock path to emulate the url that | ||||
| // Webpack provides via the file-loader | ||||
| module.exports = 'mocked-image.jpg'; | ||||
							
								
								
									
										2
									
								
								samples/react-express-mysql/frontend/src/test/mocks/styleMock.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										2
									
								
								samples/react-express-mysql/frontend/src/test/mocks/styleMock.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,2 @@ | ||||
| // Return a Proxy to emulate css modules (if you are using them) | ||||
| module.exports = require('identity-obj-proxy'); | ||||
							
								
								
									
										1
									
								
								samples/react-express-mysql/frontend/webpack.config.js
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										1
									
								
								samples/react-express-mysql/frontend/webpack.config.js
									
									
									
									
									
										Executable file
									
								
							| @@ -0,0 +1 @@ | ||||
| module.exports = require("./webpack/config-builder")(process.env.NODE_ENV || 'production'); | ||||
							
								
								
									
										231
									
								
								samples/react-express-mysql/frontend/webpack/config-builder.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										231
									
								
								samples/react-express-mysql/frontend/webpack/config-builder.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,231 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const path = require('path'), | ||||
|     webpack = require('webpack'), | ||||
|     HtmlWebpackPlugin = require('html-webpack-plugin'), | ||||
|     MiniCssExtractPlugin = require("mini-css-extract-plugin"); | ||||
|  | ||||
| const PROJECT_ROOT = path.resolve(__dirname, ".."); | ||||
|  | ||||
| module.exports = (env) => { | ||||
|     const isDev = env === 'development'; | ||||
|     const isTest = env === 'test'; | ||||
|     const isProd = !isDev && !isTest; | ||||
|  | ||||
|     const getAppEntry = () => { | ||||
|         const appEntry = path.resolve(PROJECT_ROOT, "src/app/entry.jsx"); | ||||
|         if(isDev) { | ||||
|             return [ | ||||
|                 'react-hot-loader/patch', | ||||
|                 'webpack-dev-server/client?http://localhost:9000', | ||||
|                 'webpack/hot/only-dev-server', | ||||
|                 appEntry | ||||
|             ] | ||||
|         } else { | ||||
|             return [appEntry] | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     const getPlugins = () => { | ||||
|  | ||||
|         // common plugins | ||||
|         let plugins = [ | ||||
|             // Global variables | ||||
|             new webpack.DefinePlugin({ | ||||
|                 'process.env.NODE_ENV': JSON.stringify(env), | ||||
|                 '__DEV__': isDev, | ||||
|                 '__PROD__': isProd, | ||||
|                 '__TEST__': isTest, | ||||
|             }), | ||||
|             // ignore moment locale files | ||||
|             new webpack.IgnorePlugin(/^\.\/locale$/, /moment$/), | ||||
|             // extract styles to css file | ||||
|             new MiniCssExtractPlugin({ | ||||
|                 filename: "[name].[contenthash].css", | ||||
|                 chunkFilename: "[id].css", | ||||
|                 disable: isDev, | ||||
|             }), | ||||
|             // makes index.html | ||||
|             new HtmlWebpackPlugin({ | ||||
|                 template: path.resolve(PROJECT_ROOT, 'src/index.ejs'), | ||||
|             }) | ||||
|         ]; | ||||
|  | ||||
|         // development plugins | ||||
|         if(isDev) { | ||||
|             plugins.push( | ||||
|                 // Hot Reload (HMR) | ||||
|                 new webpack.HotModuleReplacementPlugin(), | ||||
|                 // Named Modules | ||||
|                 new webpack.NamedModulesPlugin() | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         // production plugins | ||||
|         if(isProd) { | ||||
|             plugins.push( | ||||
|                 new webpack.optimize.ModuleConcatenationPlugin() | ||||
|             ); | ||||
|         } | ||||
|  | ||||
|         return plugins; | ||||
|     }; | ||||
|  | ||||
|     return { | ||||
|         target: 'web', | ||||
|         mode: isProd ? "production" : "development", | ||||
|         context: PROJECT_ROOT, | ||||
|  | ||||
|         entry: { | ||||
|             app: getAppEntry() | ||||
|         }, | ||||
|  | ||||
|         output: { | ||||
|             path: path.resolve(PROJECT_ROOT, isProd ? 'dist' : 'build'), | ||||
|             filename: isProd ? '[name].[chunkhash:8].js' : '[name].js', | ||||
|             publicPath: '/', | ||||
|             sourceMapFilename: '[file].map', | ||||
|             chunkFilename: isProd ? '[name].[chunkhash:8].js' : '[name].js', | ||||
|             pathinfo: isDev | ||||
|  | ||||
|         }, | ||||
|  | ||||
|         devtool: isProd ? "hidden-sourcemap" : 'eval', | ||||
|  | ||||
|         resolve: { | ||||
|             extensions: ['.js', '.jsx', '.ts', '.tsx'], | ||||
|             modules: ["node_modules", "src"], | ||||
|             alias: {} | ||||
|         }, | ||||
|  | ||||
|         module: { | ||||
|             rules: [ | ||||
|                 // JS / JSX files | ||||
|                 { | ||||
|                     test: /\.(js|jsx)$/, | ||||
|                     exclude: /(node_modules)/, | ||||
|                     use: [ | ||||
|                         { | ||||
|                             loader: 'babel-loader', | ||||
|                             options: { | ||||
|                                 cacheDirectory: true | ||||
|                             } | ||||
|                         } | ||||
|                     ] | ||||
|                 }, | ||||
|                 // SASS files | ||||
|                 { | ||||
|                     test: /\.scss$/, | ||||
|                     exclude: /(node_modules|bower_components)/, | ||||
|                     use: [ | ||||
|                         isDev ? "style-loader" : MiniCssExtractPlugin.loader, | ||||
|                         { | ||||
|                             loader: "css-loader", | ||||
|                             options: { | ||||
|                                 importLoaders: 2, | ||||
|                                 url: true, | ||||
|                                 import: false, | ||||
|                                 sourceMap: isDev | ||||
|                             } | ||||
|                         }, | ||||
|                         { | ||||
|                             loader: "postcss-loader", | ||||
|                             options: { | ||||
|                                 sourceMap: isDev, | ||||
|                                 plugins: isDev ? [] : [ | ||||
|                                     require("autoprefixer"), | ||||
|                                     require("cssnano")({ | ||||
|                                         safe: true, | ||||
|                                         zindex: false, | ||||
|                                         discardComments: { | ||||
|                                             removeAll: true | ||||
|                                         } | ||||
|                                     }) | ||||
|                                 ] | ||||
|                             } | ||||
|                         }, | ||||
|                         { | ||||
|                             loader: "sass-loader", | ||||
|                             options: { | ||||
|                                 sourceMap: isDev, | ||||
|                                 includePaths: [".", path.join(process.cwd(), "src/app/core/styles")] | ||||
|                             } | ||||
|                         } | ||||
|                     ] | ||||
|                 }, | ||||
|                 // Plain CSS files | ||||
|                 { | ||||
|                     test: /\.css$/, | ||||
|                     use: [ | ||||
|                         isDev ? "style-loader" : MiniCssExtractPlugin.loader, | ||||
|                         { | ||||
|                             loader: "css-loader", | ||||
|                             options: { | ||||
|                                 importLoaders: 1, | ||||
|                                 url: true, | ||||
|                                 import: false, | ||||
|                                 sourceMap: isDev | ||||
|                             } | ||||
|                         }, | ||||
|                         { | ||||
|                             loader: "postcss-loader", | ||||
|                             options: { | ||||
|                                 sourceMap: isDev, | ||||
|                                 plugins: isDev ? [] : [ | ||||
|                                     require("autoprefixer"), | ||||
|                                     require("cssnano")({ | ||||
|                                         safe: true, | ||||
|                                         zindex: false, | ||||
|                                         discardComments: { | ||||
|                                             removeAll: true | ||||
|                                         } | ||||
|                                     }) | ||||
|                                 ] | ||||
|                             } | ||||
|                         } | ||||
|                     ] | ||||
|                 }, | ||||
|                 // images loader | ||||
|                 { | ||||
|                     test: /\.(png|jpe?g|gif|svg|ico)(\?.*)?$/, | ||||
|                     use: [ | ||||
|                         { | ||||
|                             loader: 'file-loader', | ||||
|                             options: { | ||||
|                                 name: "[name].[ext]", | ||||
|                                 outputPath: isProd ? "../images/" : "images/" | ||||
|                             } | ||||
|                         } | ||||
|                     ] | ||||
|                 }, | ||||
|                 // font loader | ||||
|                 { | ||||
|                     test: /\.(woff|woff2|ttf|eot)(\?.*)?$/, | ||||
|                     use: [ | ||||
|                         { | ||||
|                             loader: 'file-loader', | ||||
|                             options: { | ||||
|                                 name: "[name].[ext]", | ||||
|                                 publicPath: isProd ? "" : "/webpack/", | ||||
|                                 useRelativePath: isProd, | ||||
|                                 outputPath: isProd ? "../fonts/" : "fonts/" | ||||
|                             } | ||||
|                         } | ||||
|                     ] | ||||
|                 } | ||||
|             ] | ||||
|         }, | ||||
|  | ||||
|         plugins: getPlugins(), | ||||
|  | ||||
|         node: { | ||||
|             __filename: true, | ||||
|             __dirname: true, | ||||
|             fs: 'empty', | ||||
|             vm: 'empty', | ||||
|             net: 'empty', | ||||
|             tls: 'empty', | ||||
|         } | ||||
|  | ||||
|     }; | ||||
| }; | ||||
							
								
								
									
										38
									
								
								samples/react-express-mysql/frontend/webpack/dev-server.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							
							
						
						
									
										38
									
								
								samples/react-express-mysql/frontend/webpack/dev-server.js
									
									
									
									
										vendored
									
									
										Executable file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| 'use strict'; | ||||
|  | ||||
| const webpack = require('webpack'), | ||||
|       WebpackDevServer = require('webpack-dev-server'), | ||||
|       makeConfig = require("./config-builder"); | ||||
|  | ||||
| const startWebpackServer = () => { | ||||
|     const config = makeConfig('development'); | ||||
|  | ||||
|     const SERVER_PORT = 9000; | ||||
|  | ||||
|     new WebpackDevServer(webpack(config), { | ||||
|         publicPath          : config.output.publicPath, | ||||
|         hot                 : true, | ||||
|         historyApiFallback  : true, | ||||
|         contentBase         : "./build/", | ||||
|  | ||||
|         watchOptions: { // no file events on D4W | ||||
|             aggregateTimeout: 300, | ||||
|             poll: 1000 | ||||
|         }, | ||||
|  | ||||
|         proxy : { | ||||
|             "/api/*"       : "http://127.0.0.1:8080"  // proxy to backend | ||||
|         }, | ||||
|  | ||||
|         before : function(app) { | ||||
|             // manually configure app `app.use(...)` | ||||
|         } | ||||
|     }).listen(SERVER_PORT, '0.0.0.0', function (err, result) { | ||||
|         if (err) { | ||||
|             console.log(err); | ||||
|         } | ||||
|         console.log('Webpack dev server listening at localhost:' + SERVER_PORT); | ||||
|     }); | ||||
| }; | ||||
|  | ||||
| startWebpackServer(); | ||||
		Reference in New Issue
	
	Block a user