最近项目上的事情很少,根据我本身的开发习惯,决定开发一些简单的开发架子,方便之后事情多的时候直接套用。本文讲的一个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/