the webpack settings you should know when developing isomorphic app
# Isomorphic App 開發要注意的 Webpack 設定

## 前情提要
[鍵盤發電機](http://github.com/tpai/keyboard-generator)是當初與 [@steveice](http://github.com/steveice) 和 [@vansteki](http://github.com/vansteki) 參加[百度黑客松 2013](http://tpai.github.io/2013/07/29/baidu-hackathon-at-clbc/) 時的作品,後端技術有 Node.js & Express & Socket.io,前端技術則是 jQuery,現在要對這個專案進行重構。
## 前端後端設定大不同
一開始,我很天真的拿之前寫好的 Webpack 設定檔直接套到 Backend 上開發,想當然爾就炸裂了 XD
跟前端設定不一樣的地方:
* 不打包內建模組,如:`fs` 或 `path`。
* 不打包 `node_modules/` 下的模組。
* 須告知 Webpack 引入 node 變數,如:`__dirname` 或 `__filename`。
[webpack.config.server.js:13-19](https://github.com/tpai/keyboard-generator/blob/master/webpack.config.server.js#L13,L19)
```
var nodeModules = {};
fs.readdirSync('node_modules')
.filter(function(x) {
return ['.bin'].indexOf(x) === -1;
})
.forEach(function(mod) {
nodeModules[mod] = 'commonjs ' + mod;
});
module.exports = {
target: "node",
externals: nodeModules,
node: {
__dirname: true
},
entry: ["server"],
...
};
```
另外值得一提的是 Entry Point 為何使用 Array 引入,因為原本的寫法是:
```
entry: {
"server": "server"
// input: ./src/server.js
// output: ./server.js
},
resolve: {
root: [ path.resolve("./src") ],
extensions: ["", ".js"]
},
```
但是這樣會造成 `Error: a dependency to an entry point is not allowed` 的錯誤發生,而我到 Webpack Github Issue 也只找到 technical reasons 的回覆,建議用 Array 處理掉這樣。(文末參考連結有該 Issue 討論串連結)
## 開發與部署環境切換
前端需要注意的主要是 Socket Server URL 在 Development 和 Production 的環境下要切換,所以我用了 [DefinePlugin](https://webpack.github.io/docs/list-of-plugins.html#defineplugin) 去定義全域變數來藉此判別現在的環境去打包 Front-End Code。
[webpack.config.server.js:37](https://github.com/tpai/keyboard-generator/blob/master/webpack.config.client.js#L37)
```
plugins: [
new webpack.DefinePlugin({
__DEVELOPMENT__: JSON.stringify(JSON.parse(process.env.NODE_ENV === 'development'))
})
]
```
`NODE_ENV` 的設定部份推薦使用 [cross-env](https://www.npmjs.com/package/cross-env) 去實作。
[package.json:7-12](https://github.com/tpai/keyboard-generator/blob/master/package.json#L7,L12)
```
"scripts": {
"watch": "cross-env NODE_ENV=development npm run ...",
"build": "cross-env NODE_ENV=production npm run ..."
}
```
## 結論
比起之前一坨混在一起的 [Client](https://github.com/tpai/keyboard-generator/blob/5a313bc60e68e339ca133442fe0d9427f141fc20/www/js/socket.handler.js) 和 [Server](https://github.com/tpai/keyboard-generator/blob/5a313bc60e68e339ca133442fe0d9427f141fc20/app.js) 真的舒服太多了,這就是所謂重構的成就感吧 XD
雖然大多時間都在弄環境以及處理莫名噴出來的 Issue,其實架構 Webpack 並不難,難的是要得心應手地使用這把武器,如果對 Webpack 還不是很熟,可以參考 [Webpack - The Confusing Parts](https://medium.com/@rajaraodv/webpack-the-confusing-parts-58712f8fcad9#.tzqd6lo76) 這篇文章。
> Refs:f
>
> * [Backend Apps With Webpack](http://jlongster.com/Backend-Apps-with-Webpack--Part-I)
> * [The need for multiple output paths?](https://github.com/webpack/webpack/issues/1189#issuecomment-156576084)
> * [Error: a dependency to an entry point is not allowed](https://github.com/webpack/webpack/issues/300#issuecomment-45313650)
> * [__dirname returns '/' when js file is built with webpack](https://github.com/webpack/webpack/issues/1599#issuecomment-186841345)