前言
以前在用koa寫server的時候,釋出簡直是噩夢。需要將src裡面的全部檔案都覆蓋掉,config配置檔案也要覆蓋,稍有不慎就會線上報各種各樣的問題,然後就得回退,本地調好在釋出。偶然看見一篇文章講如何使用webpack打包koa app,驚為天人,原來webpack也能打包後臺。這在以前想都沒想過。
關鍵問題
一:所有node_modules裡的模組都不進行打包
webpack的核心功能是將引用的各個模組打到一個檔案裡,並會將各種規範的模組進行統一的模組化處理(webpack規範)。
然而node中包含大量的fs、path操作,這些fs和path操作在打包完成後將沒有操作物件,還會報出很多各樣的錯誤。
所以使用webpack打包的核心就是拒絕打包一切node_modules裡的模組,只是將相對路徑引用的檔案打包到一個檔案裡。恰巧我們發現webapck提供externals屬性來排除掉不需要打包的模組。
再深入點我們可以發現:像webpack、nodemon、babel-preset-env這樣的模組是app開發環境依賴的包,我們的程式里根本不會require這些模組。
綜上可以發現:我們只將所有require到的包排除掉就可以了,這個模組對應的也就是package.json裡dependencies下的模組。有關dependencies和devDependencies的區別要理解好。
因此我們可以使用externals-dependencies這個外掛配合externals屬性實現dependencies的排除工作。
程式碼:
const webpack = require('webpack');
const _externals = require('externals-dependencies')
module.exports = {
...
externals: _externals(),
...
}
複製程式碼
二:target指向node
官方文件:編譯為類 Node.js 環境可用(使用 Node.js require 載入 chunk)
程式碼:
target: 'node',
複製程式碼
三:增加node配置
官方文件:這些選項可以配置是否 polyfill 或 mock 某些 Node.js全域性變數和模組。這可以使最初為 Node.js 環境編寫的程式碼,在其他環境(如瀏覽器)中執行。
程式碼:
node: {
console: true,
global: true,
process: true,
Buffer: true,
__filename: true,
__dirname: true,
setImmediate: true,
path: true
},
複製程式碼
四:babel配置
為了相容低版本的node不原生支援async/await的問題。這裡babel我使用了babel-preset-env{"modules": false}的配置。此配置會將es6語法轉為es5語法,例如let、const轉為var。
同時將所有的async/await函式也轉成了polyfill裡定義的_asyncToGenerator函式。
function _asyncToGenerator(fn) { return function () { var gen = fn.apply(this, arguments); return new Promise(function (resolve, reject) { function step(key, arg) { try { var info = gen[key](arg); var value = info.value; } catch (error) { reject(error); return; } if (info.done) { resolve(value); } else { return Promise.resolve(value).then(function (value) { step("next", value); }, function (err) { step("throw", err); }); } } return step("next"); }); }; }
複製程式碼
其實是使用promise實現了async函式的功能。
當然這個函式在執行時還需要regeneratorRuntime函式。所以我在全域性引入了babel-polyfill來提供regeneratorRuntime函。
注:如果你的node版本很高且原生支援async/await,大可將babel-preset-env和babel-polyfill省略掉
程式碼:
const path = require('path');
const webpack = require('webpack');
const _externals = require('externals-dependencies')
module.exports = {
entry: {
app: [
// 如果polyfill放在這裡,打包的時候將不會被external,必須在js裡require才能有效external
// 'babel-polyfill',
'./src/index.js'
]
},
output: {
path: path.resolve(__dirname),
filename: '[name].js'
},
resolve: {
extensions: [".js"]
},
target: 'node',
externals: _externals(),
context: __dirname,
node: {
console: true,
global: true,
process: true,
Buffer: true,
__filename: true,
__dirname: true,
setImmediate: true,
path: true
},
module: {
rules: [
{
test: /\.js/,
use: ['babel-loader']
}
]
},
plugins: [
new webpack.DefinePlugin({
'process.env': {
NODE_ENV: '"development"'
}
}),
]
}
複製程式碼
部署
經過打包,部署的時候就方便多了,只需要將package.json、app.js、以及view裡的html部署上線就好了。然後在伺服器上執行
1. npm install
2. npm run for
複製程式碼
然後server就後臺執行了。如果需要更新發布,只需要本地重新npm run dev或npm run build打好包,拖到伺服器覆蓋app.js即可。