Implementing a server side rendering app with React + Redux + Express + Webpack.
-
server is responsible for rendering initial html
-
serve js bundle as public, leave the rendering to frontend.
spins up both backend server and frontend server.
[x] setup webpack compilation environment.
-
babel-loader for es6.
-
es6 preset, transform ES6 script into browser compatible ES5 script.
-
babel stage-0, this link demonstrates what stage-0 serves.
[x] add koa router.
-
[koa-router](npm install koa-router) repo.
-
koa-cors repo.
[x] ORM package.
-
Compare Sequelize with Bookshelf.
-
will choose bookshelf over Sequelize. install it!
[x] add frontend script.
[x] add webpack-dev-server. deprecated by Dan Abramov
-
install webpack-dev-server.
-
configure webpack configuration.
-
[] add script
npm run start:devto start webpack-dev-server for front end.
[x] add react router.
[x] add redux.
-
install redux
-
install react-redux
-
install react-thunk
[x] add mocha test framework.
-
install mocha.
-
install chai.
-
install chai-immutable.
-
[] React testing framework jsdom link.
[x] change framework from KOA to express.
[x] split configuration depend on environment. use webpack merge.
[x] add hot module reload.
[x] add react hot loader for development environment.
[x] add react router.
[x] polyfill promises for webpack2.
[x] use ava for test framework.
[x] add eslint
[x] add asset-require-hook to load various image mimeTypes from server side.
[x] serve static assets.
[] add karma + enzyme for testing react components.
I read through surviveJS for extracting vendor.js. The article suggest to put all the frontend modules under dependencies such as react, redux, redux-saga...etc in package.json and bundles them up using commonChunksPlugin:
plugins: [
new commonChunksPlugin ({
name: vendor,
filename: vendor.js,
})
]
However, this reveals a problem that it does not extract out the common chunks among those frontend modules. Thus, they might use common chunks that don't get extract out. This results in bigger bundle size. To avoid this, we can use follow settings:
entry: [
join(__dirname, 'src', 'index.js')
]
...
plugins: [
new commonChunksPlugin ({
name: vendor,
filename: vendor.js,
minChunks: module => {
module.resource &&
module.resource.indexOf('node_modules') !== -1 &&
module.resource.indexOf('.css') === -1
}
})
]
the above config will load every modules that are actually being imported start from the index.js and generate a common module amongst them all.
ES6 generator pattern helps to control the flow of javascript async execution sequence. Please Consider the following code.
const testGen = function * () {
const obj = {value: 'from inside'}
const returned = yield obj
console.log('returned value', returned) // debugger 3
}
const a = testGen()
const aNext = a.next()
console.log(aNext.value) // debugger 1
console.log(aNext.done) // debugger 2
console.log(a.next('from outside'))
When testGen executes const returned = yield obj, it hands over the control outside of the function scope.
The value yield inside of testGen function will be passed on to aNext.value. Thus, debugger 1 will output {done: false, value: {value: 'from inside'}}. debugger 2 will output false
When execute the next a.next('from outside'), the execution flow will again be passed into testGen function. Thus, debugger 3 will output {value: 'from outside', done: true}
app.use(function * () {
console.log(this.request)
})
app.listen(8086)
spins KOA with babel-node.
Instead of using babel node on production(not suggested), we should prebuild production server script and host with node command.
npm run build
npm run server
Before spinning up webpack-dev-server please install by prompting:
npm install -g webpack webpack-dev-server
webpack-dev-server hosts frontend script in localhost:8080
when building server side code with koa implemented, it needs babel-polyfill to accommodate es6 promise / await async.
search the purpose of:
hot: true
historyApiFallback: true