之前用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對es6做處理,新的node版本對es6有良好的支持。
二、創(chuàng)建基本項目
1.1 啟動koa小項目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.在項目根目錄下新建config文件夾,然后進(jìn)入文件夾新建config.js,輸入以下內(nèi)容,配置端口號
module.exports = {
node: {
port: 3011
}
};
4.在項目根目錄新建app.js文件,然后輸入以下內(nèi)容,創(chuàng)建一個基本的項目
const Koa = require('koa');
const app = new Koa();
const Config = require('./config/config');
const onerror = require('koa-onerror');
//錯誤信息處理
onerror(app);
//控制臺打印請求信息
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對象中添加 "start": "node ./app.js",如下圖所示

6.此時在命令面板中輸入npm start即可啟動項目,然后在瀏覽器中訪問 http://localhost:3011/,因為現(xiàn)在還沒有對請求做任何處理,所以返回not found。

1.2 添加vue頁面,實現(xiàn)hello world
1.在根目錄下新建src,然后在src下添加index.html文件,并且添加一個id為app的div,如下。同時在命令面板輸入 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)如下:

一個hello world 的demo就寫好了,但是要在瀏覽器看到效果,還需要引入vue包,同時也需要添加webpack打包需要的文件與配置。將vue內(nèi)容打包引入index.html中,然后再將node接收到的頁面請求返回打包后的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兩個插件
webpack-dev-middleware是需要webpack打包的項目,開發(fā)時使用的中間件,主要作用是不需要將打包生成的文件放在硬盤中,而是放在內(nèi)存中,這樣可以提高開發(fā)效率,而且配合webpack-hot-middleware中間件使用可以實現(xiàn)熱加載
extract-text-webpack-plugin:主要是為了抽離css樣式,防止將樣式打包在js中引起頁面樣式加載錯亂的現(xiàn)象
html-webpack-plugin:是webpack的插件,這個插件用來簡化創(chuàng)建服務(wù)于 webpack bundle 的 HTML 文件,尤其是對于在文件名中包含了 hash 值,而這個值在每次編譯的時候都發(fā)生變化的情況。你既可以讓這個插件來幫助你自動生成 HTML 文件,也可以使用 lodash 模板加載生成的 bundles,或者自己加載這些 bundles。
vue-loader:是webpack的loader,能夠?qū)?vue文件轉(zhuǎn)換成js文件
vue-html-loader、vue-template-compiler、css-loader、vue-style-loader:這三個都是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的所有功能,不是對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)境相同配置寫字這個里邊
webpack.dev.conf.js:針對開發(fā)時配置的文件
webpack.prod.conf.js:針對生產(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.然后運行npm start啟動項目,看到打印出一下日志,證明啟動成功

9.在瀏覽器中訪問http://localhost:3011/,效果如下,vue + koa構(gòu)建一個hello world的小項目就成功了。

三、添加路由實現(xiàn)單頁
1.1 vue添加路由
1.下載路由的依賴包 npm install vue-router --save
2.在src文件夾下添加router文件夾,然后新建index.js,存放路由主要配置
3.在views文件夾下,添加example文件,然后添加兩個文件,分別是example.vue和example1.vue,作為路由中的兩個頁面。分別添加以下內(nèi)容:


4.在router下的index.js編輯以下內(nèi)容:

5.修改main.js如下,將路由:

6.修改app.vue,配置的路由中的compent將顯示在router-view中

7.刷新瀏覽器,可以看到以下效果

點擊example1將顯示(點擊example1跳轉(zhuǎn)并未刷新頁面,只是vue的路由跳轉(zhuǎn))

8.但是在http://localhost:3011/example1下刷新瀏覽器,現(xiàn)在會發(fā)現(xiàn)找不到

這是什么原因造成的呢?
因為vue的路由是在瀏覽器中進(jìn)行管理,如果刷新http://localhost:3011/時可以訪問到的,因為請求/路徑,node將其指向了index.html(因為webpack打包會把index.html打包到根目錄,而koa-webpack在沒有傳遞參數(shù)的情況下也是指向的webpack配置文件中output中的publicPath,配置文件中配置的是/,所以默認(rèn)/請求指向index.html),以下是koa-webpack中默認(rèn)配置的源代碼
的模塊
解決方法有:
(1)vue路由采用hash模式,修改router下的index.js文件,將mode的值改為hash,如果是hash,但是這樣瀏覽器路徑會變成http://localhost:3011/#/example1,有一點丑陋,http://localhost:3011/#/example1這個路徑還是請求的/后面的會被當(dāng)做參數(shù)處理

(2)將所有html請求轉(zhuǎn)到index.html 然后讓vue的瀏覽器處理
1.2 配置node端端
1.將所有的html請求轉(zhuǎn)到index.html,有一個現(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中間件需要傳入需要的方法,所以封裝返回了一個方法
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(...))就不會生效了
11.寫好之后重啟服務(wù),然后訪問瀏覽器刷新http://localhost:3011/example1就可以訪問到了
并且可以看到日志,只有請求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中配置,添加這兩個配置,將會識別.vue里邊的less,也可以將less寫成單獨的文件

(3)在頁面中引入less文件(通常便于維護(hù),less寫在單獨文件中)
在src文件夾中添加static文件夾,然后在static文件夾中添加less文件,專門存放less文件,然后添加example.less文件,順便寫一些樣式進(jìn)去,如下

然后在example.vue文件中引入這個less文件

頁面效果如下

2.實現(xiàn)懶加載,優(yōu)化初始化加載
在頁面比較多的時,單頁應(yīng)用按照之前的方式打包成一個js會導(dǎo)致首頁加載時很慢,為了解決這個問題,可以修改打包,讓首頁只加載通用代碼和首頁要用到的代碼,跳轉(zhuǎn)到其他頁面再加載對應(yīng)頁面的js,這樣可以解決項目較大首頁加載緩慢的問題。
修改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');
因為webpack.base.conf.js已經(jīng)加了chunkFilename: 'js/[name].[chunkhash].js',所以不用再修改webpack配置

瀏覽頁面,這個時候會發(fā)現(xiàn),訪問example頁面只有example.js

點擊example1頁面,才會新加入example1.js,并且加載之后,以后返回example1頁面不會重新加載,提高性能

經(jīng)過以上步驟,我們已經(jīng)可以在本地跑起來開發(fā)vue項目了。