Implementing a server side rendering app with React + Redux + Redux-saga + Express + Webpack.
-
server is responsible for rendering initial html.
-
serve js bundle as public, leave the rendering to frontend.
yarn install
npm run dev. request localhost:3005 in your browser.
npm run build:prod
npm run start:local. request localhost:3005 in your browser.
[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.
[] 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 redux-saga [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] use jest 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.
[x] upgrade to webpack 2 alone with webpack.config.js and all relative dependencies.
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
webpack-dev-middleware does not support hot reloading stateless function components. when your topmost component is written stateless function, for example:
// in routes.js
<Route path="/" component={App} >
<Route path="/home" component={Home} />
</Route>export default const Home = () => (...)The above component will not be hot reloaded by webpack-dev-middleware. to resolve this issue, we need to place the following snippet in the parent component.
// check if its HMR.
if (module.hot) {
// if it is, itself accept the update!
module.hot.accept()
}please refer to this.
Majority of the details for upgrading from v1 to v2 can be found here
This issue can be found here. The dependencies that are causing this warning are:
babel-loaderimage-webpack-loaderbabel-plugin-transform-runtimebabel-runtime
Config has changed slightly since webpack 1. We have to manually specify compression config for each image type, png, jpg / jpeg, svg... Here is the consent for the config.