最近項目上的事情很少,根據我本身的開發習慣,決定開發一些簡單的開發架子,方便之後事情多的時候直接套用。本文講的一個gulp+webpack+vue的單頁應用架子,想要達到的目的:javascript
盡我所能先作出一個知足以上特色的架子吧,最近看完ES6,準備再去看看flux和reduce,看過以後再來思考下前端數據如何管理比較科學規範。架子中有作的不規範可改進的地方,煩請你們指出,我好更新。
首先來看一下整個架子的結構:
css
庫文件不會隨業務代碼發生變化,因此全部庫文件打包成一個文件就行了,這部分代碼須要直接在頁面中以<script></script>
標籤引入,不能和業務代碼打包到一塊兒。若是和業務代碼打包到一塊兒,一旦業務代碼發生變化,整個打包的文件在瀏覽器中都須要被從新加載,這種作法不利於客戶端作緩存,也會使webpack打包業務代碼的過程變得很是慢,因此這裏使用gulp合併一下庫文件:html
/** * 合併lib文件 */ gulp.task('concat-lib',function(){ gulp.src(['vue/dist/vue.min.js','vue-router/dist/vue-router.min.js'],{ cwd:'../lib' }).pipe(concat('vue.min.js')).pipe(gulp.dest('../release')); })
從上圖能夠看到,全部的業務開發代碼都放在src目錄下,展開來看:
前端
核心代碼是這塊:vue
var Vue = require('vue') var VueRouter = require('vue-router'); Vue.use(VueRouter); var compo1=require('./modules/module1'); require('./css/main.css'); // 路由器須要一個根組件。 // 出於演示的目的,這裏使用一個空的組件,直接使用 HTML 做爲應用的模板 var App = Vue.extend({}) // 建立一個路由器實例 // 建立實例時能夠傳入配置參數進行定製,爲保持簡單,這裏使用默認配置 var router = new VueRouter() // 定義路由規則 // 每條路由規則應該映射到一個組件。這裏的「組件」能夠是一個使用 Vue.extend // 建立的組件構造函數,也能夠是一個組件選項對象。 // 稍後咱們會講解嵌套路由 router.map({ '/': { component: compo1 }, '/path1': { component: compo1 }, '/path2': { component: function (resolve) { //amd規範 實現效果: //路由1中的模塊和主頁面模塊打包在一塊兒 //路由2中的模塊按需加載 require(['./modules/module2'],resolve); //commonJs規範實現方式: //require.ensure([],function(require){ // var comm2=require('./components/compo2'); // resolve(comm2) //}); } } }); //默認路徑 //router.go('/path1'); // 如今咱們能夠啓動應用了! // 路由器會建立一個 App 實例,而且掛載到選擇符 #app 匹配的元素上。 router.start(App, '#app')
默認模塊是moduel1,/path1路由指向module1,/path2路由指向module2,module2的模塊並非和module1同樣在主頁面中一開始就加載好的,而是在路由到此路徑後纔去加載,app.js中提供了vue組件文檔中提供的兩種方式:CommonJs和AMD兩種規範的方式來加載,兩種方式是等價的。java
require('./css/main.css');
把全部css加載到應用中,以便在開發模式下能夠看到樣式,在打包發佈代碼的時候會忽略此require,將樣式打包成獨立的文件。webpack
打包開發代碼的webpack配置是build目錄下的webpack.config.dev.jsgit
var webpack = require('webpack'); var path=require('path'); module.exports={ //這裏寫成數組是爲了dev server插入服務配置 entry: { "app":['../src/app.js'], }, output:{ path:path.resolve(__dirname, "../release"),//__dirname+'/../release', publicPath: "/release/",//dev server 會今後路徑去拿hot-update.json filename:'[name].bundle.js' }, externals: { 'vue': 'Vue', 'vue-router':'VueRouter' }, module: { loaders: [ { test: /\.css$/, loader: 'style-loader!css-loader' }, {test:/\.html$/,loader:'html-loader'} ] }, plugins: [ ], devtool: "source-map" }
程序主入口是app.js,全部entry只須要配置一個app.js。
output配置中的publicPath是用來配置項目中靜態文件路徑的,這裏開發過程當中會使用webpack-dev-server,給配置到release目錄下就好了。
externals下面配置的是經過標籤引入,能夠在全局環境下訪問到的變量,能夠經過require這裏配置的key來獲取那些變量。
devtool: "source-map"
能夠爲壓縮以後的代碼生成source-map文件,這裏開發打包的代碼並無被壓縮,因此這個其實沒意義。
{test:/\.html$/,loader:'html-loader'}
是用來在組件中加載html模板的:github
var template=require('./module1.html'); // 定義組件 var comm = Vue.extend({ template: template, data:function () { return { items:[{a:1,b:2,c:3},{a:4,b:5,c:5},{a:7,b:8,c:9}] } } });
用上面的配置來打包,就會獲得開發版本的打包代碼了。web
爲了方便開發調試,須要啓動一個server來訪問項目,並支持熱替換,自動刷新瀏覽器,以方便修改代碼以後可以實時看到效果。
在gulpfile.js作以下配置:
ar webpackConfigDev=require("./webpack.config.dev.js"); var WebpackDevServer = require("webpack-dev-server"); /** * 使用測試配置打包,啓動hot dev server */ gulp.task('webpack-dev',['concat-lib'],function(){ var config = Object.create(webpackConfigDev); //這兩項配置本來是在webpack.config.dev.js裏邊配置,但是經過gulp啓動devserver,那種配置無效,只能在此處寫入 //官網的解釋是webpack-dev-server沒有權限讀取webpack的配置 config.entry.app.unshift("webpack-dev-server/client?http://localhost:8080/", "webpack/hot/dev-server"); config.plugins.push(new webpack.HotModuleReplacementPlugin()); var compiler = webpack(config); var server = new WebpackDevServer(compiler, { contentBase: "../", publicPath: "/release/", hot: true, compress: false, stats: { colors: true } }); server.listen(8080, "localhost", function() {}); // server.close(); });
這樣會啓動一個本地的8080端口監聽,用來訪問某個目錄下的靜態文件
contentBase: "../"
配置,指定了靜態文件目錄在項目根目錄下,因此訪問http://localhost:8080 會看到根目錄下的文件列表,點進去src目錄,就會默認訪問index.html,看到單頁應用的效果了publicPath: "/release/"
這個配置很重要,它指定了webpack-dev-server提供的打包靜態文件路徑,值得注意的是,使用WebpackDevServer的時候,並不會在release目錄生成webpack打包文件,只會在內存中生成打包文件,經過localhost:8080/release/ 路徑,能夠訪問到開發打包後的代碼。
能夠看到,訪問主頁面的時候,加載了app.bundle.js打包文件,訪問路由/path2的時候,纔會去加載1.1.bundle.js文件,子組件是延遲2s後才加載的。
更新代碼以後,會實時打包並刷新瀏覽器,看到實時效果。
和開發代碼不一樣,生產環境代碼具備如下特色:
var webpack = require('webpack'); var ExtractTextPlugin = require("extract-text-webpack-plugin"); var path=require('path'); var cssExtract=new ExtractTextPlugin("[name].[contenthash:8].css"); module.exports={ entry: { index:'../src/app.js' }, output:{ path:path.resolve(__dirname, "../release"), publicPath:"",//TODO 填寫生產環境靜態文件路徑 filename:'[name].[chunkhash:8].bundle.js' }, externals: { 'vue': 'Vue', 'vue-router':'VueRouter' }, module: { loaders: [ { test: /\.css$/, loader: cssExtract.extract("style-loader", "css-loader") }, {test:/\.html$/,loader:'html-loader'} ] }, plugins: [ new webpack.optimize.UglifyJsPlugin({ compress: { drop_console: true, warnings: false } }), cssExtract ] }
其中publicPath是填寫靜態文件路徑的,若是圖片或其餘靜態資源須要存放在CDN服務器上,能夠把CDN地址配置到這裏。
生成打包文件以後,能夠經過gulp替換掉主入口文件 index.html裏面的靜態文件路徑,這裏經過webpack模板也能夠完成此工做,但配置較爲繁瑣,我的感受仍是經過gulp來替換比較方便一點:
gulp.src('../src/index.html') //.pipe(greplace(/xxxxx/g,"xxxxx")) .pipe(gulp.dest('../release'));
打包後的代碼:
後面的步驟就是上傳靜態文件到CDN或其餘上線流程了,這裏能夠經過根據本身業務編寫的gulp插件來完成,你們業務不一樣,處理方式不盡相同,我就不繼續往下寫了。
我我的不太喜歡項目根目錄下一堆跟打包相關的文件,因此在這個項目中,我把全部跟打包相關的文件都放到了build目錄下,而後在package.json中:
"scripts": { "dev": "gulp default --gulpfile build/gulpfile.js", "build": "gulp build --gulpfile build/gulpfile.js", "release": "gulp release --gulpfile build/gulpfile.js" },
這樣就可使用npm命令來執行上面的操做了:
npm run dev
啓動webpack-dev-server,使用開發webpack配置來打包代碼,支持熱替換
npm run build
打包開發代碼
npm run release
打包生產環境代碼
對於一個可用單頁應用而言,這個架子可能還缺着不少東西,對前端數據流程的管理、網絡請求的管理、公共組件的組織等,在之後的項目中都會加上這些東西,用到了再往裏邊更新吧!
代碼地址:https://github.com/zouchengzhuo/scaffold/tree/master/gulp-webpack-vue
本文轉自個人我的站點:http://zoucz.com/blog/2016/07/19/gulp-webpack-vue/