本文转载于:https://jiongks.name/blog/just-vue/javascript
转载仅供本身后期学习css
首先,我会先简单介绍一下 vue 和 webpack:html
(固然若是你已经比较熟悉它们的话前两个部分能够直接跳过)前端
Vue.js 是一款极简的 mvvm 框架,若是让我用一个词来形容它,就是 “轻·巧” 。若是用一句话来描述它,它可以集众多优秀逐流的前端框架之大成,但同时保持简单易用。废话很少说,来看几个例子:vue
<script src="vue.js"></script> <div id="demo"> {{message}} <input v-model="message"> </div> <script> var vm = new Vue({ el: '#demo', data: { message: 'Hello Vue.js!' } }) </script>
首先,代码分两部分,一部分是 html,同时也是视图模板,里面包含一个值为 message
的文本何一个相同值的输入框;另外一部分是 script,它建立了一个 vm 对象,其中绑定的 dom 结点是 #demo
,绑定的数据是 {message: 'Hello Vue.js'}
,最终页面的显示效果就是一段 Hello Vue.js
文本加一个含相同文字的输入框,更关键的是,因为数据是双向绑定的,因此咱们修改文本框内文本的同时,第一段文本和被绑定的数据的 message
字段的值都会同步更新——而这底层的复杂逻辑,Vue.js 已经所有帮你作好了。java
咱们还能够加入更多的 directive,好比:node
<script src="vue.js"></script> <div id="demo2"> <img title="{{name}}" alt="{{name}}" v-attr="src: url"> <input v-model="name"> <input v-model="url"> </div> <script> var vm = new Vue({ el: '#demo2', data: { name: 'taobao', url: 'https://www.taobao.com/favicon.ico' } }) </script>
这里的视图模板加入了一个 <img>
标签,同时咱们看到了 2 个特性的值都写做了 。这样的话,图片的
title
和 alt
特性值就都会被绑定为字符串 'taobao'
。webpack
若是想绑定的特性是像 img[src]
这样的不能在 html 中随意初始化的 (可能默认会产生预期外的网络请求),不要紧,有 v-attr="src: url"
这样的写法,把被绑定的数据里的 url
同步过来。git
没有介绍到的功能还有不少,推荐你们来我(发起并)翻译的Vue.js 中文文档github
最后要介绍 Vue.js 对于 web 组件化开发的思考和设计
若是咱们要开发更大型的网页或 web 应用,web 组件化的思惟是很是重要的,这也是今天整个前端社区长久不衰的话题。
Vue.js 设计了一个 *.vue
格式的文件,令每个组件的样式、模板和脚本集合成了一整个文件, 每一个文件就是一个组件,同时还包含了组件之间的依赖关系,麻雀虽小五脏俱全,整个组件从外观到结构到特性再到依赖关系都尽收眼底 :
而且支持预编译各类方言:
这样再大的系统、在复杂的界面,也能够用这样的方式庖丁解牛。固然这种组件的写法是须要编译工具才能最终在浏览器端工做的,下面会提到一个基于 webpack 的具体方案。
从功能角度,template, directive, data-binding, components 各类实用功能都齐全,而 filter, computed var, var watcher, custom event 这样的高级功能也都洋溢着做者的巧思;从开发体验角度,这些设计几乎是彻底天然的,没有刻意设计过或欠考虑的感受,只有个别不得已的地方带了本身框架专属的 v-
前缀。从性能、体积角度评估,Vue.js 也很是有竞争力!
webpack 是另外一个近期发现的好东西。它主要的用途是经过 CommonJS 的语法把全部浏览器端须要发布的静态资源作相应的准备,好比资源的合并和打包。
举个例子,如今有个脚本主文件 app.js
依赖了另外一个脚本 module.js
// app.js var module = require('./module.js') ... module.x ... // module.js exports.x = ...
则经过 webpack app.js bundle.js
命令,能够把 app.js
和 module.js
打包在一块儿并保存到 bundle.js
同时 webpack 提供了强大的 loader 机制和 plugin 机制,loader 机制支持载入各类各样的静态资源,不仅是 js 脚本、连 html, css, images 等各类资源都有相应的 loader 来作依赖管理和打包;而 plugin 则能够对整个 webpack 的流程进行必定的控制。
好比在安装并配置了 css-loader 和 style-loader 以后,就能够经过 require('./bootstrap.css')
这样的方式给网页载入一份样式表。很是方便。
webpack 背后的原理其实就是把全部的非 js 资源都转换成 js (如把一个 css 文件转换成“建立一个 style
标签并把它插入 document
”的脚本、把图片转换成一个图片地址的 js 变量或 base64 编码等),而后用 CommonJS 的机制管理起来。一开始对于这种技术形态我我的仍是不太喜欢的,不过随着不断的实践和体验,也逐渐习惯并认同了。
最后,对于以前提到的 Vue.js,做者也提供了一个叫作 vue-loader 的 npm 包,能够把 *.vue
文件转换成 webpack 包,和整个打包过程融合起来。因此有了 Vue.js、webpack 和 vue-loader,咱们天然就能够把它们组合在一块儿试试看!
回到正题。今天要分享的是,是基于上面两个东西:Vue.js 和 webpack,以及把它们串联起来的 vue-loader
Vue.js 的做者以及提供了一个基于它们三者的项目示例 (连接已失效)。而咱们的例子会更贴近实际工做的场景,同时和团队以前总结出来的项目特色和项目流程相吻合。
<components>
组件目录,一个组件一个 .vue
文件
a.vue
b.vue
<lib>
若是实在有不能算组件,但也不来自外部 (tnpm) 的代码,能够放在这里
foo.css
bar.js
<src>
主应用/页面相关文件
app.html
主 htmlapp.vue
主 vueapp.js
一般作的事情只是 var Vue = require('vue'); new Vue(require('./app.vue'))
<dist>
(ignored)<node_modules>
(ignored)gulpfile.js
设计项目打包/监听等任务package.json
记录项目基本信息,包括模块依赖关系README.md
项目基本介绍经过 gulpfile.js
咱们能够设计整套基于 webpack 的打包/监听/调试的任务
在 gulp-webpack 包的官方文档里推荐的写法是这样的:
var gulp = require('gulp'); var webpack = require('gulp-webpack'); var named = require('vinyl-named'); gulp.task('default', function() { return gulp.src(['src/app.js', 'test/test.js']) .pipe(named()) .pipe(webpack()) .pipe(gulp.dest('dist/')); });
咱们对这个文件稍加修改,首先加入 vue-loader
tnpm install vue-loader --save .pipe(webpack({ module: { loaders: [ { test: /\.vue$/, loader: 'vue'} ] } }))
其次,把要打包的文件列表从 gulp.src(...)
中抽出来,方便未来维护,也有机会把这个信息共享到别的任务
var appList = ['main', 'sub1', 'sub2'] gulp.task('default', function() { return gulp.src(mapFiles(appList, 'js')) ... }) /** * @private */ function mapFiles(list, extname) { return list.map(function (app) {return 'src/' + app + '.' + extname}) }
如今运行 gulp
命令,相应的文件应该就打包好并生成在了 dist
目录下。而后咱们在 src/*.html
中加入对这些生成好的 js
文件的引入:
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Main</title> </head> <body> <div id="app"></div> <script src="../dist/main.js"></script> </body> </html>
用浏览器打开 src/main.html
这时页面已经能够正常工做了
监听更加简单,只要在刚才 webpack(opt)
的参数中加入 watch: true
就能够了。
.pipe(webpack({ module: { loaders: [ { test: /\.vue$/, loader: 'vue'} ] }, watch: true }))
固然最好把打包和监听设计成两个任务,分别起名为 bundle
和 watch
:
gulp.task('bundle', function() { return gulp.src(mapFiles(appList, 'js')) .pipe(named()) .pipe(webpack(getConfig())) .pipe(gulp.dest('dist/')) }) gulp.task('watch', function() { return gulp.src(mapFiles(appList, 'js')) .pipe(named()) .pipe(webpack(getConfig({watch: true}))) .pipe(gulp.dest('dist/')) }) /** * @private */ function getConfig(opt) { var config = { module: { loaders: [ { test: /\.vue$/, loader: 'vue'} ] } } if (!opt) { return config } for (var i in opt) { config[i] = opt } return config }
如今你能够没必要每次修改文件以后都运行 gulp bundle
才能看到最新的效果,每次改动以后直接刷新浏览器便可。
打包好的代码已经不那么易读了,直接在这样的代码上调试仍是不那么方便的。这个时候,webpack + vue 有另一个现成的东西:source map 支持。为 webpack 加入这个配置字段 devtool: 'source-map'
:
var config = {
module: {
loaders: [
{ test: /.vue$/, loader: ‘vue’}
]
},
devtool: ‘source-map’
}
再次运行 gulp bundle
或 gulp watch
试试看,是否是开发者工具里 debug 的时候,能够追踪断点到源代码了呢:)
完整的 javascript 代码以下:
var gulp = require('gulp') var webpack = require('gulp-webpack') var named = require('vinyl-named') var appList = ['main'] gulp.task('default', ['bundle'], function() { console.log('done') }) gulp.task('bundle', function() { return gulp.src(mapFiles(appList, 'js')) .pipe(named()) .pipe(webpack(getConfig())) .pipe(gulp.dest('dist/')) }) gulp.task('watch', function() { return gulp.src(mapFiles(appList, 'js')) .pipe(named()) .pipe(webpack(getConfig({watch: true}))) .pipe(gulp.dest('dist/')) }) /** * @private */ function getConfig(opt) { var config = { module: { loaders: [ { test: /\.vue$/, loader: 'vue'} ] }, devtool: 'source-map' } if (!opt) { return config } for (var i in opt) { config[i] = opt[i] } return config } /** * @private */ function mapFiles(list, extname) { return list.map(function (app) {return 'src/' + app + '.' + extname}) }
作出一个 vue + webpack 的 generator,把这样的项目体验分享给更多的人。目前我基于团队内部在使用的轻量级脚手架工具写了一份名叫 just-vue
的 generator,目前这个 generator 还在小范围试用当中,待比较成熟以后,再分享出来