SPA(單頁面富應用single page web application)在開發環境中依賴node和npm運行,項目在開發完畢后,需要進行配置生產環境進行打包,然后部署到服務器上方可發布。
1.分析webpack打包后的產物
SPA項目中,只有一個.html文件,其余都是靜態資源
。實際部署到生產環境時,一般會將html掛在后端程序下,由后端路由渲染這個頁面,將所有的靜態資源(css、js、image、iconfont等)單獨由部署到CDN,當然也可以也可以和后端程序放在一起,以實現前后端分離。
在webpack.config.js中,我們指定了output選項的配置:
output: {
path: path.join(__dirname, './dist'),
publicPath: '/dist/',
filename: 'index.js'
}
那么,在生產環境打包完成后,所有的資源都會放在zhihu-daily/dist這個文件夾下。
2.安裝使用到的依賴
打包會用到webpack-merge:主要用于文件合并
、html-webpack-plugin:通過模板渲染html文件
這兩個依賴,通過npm安裝:
npm install --save-dev webpack-merge html-webpack-plugin
3.新建生產環境配置文件
為了方便開發環境和生產環境的切換,我們在根目錄下新建一個用于配置生產環境的配置文件webpack.prod.config.js,代碼如下:
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var ExtractTextPlugin = require('extract-text-webpack-plugin');
var merge = require('webpack-merge');
var webpackBaseConfig = require('./webpack.config.js');
// 清空配置文件的插件列表
webpackBaseConfig.plugins = [];
module.exports = merge(webpackBaseConfig, {
output: {
publicPath: '/dist/',
// 將入口文件重命名為帶有20位hash值的唯一文件
filename: '[name].[hash].js'
},
plugins: [
new ExtractTextPlugin({
// 提取css,將文件命名為帶有20位hash值的唯一文件
filename: '[name].[hash].css',
allChunks: true
}),
// 定義當前node環境為生產環境
new webpack.DefinePlugin({
'procee.env': {
NODE_ENV: '"production"'
}
}),
// 壓縮js
new webpack.optimize.UglifyJsPlugin({
compress: {
warnings: false
}
}),
// 提取模板并在根目錄下生成入口html文件(zhihu-daily/index_prod.html,zhihu-daily/dist/..)
new HtmlWebpackPlugin({
filename: '../index_prod.html',
template: './index.ejs',
inject: false
})
]
})
webpack.prod.config.js主要起到以下作用:
- 使用
webpack-merge
在webpack.config.js的基礎上擴展部分參數為生產環境,如:清空插件列表、輸出帶有20位hash值的css、js文件、定義當前環境、壓縮js等。 -
html-webpack-plugin
用來生產html文件,通過它的template選項指定模板為根目錄下的index.ejs
,然后輸出到filename指定的目錄,即zhihu-daily/index_prod.html。其中,模板index.ejs動態設置了靜態資源的路徑和文件名。
4.新建模板文件
在webpack.prod.config.js里,我們用到了:
new HtmlWebpackPlugin({
filename: '../index_prod.html',
template: './index.ejs',
inject: false
})
在根目錄下新建index.ejs,這個文件是用來作為模板,根據配置最終輸出index_prod.html
。代碼如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta http-equiv="X-UA-Compatible" content="ie=edge">
<title>Document</title>
<link rel="stylesheet" href="<%= htmlWebpackPlugin.files.css[0] %>">
</head>
<body>
<div id="app"></div>
<script src="<%= htmlWebpackPlugin.files.js[0] %>"></script>
</body>
</html>
為何要設置動態的路徑和文件名?
靜態資源在大部分場景下都有緩存(304),更新上線后都希望用戶能及時看到最新的內容,所以給打包后的css和js文件的名稱都加了20位的hash值,這樣打包后的文件名就是唯一的了,如:main.1cbc192f6ebd984a9dd0.css,只要不對html文件設置緩存,上線立即就可以加載到最新的靜態資源。
5.配置打包shell命令
完成3,4兩步后,我們需要配置一下shell命令以便webpack.prod.config.js生效,在package.json
中的scripts
屬性下加入build
屬性,以下代碼:
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"dev": "webpack-dev-server --open --host 0.0.0.0 --port 8888 --config webpack.config.js",
"build": "webpack --progress --hide-modules --config webpack.prod.config.js"
}
然后在終端內運行npm run build
,等待打包完成,會在根目錄下生成一個包含所有靜態資源的dist文件夾和入口文件index_prod.html。打包過程如下:
這就代表打包成功,根目錄下的index_prod.html和dist文件夾就是我們生產環境的打包文件。
6.直接在磁盤中訪問index_prod.html
在資源管理器中找到index_prod.html,在瀏覽器中打開,發現什么也沒有。打開控制臺報錯:
說明html文件沒有找到相應的靜態資源,原因是在index_prod.html中使用了
/dist/main.xxxx.css、/dist/main.xxxx.js
引永靜態資源,直接在磁盤中打開并不能找到這個路徑,把/dist
替換成dist
即可。效果如下:不過在大部分情況下,我們都是將打包后的文件部署到tomcat上,這個路徑根據實際需求進行修改即可。
至此,我們完成了一個簡單的生產環境打包示例。
完整代碼github地址:https://github.com/zhiyuanMain/zhihu-daily