Vue2 + webpack + express4構建單頁應用(一)

想要構建一個vue2的單頁應用,發現vue-cli生成的項目雖然可以直接用,但是生成的項目是用的vue1,而且直接使用也不能完全掌握和了解項目用了哪些插件和打包工具,為了自己更好的了解和學習開發vue2需要用到的打包工具和相關插件,自己看了許多博客,總結了以下一個構建基本vue2單頁項目的流程,對于vue2和webpack小白可以跟著步驟試著自己構建一個小項目,如有大神請多指教。

完整源碼鏈接:https://github.com/chenjiaj/vue2-express4-webpack

一、環境

需要安裝node v4.4.4及以上

二、創建基本項目

1.打開cmd,運行 npm install express-generator -g (express-generator是express的應用生成器,相關介紹:http://www.expressjs.com.cn/starter/generator.html
用生成器生成主要是為了使用bin文件夾下的www文件,為了少寫一點打印的日志而已,對應不需要的,可以不用生成器生成,自己創建server就行,可以用http模塊或者直接調用app.listen都可以

2.切換到你要生成項目的目錄,然后運行 express myapp,生成新的express項目,目錄如下:

Paste_Image.png

3.刪除public、routes、views文件夾,現在項目目錄如下

Paste_Image.png

4.在根目錄下創建index.html,內容如下:

<!DOCTYPE html>
<html lang="en">
  <head>   
     <meta charset="UTF-8"> <title>Title</title>
  </head>
  <body>  
     <div id="app"></div>
  </body>
 </html>

5.在根目錄下添加src文件,然后創建app.vue和main.js

app.vue的內容如下:

<template>
   <div>hello , this app vue !</div>
</template>
<style>  
     body{color:red;}
</style>

main.js的內容如下:

import Vue from "vue";
import App from "./app";
new Vue({
    el:'#app', 
    render:h=> h(App)
})

如果是用的webStorm,請將language設置為ECMAScript6,這樣才不會報錯誤提示


Paste_Image.png

6.需要安裝以下依賴,將package.json文件替換如下:

  {  "name": "myapp",  
      "version": "0.0.0", 
      "private": true,  
      "scripts": {    "start": "node ./bin/www"  },     
      "devDependencies": {
        "babel-core": "^6.20.0",    
        "babel-loader": "^6.2.9",    
        "babel-plugin-transform-runtime": "^6.15.0",    
        "babel-preset-es2015": "^6.18.0",   
        "babel-runtime": "^5.8.38",    
        "babel-preset-stage-2": "^6.18.0",
        "html-webpack-plugin": "^2.24.1",   
        "vue-html-loader": "^1.2.3",   
        "css-loader": "^0.26.1",
        "vue-loader": "^10.0.2",    
        "vue-template-compiler": "^2.1.6",    
        "webpack": "^1.14.0",   
        "webpack-dev-middleware": "^1.6.1" 
       }, 
       "dependencies": {    
          "express": "^4.14.0",   
          "vue": "^2.1.6",   
          "vue-router": "^2.1.1" 
       }
  }

以babel-開頭:都是用于兼容es6寫法,將es6的代碼轉換成es5的代碼
babel-core、babel-loader:babel配合webpack工具使用必須要引入的
babel-plugin-transform-runtime、babel-runtime:解決重復出現在一些模塊里,導致編譯后的代碼體積變大的問題。
babel-preset-es2015:將 ES2015 編譯成 ES5
babel-preset-stage-2:除了覆蓋stage-3的所有功能,不是對ES6功能的增加,而是為了增強代碼的可讀性和可修改性而提出的
參考:http://babeljs.io/docs/setup/#installation

webpack :webpack打包需要引入的核心包

html-webpack-plugin:是webpack的插件,這個插件用來簡化創建服務于 webpack bundle 的 HTML 文件,尤其是對于在文件名中包含了 hash 值,而這個值在每次編譯的時候都發生變化的情況。你既可以讓這個插件來幫助你自動生成 HTML 文件,也可以使用 lodash 模板加載生成的 bundles,或者自己加載這些 bundles。

vue-loader:是webpack的loader,能夠將.vue文件轉換成js文件

vue-html-loadervue-template-compilercss-loader:這三個都是webpack的loader,都是將.vue文件轉換成js文件的依賴

webpack-dev-middleware :需要webpack打包的項目,開發時使用的中間件,主要作用是不需要將打包生成的文件放在硬盤中,而是放在內存中,這樣可以提高開發效率,而且配合webpack-hot-middleware中間件使用可以實現熱加載(熱加載插件后面會介紹)

7.在根目錄下添加build文件夾,在文件夾內創建webpack.base.conf.js,內容如下:

// nodejs 中的path模塊
var path = require('path');
var webpack = require('webpack');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var  webpackConf = {
    // 入口文件,path.resolve()方法,可以結合我們給定的兩個參數最后生成絕對路徑,最終指向的就是我們的index.js文件 
    entry: {  index: [   path.resolve(__dirname, '../src/main.js')  ] },
    // 輸出配置 
    output: {  // 輸出路徑是 myProject/output/static  
        path: path.resolve(__dirname, '../output'), 
        publicPath:'/',  filename: '[name].[hash].js' 
    },
     resolve: {  
        extensions: ['', '.js', '.vue'], 
        alias: {   'vue': 'vue/dist/vue.js'  } // 設置別名vue1不需要設置,vue2必須設置 否則會報錯 
    },
    module: {  
        loaders: [   
        // 使用vue-loader 加載 .vue 結尾的文件   
            {    test: /\.vue$/,    loader: 'vue'   },  
             {    test: /\.js$/,    loader: 'babel',    exclude: /node_modules/   }  ]
    }, 
    vue: {  loaders: {   js: 'babel'  } }, 
    plugins:[  
        new HtmlWebpackPlugin({   
              filename: 'index.html',  
              template: path.resolve(__dirname, '../index.html'),  
              inject: true  
          }) ]
 };
 module.exports  = webpackConf;

path:用來存放打包后文件的輸出目錄
publicPath:指定資源文件引用的目錄

8.將根目錄下app.js內容替換如下:

var express = require('express');
var path = require('path');
var webpack = require('webpack');
var webpackConfig = require('./build/webpack.base.conf');
var app = express();// 創建一個express實例
var compiler = webpack(webpackConfig);// 調用webpack并把配置傳遞過去
// 使用 webpack-dev-middleware 中間件
var devMiddleware = require('webpack-dev-middleware')(compiler, { 
   publicPath: '/', 
   stats: {   
     colors: true,    
    chunks: false  
  }});
app.use(devMiddleware);
module.exports = app;

10.在根目錄下添加.babelrc文件,內容如下:

{  "presets": ["es2015","stage-2"],  "plugins": ["transform-runtime"],  "comments": false}

presets 字段設定轉碼規則,官方提供以下的規則集,你可以根據需要安裝。
comments是否輸出輸出中的注釋

9.在根目錄下運行 npm install ,然后運行npm start,webpack編譯完之后如下圖所示,就可以通過http://localhost:3000 訪問了,效果如圖所示:

Paste_Image.png
Paste_Image.png

這樣就生成了一個簡單的應用。

三、添加熱加載

開發是需要熱加載,即修改完代碼后重新編譯并更新瀏覽器,提高開發效率
熱加載需要webpack-hot-middleware中間件(https://www.npmjs.com/package/webpack-hot-middleware
1.在項目根目錄下運行npm install --save-dev webpack-hot-middleware
2.打開app.js,添加app.use(require("webpack-hot-middleware")(compiler));
3.在webpack.base.conf.js中的plugins中添加

  // Webpack 1.0
  new webpack.optimize.OccurenceOrderPlugin(),
  // Webpack 2.0 fixed this mispelling
  // new webpack.optimize.OccurrenceOrderPlugin(),
  new webpack.HotModuleReplacementPlugin(),
  new webpack.NoErrorsPlugin()

方法一:只完成以下步驟4

4.在webpack.base.conf.js中添加以下代碼:

Object.keys(webpackConf.entry).forEach(function (name) { 
    var extras = ['webpack-hot-middleware/client?reload=1'];
     webpackConf.entry[name] = extras.concat(webpackConf.entry[name]);
});

方法二:以下步驟4-6

4.在build文件夾中新建hot-client.js文件,內容如下:

// 動態向入口配置中注入 webpack-hot-middleware/client
var hotClient = require('webpack-hot-middleware/client')
// 訂閱事件,當 event.action === 'reload' 時執行頁面刷新
hotClient.subscribe(function (event) {
     if (event.action === 'reload') {  window.location.reload() }
})
  1. 修改webpack.base.conf.js中的enter,改為以下代碼:
  entry: { 
    index: [ 
        'webpack-hot-middleware/client',  
        path.resolve(__dirname, '../src/main.js') ]
  }

6.在webpack.base.conf.js中添加以下代碼:

var hotClient = './build/hot-client';
Object.keys(webpackConf.entry).forEach(function (name) { 
    var extras = [hotClient];
     webpackConf.entry[name] = extras.concat(webpackConf.entry[name]);
});

重新啟動服務,修改vue或者js可以看到瀏覽器自動更新了

** 注意如果編輯器是webstorm的要將settings=>appearance=>system settings中synchronization中的最后一個選項不勾選,否則沒有效果 **

Paste_Image.png

四、將開發的webpack配置提取出來

因為開發時需要webpack-dev-middleware、webpack-hot-middleware這兩個中間件,但是正真發布的時候并不需要,因此需要將這兩個的配置提取出來。

webpack-dev-middleware 這個中間件的作用是 開發的時候不生成代碼,編譯后的代碼放在內存中,不會寫入硬盤,因此不用每次編譯都生成新的文件,提高開發效率

webpack-hot-middleware用于熱加載,修改代碼后立即更新

1.首先運行npm install --save-dev webpack-merge 下載 webpack-merge 工具,用于合并webpack配置使用

2.運行 npm install --save-dev cross-env 下載cross-env工具,用戶在命令中設置環境變量

3.在build文件夾中新建webpack.dev.conf.js,寫入以下代碼:

var path = require('path');
var webpack = require('webpack');
var webPackBaseConf = require('./webpack.base.conf');
var HtmlWebpackPlugin = require('html-webpack-plugin');
var merge = require('webpack-merge');
var hotClient = './build/hot-client';

var webpackDevConf = merge(webPackBaseConf,{ 
    entry: { index: [  hotClient,  path.resolve(__dirname, '../src/main.js') ]},
    plugins:[  
    // Webpack 1.0  new webpack.optimize.OccurenceOrderPlugin(), 
    // Webpack 2.0 fixed this mispelling  
    // new webpack.optimize.OccurrenceOrderPlugin(),  
    new webpack.HotModuleReplacementPlugin(),  
    new webpack.NoErrorsPlugin()
    ]});

Object.keys(webpackDevConf.entry).forEach(function (name) { 
    var extras = [hotClient]; 
    webpackDevConf.entry[name] = extras.concat(webpackDevConf.entry[name]);
});
module.exports = webpackDevConf;

然后刪除webpack.base.conf.js中對應的代碼

注意刪除的時候小心,不要將webpack.base.conf.js中的下面代碼刪掉了

    plugins:[new HtmlWebpackPlugin({   
        filename: 'index.html',   
        template: path.resolve(__dirname, '../index.html'),   
        inject: true  }) 
    ]})]

4.修改package.json中script中start改為如下:

"start": "cross-env NODE_ENV=development node bin/www"

運行這個命令會將環境變量設置為development(默認也是development ,但為了避免環境配置被修改的情況下可以手動設置一次)

5.修改app.js,添加環境變量判斷,將開發使用的中間件添加到條件成立時執行,改為如下:

var express = require('express');
var path = require('path');
// 創建一個express實例
var app = express();
if(app.get('env') == 'development'){  
      var webpack = require('webpack');
      var webpackConfig = require('./build/webpack.dev.conf');
     // 調用webpack并把配置傳遞過去 
     var compiler = webpack(webpackConfig);  
    // 使用 webpack-dev-middleware 中間件  
    var devMiddleware = require('webpack-dev-middleware')(compiler, {   
       publicPath: '/',   
       stats: {      colors: true,      chunks: false    }  
    });    
    app.use(devMiddleware);  
    app.use(require("webpack-hot-middleware")(compiler));  

}
module.exports = app;

重新啟動服務查看效果

五、添加路由實現單頁應用

1.按照下圖添加文件夾和文件

Paste_Image.png

說明:
components文件夾中放公用組件
router放置路由相關配置的js
views下放置單頁的vue,按照模塊放置

現在模擬一個場景:
有兩個頁面首頁和用戶頁

1.修改main.js

import Vue from "vue";
import router from './router/index';//引入路由配置
import App from "./app";
import VueRouter from "vue-router";

Vue.config.debug = true;//開啟錯誤提示

Vue.use(VueRouter);

const app = new Vue({ 
    el:'#app', 
    router:router,//添加路由配置
    render: h => h(App)
});

2.修改app.vue

添加<router-view></router-view>(路由更新的地方)
注意<template></template>中的代碼必須有一個包裹元素

3.在/src/router/index.js中添加:

import VueRouter from "vue-router";
import Index from "../views/Index/index";
import User from "../views/User/user";
const routes = [
{
     path:'/', component:Index
},
{ 
    path:'/user', component:User
}];
const router = new VueRouter({ mode: 'history', routes});
module.exports = router;

4.在index.vue和user.vue中分別加上<template><div>this index page</div></template>和<template><div>this user page</div></template>

5.運行npm install --save connect-history-api-fallback,然后在app.js中加入
var history = require('connect-history-api-fallback');
app.use(history());//放在app.use(devMiddleware);之前才有效(放在 if(app.get('env') == 'development'){ 之前)

單頁請求,需要加上connect-history-api-fallback中間件否則會報404

** 注意:一定要放在app.use(devMiddleware);之前才有效 **

參考:https://github.com/bripkens/connect-history-api-fallback

重啟服務,就可以訪問http://localhost:3000看到如下

Paste_Image.png

訪問http://localhost:3000/user 效果如下

Paste_Image.png

完成以上步驟就可以開發用vue開發一個簡單的單頁應用了

五、生成環境打包

1.運行 npm install shelljs ora --save-dev

2.在build文件下創建一個webpack.prod.conf.js.內容如下:

var path = require('path');
var webpack = require('webpack');
var merge = require('webpack-merge');
// 引入基本配置
var webpackConf = require('./webpack.base.conf');
var prodWebpackConf = merge(webpackConf,{ 
    output:{  publicPath:'/',  filename: 'static/js/[name].[hash].js' },
    plugins:[ 
         new webpack.optimize.UglifyJsPlugin({  
            compress: {    warnings: false   } 
        })
    ]});
module.exports = prodWebpackConf;

3.在build文件下創建一個build.js文件,內容如下:

// https://github.com/shelljs/shelljs
require('shelljs/global');
var path = require('path');
var ora = require('ora');
var webpack = require('webpack');
var webpackConf = require('./webpack.prod.conf');
console.log( '  Tip:\n' + '  Built files are meant to be served over an HTTP server.\n' + '  Opening index.html over file:// won\'t work.\n');
var spinner = ora('building for production...');
spinner.start();
var assetsPath = path.join('/', 'static');
rm('-rf', assetsPath);
mkdir('-p', assetsPath);
cp('-R', 'static/', assetsPath);
webpack(webpackConf, function (err, stats) { 
    spinner.stop();
    if (err) throw err 
    process.stdout.write(stats.toString({   
        colors: true,   
        modules: false,   
        children: false,   
        chunks: false,   
        chunkModules: false  
    }) + '\n')
 });

4.在package.json的script中添加 "build": "node build/build.js"

5.運行npm run build 之后會生成一下文件

Paste_Image.png

6.修改app.js,在if(app.get('env') == 'development'){......}條件后添加
else{
app.use(express.static('output'));
}

7.在package.json的script中添加 "prod":"cross-env NODE_ENV=production node bin/www"

8.運行npm run prod 就可以查看成產環境了

9.一般生成環境用pm2來起服務,于是在根目錄下創建pm2.json 內容如下:

{  "apps": [    {      "script": "bin/www"    }  ]}

connect-history-api-fallback中間件注冊一定要在app.use(express.static(path.join(__dirname, 'output')));之前
10.在package.json的script中添加 "pm2_start":"cross-env NODE_ENV=production pm2 start pm2.json"

運行 npm run pm2_start就可用pm2啟動服務 (運行前需要安裝過全局的pm2 , npm install -g pm2)

完成以上步驟就可以基本完成一個簡單的vue單頁應用了

注意

1.connect-history-api-fallback中間件注冊一定要在webpack-dev-middleware中間件注冊之前
2.connect-history-api-fallback中間件注冊一定要在app.use(express.static(path.join(__dirname, 'output')));之前

參考鏈接:

1.vue2官網:http://cn.vuejs.org/v2/guide/
2.vue-loader文檔:https://vue-loader.vuejs.org/en/
3.vue-cli創建項目介紹:https://vuejs-templates.github.io/webpack/
4.Vue作者尤雨溪:Vue 2.0,漸進式前端解決方案

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容