dvdzkwsk / react-redux-starter-kit

Get started with React, Redux, and React-Router.
MIT License
10.29k stars 2.2k forks source link

Better deployment description #730

Closed Marschelloss closed 8 years ago

Marschelloss commented 8 years ago

This Pack needs a better description how a production-ready server can get implented. The Pack itself is great and its fun to work with it. But people will stop using it, when they realise they cant deploy it easily to popular server-structures like heroku.

A Beginner will not notice, that after including devDepencies to Heroku and reading the linked issue #571 that he still doesnt have a running webserver and will get an empty page.

Sadly i also didnt get it running after that. I dont know what i have to do to get an simple production ready server or just "test-deploy" to heroku. Even after changing /server/main.js so i also uses the "not stable" sever in production: ... if (config.env === 'development' || config.env === 'production') { ... it doesnt work. Since it cant find the the duck-files:

/.../
 Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [175] ./src/containers/ActorList.js 2.78 kB {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [176] ./src/containers/ActorSearch.js 3.02 kB {1} [built] [1 error] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [177] ./src/containers/Root.js 2.51 kB {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [178] ./src/layouts/CoreLayout/CoreLayout.js 1.67 kB {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [179] ./src/main.js 2.03 kB {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [180] ./src/redux/configureStore.js 1.43 kB {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [181] ./src/redux/rootReducer.js 477 bytes {1} [built] [1 error] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [182] ./src/routes/index.js 798 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [183] ./src/views/HomeView/HomeView.js 1.99 kB {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [184] ./~/babel-runtime/core-js/object/create.js 94 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [185] ./~/babel-runtime/core-js/object/define-property.js 103 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [186] ./~/babel-runtime/core-js/object/set-prototype-of.js 104 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [187] ./~/babel-runtime/core-js/symbol.js 87 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [188] ./~/babel-runtime/core-js/symbol/iterator.js 96 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [189] ./~/babel-runtime/~/core-js/library/fn/object/create.js 170 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [190] ./~/babel-runtime/~/core-js/library/fn/object/define-property.js 213 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [191] ./~/babel-runtime/~/core-js/library/fn/object/get-prototype-of.js 124 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [192] ./~/babel-runtime/~/core-js/library/fn/object/set-prototype-of.js 124 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [193] ./~/babel-runtime/~/core-js/library/fn/symbol/index.js 139 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [194] ./~/babel-runtime/~/core-js/library/fn/symbol/iterator.js 148 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [195] ./~/babel-runtime/~/core-js/library/modules/_a-function.js 120 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [196] ./~/babel-runtime/~/core-js/library/modules/_add-to-unscopables.js 43 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [197] ./~/babel-runtime/~/core-js/library/modules/_array-includes.js 788 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [198] ./~/babel-runtime/~/core-js/library/modules/_enum-keys.js 472 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [199] ./~/babel-runtime/~/core-js/library/modules/_html.js 75 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [200] ./~/babel-runtime/~/core-js/library/modules/_iobject.js 236 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [201] ./~/babel-runtime/~/core-js/library/modules/_is-array.js 145 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [202] ./~/babel-runtime/~/core-js/library/modules/_iter-create.js 528 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [203] ./~/babel-runtime/~/core-js/library/modules/_iter-step.js 81 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [204] ./~/babel-runtime/~/core-js/library/modules/_keyof.js 307 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [205] ./~/babel-runtime/~/core-js/library/modules/_meta.js 1.55 kB {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [206] ./~/babel-runtime/~/core-js/library/modules/_object-dps.js 416 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [207] ./~/babel-runtime/~/core-js/library/modules/_object-gopn-ext.js 603 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [208] ./~/babel-runtime/~/core-js/library/modules/_object-sap.js 368 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [209] ./~/babel-runtime/~/core-js/library/modules/_set-proto.js 893 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [210] ./~/babel-runtime/~/core-js/library/modules/_string-at.js 611 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [211] ./~/babel-runtime/~/core-js/library/modules/_to-index.js 230 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [212] ./~/babel-runtime/~/core-js/library/modules/_to-length.js 217 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [213] ./~/babel-runtime/~/core-js/library/modules/es6.array.iterator.js 1.13 kB {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [214] ./~/babel-runtime/~/core-js/library/modules/es6.object.create.js 160 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [215] ./~/babel-runtime/~/core-js/library/modules/es6.object.define-property.js 216 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [216] ./~/babel-runtime/~/core-js/library/modules/es6.object.get-prototype-of.js 275 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [217] ./~/babel-runtime/~/core-js/library/modules/es6.object.set-prototype-of.js 157 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [218] ./~/babel-runtime/~/core-js/library/modules/es6.object.to-string.js 0 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [219] ./~/babel-runtime/~/core-js/library/modules/es6.string.iterator.js 523 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [220] ./~/babel-runtime/~/core-js/library/modules/es6.symbol.js 8.6 kB {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [221] ./~/babel-runtime/~/core-js/library/modules/web.dom.iterable.js 559 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [225] ./src/styles/core.scss 229 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [247] ./~/react-dom/index.js 63 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:   [329] ./~/redux-thunk/lib/index.js 370 bytes {1} [built] 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1: ERROR in ./src/redux/rootReducer.js 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1: Module not found: Error: Cannot resolve 'file' or 'directory' ./modules/actor.js in /app/src/redux 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:  @ ./src/redux/rootReducer.js 11:13-42 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1: ERROR in ./src/containers/ActorSearch.js 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1: Module not found: Error: Cannot resolve 'file' or 'directory' ../redux/modules/actor.js in /app/src/containers 
Apr 20 02:50:43 mysterious-sea-57590 app/web.1:  @ ./src/containers/ActorSearch.js 36:13-49 
/.../

And yes, i know that the Pack cant include a production-ready server. But maybe another branch?

Marschelloss commented 8 years ago

For everybody who is searching to demo deploy: Remove the dist folder from the .gitignore-file. Run npm start deploy to compile the app into dist. Now you can deploy the folder to git/heroku/whatever. Till now i wasnt able to fix my own error. I think it doesnt load some webpack middleware.

deep-c commented 8 years ago

I am in the same boat. Could someone explain to me why the server that is bundled isnt production ready and what would constitute a server that is. For example if I were building a docker container to serve this why shouldnt I use the provided server? Is it security, performance, flexibility, limited featureset which is the reason or...

dvdzkwsk commented 8 years ago

I think this is mostly a misunderstanding. Maybe there are fixes we have to make specifically for Heroku, but...

@deep-c the server is production ready, it just simply does not do anything besides serve up your ~/dist directory when in production. At that point, you're better of using a web server meant for that job (Nginx, Apache, et al.) rather than a node server. The deployment strategy should be exactly what @DonHansDampf mentions (though there are other ways of deploying the ~/dist folder), meaning that unless you're also using the Koa server for an API it's better to serve static files than run an additional node server.

Marschelloss commented 8 years ago

Thanks for the answer @davezuko. I have to say i like this package more and more. Its clean and simple. But the deployment was somehow a let down for a moment. I started again and looked into the code. Deploying to Heroku isnt that hard it seams at first. At all there are two solutions:

  1. Remove the ~/dist folder from the .gitignore file. Change the NODE_ENV for npm run start to 'production' in the package.json. First run npm run compile then push to heroku via git push heroku master. Simple as that.
  2. If you want to build the app on the heroku sever, change the npm run start command in the package.json to:
/.../
"start": {
  "command": "npm run clean && npm run compile && babel-node bin/server",
  "env": {
    "NODE_ENV": "production",
    "DEBUG": "app:*"
  }
},
/.../

Tell Heroku to also push the devDependencies to build the App on the server via heroku config:set NPM_CONFIG_PRODUCTION=false. Now push to Heroku via git push heroku master. Now it should build the app on every start and serve the dist folder. (can take some time on every restart).

Maybe we could add this somehow in a clean way to the Deploy Section and add also your description about the server?

dvdzkwsk commented 8 years ago

@DonHansDampf Those are all great suggestions. I will try to condense them down and add them to the README tonight/tomorrow. An additional solution could just be something like:

// npm run deploy:serve
"command": "npm run deploy && npm start",
"env": {
  "NODE_ENV": "production"
}
Marschelloss commented 8 years ago

@davezuko That's also a nice solution. The only problem is: Heroku always runs npm start to start an app. I looked into the heroku wiki but wasnt able to find a way to change the default command (propably via the package.json ?). But we could define a postinstall script. (Same as npm run deploy) Heroku will run this after npm install. This way npm run start could be clean as it is. And it would be more clear for new users what happens on the heroku server. (Push to Heroku, Install Modules, Run Postinstall Routine to build the files, run koa to serve the files.) This way the Heroku server will also respond faster since it doesnt build on every restart (for example after sleeping). But we would still have to change the heroku config to push devDependencies.

yannbertrand commented 8 years ago

Is it possible to deploy the app directly onto a gh-pages branch? I'm not sure why would a custom server be required since we only have static files (index.html, app.js, vendor.js, app.css, favicon.ico...).

This would be extremely convenient.

Marschelloss commented 8 years ago

Hey @YannBertrand ! No there is no need for a custom server if you just want to host the static files in the dist folder. You only need one if you use the koa server for other things besides hosting like serving a rest api. Deploying to gh-pages works like every other deploy to the gh-pages. Simply run npm run build and deploy the files inside the dist folder.

justingreenberg commented 8 years ago

this is really a "front-end" kit

heroku is a paas—the whole idea is to abstract production hardening and deployment... so, just because the included server runs on their platform does not make it "production ready"

as @davezuko suggested, you should use this kit to generate highly optimized, static distributables and then use a battle-tested, purpose-built server for assets.. run your api as a separate service. if you are managing your own ops/servers, i recommend openresty (nginx) or h2o (http2)... however i prefer the "serverless" approach using s3 behind a cloudfront distribution to serve statics with something like s3-plugin-webpack to automate deployments

dvdzkwsk commented 8 years ago

Closing in favor of a todo task in our chore to improve the readme: https://github.com/davezuko/react-redux-starter-kit/issues/765

egeozin commented 6 years ago

Hi @DonHansDampf !

I tried the second approach that you defined above for Heroku deployment:

`/.../
"start": {
  "command": "npm run clean && npm run compile && babel-node bin/server",
  "env": {
    "NODE_ENV": "production",
    "DEBUG": "app:*"
  }
},
/.../`

However I get babel-node: not found error in Heroku logs just after compiling in Heroku finishes. And I already installed the babel-cli packages.

Am I missing something?

Thanks in advance