之前用Vue2+webpack+express構(gòu)建單頁應(yīng)用,發(fā)現(xiàn)node端不能用es6的語法猾骡,為了前后端都用上es6的語法,node框架決定嘗試koa2
代碼地址:https://github.com/chenjiaj/Vue2-koa2-demo
一竹观、需要環(huán)境
node版本在7及以上
選擇新版本的環(huán)境是為了node端不用引入babel對(duì)es6做處理土辩,新的node版本對(duì)es6有良好的支持。
二摘符、創(chuàng)建基本項(xiàng)目
1.1 啟動(dòng)koa小項(xiàng)目demo
1.新建文件夾koa2+vue2-demo贤斜,然后進(jìn)入文件夾,打開cmd進(jìn)入文件夾內(nèi)的目錄或者webstorm的命令面板逛裤。
2.執(zhí)行npm init命令生成package.json文件,然后執(zhí)行npm install koa koa-onerror --save 下載koa和 koa-onerror
3.在項(xiàng)目根目錄下新建config文件夾,然后進(jìn)入文件夾新建config.js瘩绒,輸入以下內(nèi)容,配置端口號(hào)
module.exports = {
node: {
port: 3011
}
};
4.在項(xiàng)目根目錄新建app.js文件带族,然后輸入以下內(nèi)容锁荔,創(chuàng)建一個(gè)基本的項(xiàng)目
const Koa = require('koa');
const app = new Koa();
const Config = require('./config/config');
const onerror = require('koa-onerror');
//錯(cuò)誤信息處理
onerror(app);
//控制臺(tái)打印請(qǐng)求信息
app.use(async(ctx, next) => {
const start = Date.now();
await next();
const ms = Date.now() - start;
console.log(`${ctx.method} ${ctx.url} - ${ms}ms`);
});
app.listen(Config.node.port);
- 修改package.json,在script對(duì)象中添加 "start": "node ./app.js",如下圖所示
6.此時(shí)在命令面板中輸入npm start即可啟動(dòng)項(xiàng)目蝙砌,然后在瀏覽器中訪問 http://localhost:3011/阳堕,因?yàn)楝F(xiàn)在還沒有對(duì)請(qǐng)求做任何處理跋理,所以返回not found。
1.2 添加vue頁面恬总,實(shí)現(xiàn)hello world
1.在根目錄下新建src,然后在src下添加index.html文件,并且添加一個(gè)id為app的div前普,如下。同時(shí)在命令面板輸入 npm install vue --save
2.在src目錄下新建views文件夾(存放所有的.vue文件)壹堰,并在此文件夾下添加app.vue文件拭卿。在app.vue寫入一下代碼:
<template>
<div>hello world!</div>
</template>
3.在src下新建main.js作為vue的入口文件。在main.js中添加以下內(nèi)容:
import Vue from 'vue';
import App from './views/app.vue';
new Vue({
el: '#app',
render: h=> h(App)
});
現(xiàn)在目錄結(jié)構(gòu)如下:
一個(gè)hello world 的demo就寫好了贱纠,但是要在瀏覽器看到效果峻厚,還需要引入vue包,同時(shí)也需要添加webpack打包需要的文件與配置谆焊。將vue內(nèi)容打包引入index.html中惠桃,然后再將node接收到的頁面請(qǐng)求返回打包后的index.html頁面
1.3 添加webpack打包文件與配置
1.下載webpack打包需要的依賴包
npm install webpack webpack-merge koa-webpack extract-text-webpack-plugin html-webpack-plugin css-loader file-loader vue-template-compiler vue-loader vue-style-loader --save-dev
webpack :webpack打包需要引入的核心包
koa-webpack:封裝了webpack-dev-middleware和webpack-hot-middleware兩個(gè)插件
webpack-dev-middleware是需要webpack打包的項(xiàng)目,開發(fā)時(shí)使用的中間件懊渡,主要作用是不需要將打包生成的文件放在硬盤中刽射,而是放在內(nèi)存中,這樣可以提高開發(fā)效率剃执,而且配合webpack-hot-middleware中間件使用可以實(shí)現(xiàn)熱加載
extract-text-webpack-plugin:主要是為了抽離css樣式,防止將樣式打包在js中引起頁面樣式加載錯(cuò)亂的現(xiàn)象
html-webpack-plugin:是webpack的插件誓禁,這個(gè)插件用來簡化創(chuàng)建服務(wù)于 webpack bundle 的 HTML 文件,尤其是對(duì)于在文件名中包含了 hash 值肾档,而這個(gè)值在每次編譯的時(shí)候都發(fā)生變化的情況摹恰。你既可以讓這個(gè)插件來幫助你自動(dòng)生成 HTML 文件,也可以使用 lodash 模板加載生成的 bundles怒见,或者自己加載這些 bundles俗慈。
vue-loader:是webpack的loader,能夠?qū)?vue文件轉(zhuǎn)換成js文件
vue-html-loader、vue-template-compiler遣耍、css-loader闺阱、vue-style-loader:這三個(gè)都是webpack的loader,都是將.vue文件轉(zhuǎn)換成js文件的依賴
2.下載babel需要的依賴包
npm install babel-core babel-loader babel-plugin-transform-runtime babel-polyfill babel-preset-es2015 babel-preset-stage-0 babel-runtime --save-dev
以babel-開頭:都是用于兼容es6寫法,將es6的代碼轉(zhuǎn)換成es5的代碼
babel-core舵变、babel-loader:babel配合webpack工具使用必須要引入的
babel-plugin-transform-runtime酣溃、babel-runtime:解決重復(fù)出現(xiàn)在一些模塊里,導(dǎo)致編譯后的代碼體積變大的問題纪隙。
babel-preset-es2015:將 ES2015 編譯成 ES5
babel-preset-stage-2:除了覆蓋stage-3的所有功能,不是對(duì)ES6功能的增加赊豌,而是為了增強(qiáng)代碼的可讀性和可修改性而提出的參考:http://babeljs.io/docs/setup/#installation
3.在根目錄下添加.babelrc文件,添加以下配置:
{
"presets": ["es2015","stage-0"],
"plugins": ["transform-runtime"],
"comments": false
}
4.在根目錄下新建build文件夾绵咱,然后添加webpack.base.conf.js碘饼、webpack.dev.conf.js、webpack.prod.conf.js
webpack.base.conf.js:開發(fā)和生成環(huán)境相同配置寫字這個(gè)里邊
webpack.dev.conf.js:針對(duì)開發(fā)時(shí)配置的文件
webpack.prod.conf.js:針對(duì)生產(chǎn)環(huán)境(正式上線)配置的文件
5.在webpack.base.conf.js中添加以下配置
/* 引入操作路徑模塊和webpack */
const path = require('path');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin');
const ExtractTextPlugin = require('extract-text-webpack-plugin');
module.exports = {
/* 輸入文件 */
entry: {
index: ['babel-polyfill', path.resolve(__dirname, '../src/main.js')]
},
output: {
/* 輸出目錄,沒有則新建 */
path: path.resolve(__dirname, '../dist'),
/* 靜態(tài)目錄艾恼,可以直接從這里取文件 */
publicPath: '/',
/* 文件名 */
filename: 'js/[name].[hash].js',
chunkFilename: 'js/[name].[chunkhash].js'
},
module: {
rules: [{
test: /\.vue$/,
loader: 'vue-loader',
options: {
loaders: {
css: ExtractTextPlugin.extract({
use: 'css-loader',
fallback: 'vue-style-loader' // <- this is a dep of vue-loader, so no need to explicitly install if using npm3
})
}
}
}, {//頁面中import css文件打包需要用到
test: /\.css/,
loader: ExtractTextPlugin.extract({ fallback: 'style-loader', use: 'css-loader' })
}, {
test: /\.js$/,
loader: 'babel-loader',
/* 排除模塊安裝目錄的文件 */
exclude: /node_modules/
},{
test: /\.png$|\.jpg$|\.gif$|\.ico$/,
loader: "file-loader",
exclude: /node_modules/
}]
},
plugins: [
new HtmlWebpackPlugin({
filename: 'index.html',
template: path.resolve(__dirname, '../src/index.html'),
inject: true
}),
new ExtractTextPlugin("style.css")
]
};
6.我們先配置開發(fā)是需要文件住涉,生成環(huán)境之后再近些配置。
首先在webpack.dev.conf.js中添加
const merge = require('webpack-merge');
const baseConfig = require('./webpack.base.conf');
const webpack = require('webpack');
let devConfig = merge(baseConfig, {
output: {
path: '/'
},
plugins: [
new webpack.HotModuleReplacementPlugin(),
new webpack.NoEmitOnErrorsPlugin()
]
});
module.exports = devConfig;
7.然后在app.js中添加webpack配置蒂萎,如下
8.然后運(yùn)行npm start啟動(dòng)項(xiàng)目秆吵,看到打印出一下日志,證明啟動(dòng)成功
9.在瀏覽器中訪問http://localhost:3011/五慈,效果如下,vue + koa構(gòu)建一個(gè)hello world的小項(xiàng)目就成功了主穗。
三泻拦、添加路由實(shí)現(xiàn)單頁
1.1 vue添加路由
1.下載路由的依賴包 npm install vue-router --save
2.在src文件夾下添加router文件夾,然后新建index.js,存放路由主要配置
3.在views文件夾下忽媒,添加example文件争拐,然后添加兩個(gè)文件,分別是example.vue和example1.vue晦雨,作為路由中的兩個(gè)頁面架曹。分別添加以下內(nèi)容:
4.在router下的index.js編輯以下內(nèi)容:
5.修改main.js如下,將路由:
6.修改app.vue闹瞧,配置的路由中的compent將顯示在router-view中
7.刷新瀏覽器绑雄,可以看到以下效果
點(diǎn)擊example1將顯示(點(diǎn)擊example1跳轉(zhuǎn)并未刷新頁面,只是vue的路由跳轉(zhuǎn))
8.但是在http://localhost:3011/example1下刷新瀏覽器奥邮,現(xiàn)在會(huì)發(fā)現(xiàn)找不到
這是什么原因造成的呢万牺?
因?yàn)関ue的路由是在瀏覽器中進(jìn)行管理,如果刷新http://localhost:3011/時(shí)可以訪問到的洽腺,因?yàn)檎?qǐng)求/路徑脚粟,node將其指向了index.html(因?yàn)閣ebpack打包會(huì)把index.html打包到根目錄,而koa-webpack在沒有傳遞參數(shù)的情況下也是指向的webpack配置文件中output中的publicPath蘸朋,配置文件中配置的是/核无,所以默認(rèn)/請(qǐng)求指向index.html),以下是koa-webpack中默認(rèn)配置的源代碼
![Paste_Image.png](http://upload-images.jianshu.io/upload_images/1210894-bb4f6395ba003114.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240z
而/example1請(qǐng)求到node,node會(huì)去尋找node端的路由處理藕坯,因?yàn)閚ode端沒有配置這個(gè)路由团南,所有找不到。
如果想要訪問到/example1堕担,需要請(qǐng)求到index.html,然后由vue的路由處理找到對(duì)應(yīng)的模塊
解決方法有:
(1)vue路由采用hash模式已慢,修改router下的index.js文件,將mode的值改為hash霹购,如果是hash佑惠,但是這樣瀏覽器路徑會(huì)變成http://localhost:3011/#/example1,有一點(diǎn)丑陋,http://localhost:3011/#/example1這個(gè)路徑還是請(qǐng)求的/后面的會(huì)被當(dāng)做參數(shù)處理
(2)將所有html請(qǐng)求轉(zhuǎn)到index.html 然后讓vue的瀏覽器處理
1.2 配置node端端
1.將所有的html請(qǐng)求轉(zhuǎn)到index.html,有一個(gè)現(xiàn)成的插件connect-history-api-fallback替我們做了這件事膜楷,但是需要稍微封裝一下才能在koa2中使用旭咽。
(1)npm install connect-history-api-fallback --save 下載插件包
(2)在根目錄下添加middleware文件夾,用于存放koa的中間件
(3)在middleware文件夾中添加koa2-connect-history-api-fallback.js 文件赌厅,koa2中間件需要傳入需要的方法穷绵,所以封裝返回了一個(gè)方法
const history = require('connect-history-api-fallback');
module.exports = options=> {
const middleware = history(options);
const noop = () => {
};
return async (ctx, next)=> {
middleware(ctx, null, noop);
await next();
};
};
2.在app.js添加const history = require('./middleware/koa2-connect-history-api-fallback');和
app.use(history({
verbose: true//打出轉(zhuǎn)發(fā)日志
}));
注意:app.use(history(...))要寫在app.use(middleware({...}))之前,不然koa-webpack已經(jīng)返回not found了特愿,app.use(history(...))就不會(huì)生效了
11.寫好之后重啟服務(wù)仲墨,然后訪問瀏覽器刷新http://localhost:3011/example1就可以訪問到了
并且可以看到日志,只有請(qǐng)求html轉(zhuǎn)到了index.html
1.3 優(yōu)化
1.添加less配置揍障,讓.vue文件支持寫less文件
(1)下載less打包編譯需要的依賴目养,npm install less less-loader --save-dev
(2)在webpack.base.conf.js中配置,添加這兩個(gè)配置毒嫡,將會(huì)識(shí)別.vue里邊的less,也可以將less寫成單獨(dú)的文件
(3)在頁面中引入less文件(通常便于維護(hù)癌蚁,less寫在單獨(dú)文件中)
在src文件夾中添加static文件夾,然后在static文件夾中添加less文件兜畸,專門存放less文件努释,然后添加example.less文件,順便寫一些樣式進(jìn)去咬摇,如下
然后在example.vue文件中引入這個(gè)less文件
頁面效果如下
2.實(shí)現(xiàn)懶加載伐蒂,優(yōu)化初始化加載
在頁面比較多的時(shí)瓦堵,單頁應(yīng)用按照之前的方式打包成一個(gè)js會(huì)導(dǎo)致首頁加載時(shí)很慢澎剥,為了解決這個(gè)問題,可以修改打包锈拨,讓首頁只加載通用代碼和首頁要用到的代碼龄坪,跳轉(zhuǎn)到其他頁面再加載對(duì)應(yīng)頁面的js昭雌,這樣可以解決項(xiàng)目較大首頁加載緩慢的問題。
修改router中index.js,將.vue文件加載改為
const Example = r => require.ensure([], () => r(require('../views/example/example.vue')), 'Example');
const Example1 = r => require.ensure([], () => r(require('../views/example/example1.vue')), 'Example1');
因?yàn)閣ebpack.base.conf.js已經(jīng)加了chunkFilename: 'js/[name].[chunkhash].js'健田,所以不用再修改webpack配置
瀏覽頁面烛卧,這個(gè)時(shí)候會(huì)發(fā)現(xiàn),訪問example頁面只有example.js
點(diǎn)擊example1頁面妓局,才會(huì)新加入example1.js总放,并且加載之后,以后返回example1頁面不會(huì)重新加載好爬,提高性能
經(jīng)過以上步驟局雄,我們已經(jīng)可以在本地跑起來開發(fā)vue項(xiàng)目了。