From 063c1c8d8cd9ef5a60c7f3458710a78743393639 Mon Sep 17 00:00:00 2001 From: kodo <524580860@qq.com> Date: Sun, 27 Nov 2016 22:20:56 +0800 Subject: [PATCH] finish : vue2.0 --- .eslintrc.js | 16 - .gitignore | 5 +- .idea/codeStyleSettings.xml | 9 + README.md | 899 +-------------------- app.js | 99 --- build/build.js | 3 +- build/check-versions.js | 45 ++ build/dev-client.js | 1 + build/dev-server.js | 19 +- build/{css-loaders.js => utils.js} | 29 +- build/webpack.base.conf.js | 57 +- build/webpack.dev.conf.js | 12 +- build/webpack.prod.conf.js | 70 +- config.js | 16 - config/dev.env.js | 6 + config/index.js | 32 + config/prod.env.js | 3 + index.html | 26 +- package.json | 85 +- src/App.vue | 42 +- src/components/404.vue | 19 + src/components/Hello.vue | 53 ++ src/components/Home.vue | 21 +- src/components/LogTime.vue | 63 +- src/components/Sidebar.vue | 12 +- src/components/TimeEntries.vue | 100 +-- src/main.js | 71 +- src/store/actions.js | 16 + src/store/index.js | 18 + src/store/mutation-types.js | 7 + src/store/mutations.js | 21 + test/e2e/custom-assertions/elementCount.js | 26 - test/e2e/nightwatch.conf.js | 40 - test/e2e/runner.js | 31 - test/e2e/specs/test.js | 14 - test/unit/.eslintrc | 9 - test/unit/index.js | 13 - test/unit/karma.conf.js | 66 -- test/unit/specs/Hello.spec.js | 12 - 39 files changed, 556 insertions(+), 1530 deletions(-) delete mode 100644 .eslintrc.js create mode 100644 .idea/codeStyleSettings.xml delete mode 100644 app.js create mode 100644 build/check-versions.js rename build/{css-loaders.js => utils.js} (55%) delete mode 100644 config.js create mode 100644 config/dev.env.js create mode 100644 config/index.js create mode 100644 config/prod.env.js create mode 100644 src/components/404.vue create mode 100644 src/components/Hello.vue create mode 100644 src/store/actions.js create mode 100644 src/store/index.js create mode 100644 src/store/mutation-types.js create mode 100644 src/store/mutations.js delete mode 100644 test/e2e/custom-assertions/elementCount.js delete mode 100644 test/e2e/nightwatch.conf.js delete mode 100644 test/e2e/runner.js delete mode 100644 test/e2e/specs/test.js delete mode 100644 test/unit/.eslintrc delete mode 100644 test/unit/index.js delete mode 100644 test/unit/karma.conf.js delete mode 100644 test/unit/specs/Hello.spec.js diff --git a/.eslintrc.js b/.eslintrc.js deleted file mode 100644 index 85a83760..00000000 --- a/.eslintrc.js +++ /dev/null @@ -1,16 +0,0 @@ -module.exports = { - root: true, - // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style - extends: 'standard', - // required to lint *.vue files - plugins: [ - 'html' - ], - // add your custom rules here - 'rules': { - // allow paren-less arrow functions - 'arrow-parens': 0, - // allow debugger during development - 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 - } -} diff --git a/.gitignore b/.gitignore index be86a2b1..1227225f 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,5 @@ node_modules/ dist/ npm-debug.log -selenium-debug.log -test/unit/coverage -test/e2e/reports +.idea/ + diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml new file mode 100644 index 00000000..85fb28c8 --- /dev/null +++ b/.idea/codeStyleSettings.xml @@ -0,0 +1,9 @@ + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index 3bfa084b..283044d4 100644 --- a/README.md +++ b/README.md @@ -1,895 +1,18 @@ -# (1/2)Vue构建单页应用最佳实战 +# vue-tutorial ---- +> A Vue.js project -## 前言 +## Build Setup -我们将会选择使用一些vue周边的库 +``` bash +# install dependencies +npm install -> 1.使用node.js后台,了解到如何获取数据 +# serve with hot reload at localhost:8080 +npm run dev -> 2.实现单页路由 - -> 3.实现HTTP请求我们的node - -> 4.单项数据流 - -> 5.使用.vue文件进行开发 - -最终我们将会构建出一个小demo,不废话,直接上图。 -![](http://7xim8z.com1.z0.glb.clouddn.com/vue-tutorial-4.png) - - -## 安装 - -1.我们将会使用webpack去为我们的模块打包,预处理,热加载。如果你对webpack不熟悉,它就是可以帮助我们把多个js文件打包为1个入口文件,并且可以达到按需加载。这就意味着,我们不用去担心由于太多的组件,导致了过多的HTTP请求,这是非常有益于产品体验的。但,我们并不只是为了这个而使用webpack,我们需要用webpack去编译.vue文件,如果没有使用一个loader去转换我们.vue文件里的style,js,html,那么浏览器就无法识别。 - -2.模块热加载是webpack的一个非常碉堡的特性,将会为我们的单页应用带来极大的便利。 -通常来说,当我们修改了代码刷新页面,那应用里的所有状态就都没有了。这对于开发一个单页应用来说是非常痛苦的,因为需要重新在跑一遍流程。如果有模块热加载,当你修改了代码,你的代码会直接修改,页面并不会刷新,所以状态也会被保留。 - -3.Vue也为我们提供了CSS预处理,所以我们可以选择在.vue文件里写LESS或者SASS去代替原生CSS。 - -4.我们过去通常需要使用npm下载一堆的依赖,但是现在我们可以选择Vue-cli。这是一个vue生态系统中一个伟大创举。这意味着我们不需要手动构建我们的项目,而它就可以很快地为我们生成。 - -首先,安装vue-cli。(确保你有node和npm) - -`npm i -g vue-cli` - -然后创建一个webpack项目并且下载依赖 - -`vue init webpack vue-time-tracker` -`cd vue-time-tracker` -`npm i` - -接着使用 `npm run dev` 在热加载中运行我们的应用 - -这一行命令代表着它会去找到`package.json`的`scripts`对象,执行`node bulid/dev-server.js`。在这文件里,配置了Webpack,会让它去编译项目文件,并且运行服务器,我们在`localhost:8080`即可查看我们的应用。 - -![](https://cdn.scotch.io/9/vFba0QgQRReyNZPgFpKU_vue-time-1.png) - -这些都准备好后,我们需要为我们的路由和XHR请求下载两个库,我们可以从vue的官网中找到他们。 - -`npm i vue-resource vue-router --save` - -### 初始化(main.js) - -查看我们的应用文件,我们可以在src目录下找到`App.vue`和`main.js`。在`main.js`文件中,我们引入`Vue`和`App`,并且创建了一个vue的实例(因为在router这行引入了App组件`router.start(App, '#app')`) - -```javascript -// src/main.js - -import Vue from 'vue' -import App from './App.vue' -import Hello from './components/Hello.vue' - -import VueRouter from 'vue-router' -import VueResource from 'vue-resource' - -//注册两个插件 -Vue.use(VueResource) -Vue.use(VueRouter) - -const router = new VueRouter() - -// 路由map -router.map({ - '/hello': { - component: Hello - } -}) - -router.redirect({ - '*': '/hello' -}) - -router.start(App, '#app') -``` - -我们还需要在`index.html`包裹下我们的`` - -```html -//index.html - -
- -
-``` - -我们的初始化就到这结束了,接下来让我们开始创建别的组件。 - - -### 创建首页 View - -首先,我们需要为我们的应用增加下bootstrap.css,为了方便,在这就直接在头部引入CDN。 - -```html - - - 计划板 - - -``` - -接着在App.vue里为我们的应用写个顶部导航。 - -```js -// src/App.vue - - -``` - -除了我们的`navbar`以外,我们还需要一个`.container`去放我们其余需要展示的信息。 -并且在这里我们要放一个`router-view`标签,`vue-router`的切换就是通过这个标签开始显现的。 - -接着,我们需要创建一个`Home.vue`作为我们的首页 - -```js -// src/components/Home.vue - - -``` - -既然我们需要显示Home,那就需要开始配置路由,这很简单,只需要在`main.js`里把`Hello.vue`换为`Home.vue`即可 - -```js -//... -router.map({ - '/Home': { - component: Home - } -}) - -router.redirect({ - '*': '/Home' -}) -``` - -![](http://7xim8z.com1.z0.glb.clouddn.com/vue-tutorial-1.png) - - -### 创建 任务列表 View - -在这个页面,我们需要去创建我们的时间跟踪列表。 - -> PS:现在这个页面没有数据,之后我们会在后台配置 - -```js - -// src/components/TimeEntries.vue - - -``` - -关于template的解释,都写在一起了,再看看我们的`script` - -```js -// src/components/TimeEntries.vue - - -``` - -别忘了为我们的组件写上一些需要的样式 -```js -// src/components/TimeEntries.vue - - -``` - -由于新增了页面,所以我们继续配置我们的路由 - -```js -// src/main.js - -import TimeEntries from './components/TimeEntries.vue' - -//... - -router.map({ - '/home': { - component: Home - }, - '/time-entries': { - component: TimeEntries - } -}) - -//... -``` - -![](http://7xim8z.com1.z0.glb.clouddn.com/vue-tutorial-2.png) - - -### 创建任务组件 - -这个比较简单我们直接给出代码 - -```js -// src/components/LogTime.vue - - - - - -``` - -这个组件很简单就3个input输入而已,然后就两个按钮,保存我们就把数据push进我们的列表里,并且初始化我们的timeEntry。取消的话,我们就路由定位到`/time-entries`即可。 - -> ps:按理来说我们应该是要填写6个数据包括名字,邮箱和头像。但这里为了演示就暂时先这样。以后结合后台我们会继续完善这里。 - -`LogTime`属于我们`TimeEntries`组件的一个子路由,所以我们依旧需要配置下我们的`router.map` - -```js -// src/main.js - -import LogTime from './components/LogTime.vue' - -//... - -router.map({ - '/home': { - component: Home - }, - '/time-entries': { - component: TimeEntries, - subRoutes: { - '/log-time': { - component: LogTime - } - } - } -}) - -//... -``` - -![](http://7xim8z.com1.z0.glb.clouddn.com/vue-tutorial-3.png) - -### 创建侧边栏组件 - -目前我们首页左侧还有一块空白,我们需要它放下一个侧边栏去统计所有计划的总时间。 - -```js -// src/App.vue - - //... - -
-
- -
-
- -
-
- - //... -``` - -由于我们把总时间存放在最上级的父组件上,所以我们需要把我们的总时间传入我们的`sidebar`组件。 - -在写下我们的两个时间计算方法 - -```js - -``` - -最后给出我们`Sidebar.vue` -``` - - - -``` - -`props`就是vue中传值的写法,不仅要在我们自定义的标签上传入` `,还需要在组件里js里定义`props: ['time']` - - -### 最后 - -本章,我们可以学习到许多关于vue的特性。 - -1.了解了vue-cli脚手架 - -2.初步对webpack有了一些了解和认识 - -3.如何用.vue愉快的开发 - -4.父子组件通信 - -5.路由(子路由)的应用 - - -> 下一章,我们将会结合node学习vue-resource,更好的完善我们SPA应用 - - -## 番外篇 - -> 我看很多人都不知道如何引入bootstrap,我就在这加了一下 - -首先npm i jquery bootstrap style-loader --save-dev; - -然后我修改了两个文件 第一个是 `webpack.base.conf.js` 我把module都改了 - -最后我们在入口js文件里加三行代码 - -`import 'jquery'` -`import 'bootstrap/dist/css/bootstrap.css'` -`import 'bootstrap/dist/js/bootstrap'` - -在npm run dev 看看页面吧! 在head里会有一个style全是bootstrap的代码.别忘了把index.html里的第三方bootstrap注释了. - -在我这次更新的代码里,我已经把引用第三方代码删了. - - -# (2/2)Vue构建单页应用最佳实战 - -## 前言 - -> 本章节,将会把所有的请求全写为跨域请求。不知道为什么,很多人一用了框架就会不知所措。给大家一个忠告,享受框架带来的便利,别忘了时刻提醒自己学好基础知识。 - -先把一些不必要的代码删了。 - -```js -//TimeEntries.vue 的模拟数据代码 -data () { - // 模拟下初始化数据 - /*let existingEntry = { - comment: '我的第一个任务', - totalTime: 1.5, - date: '2016-05-01' - }*/ - return { - timeEntries: [] - } -}, -//头像和昵称暂时写死 -
- -

- - 二哲 - -

-
- - -//LogTime.vue里的模拟数据代码 -data () { - return { - timeEntry: { - /*user: { - name: '二哲', - email: 'kodo@forchange.cn', - image: 'https://sfault-avatar.b0.upaiyun.com/888/223/888223038-5646dbc28d530_huge256' - },*/ - } - } -}, -``` - -> 我们将专注3个字段的增删改查,任务时间,持续时间,备注。 - -## 正文 - -我们的数据交互其实很简单,所以我在这选择使用大家最熟悉的`express`和`mongodb`,在一个`app.js` 文件里完成所有的`controller`。 - -首先,安装几个必要的包`npm i express mongodb morgan body-parser --save-dev;` - -简单解释下Morgan和body-parser,其实就是一个log美化和解析参数。具体大家可以google下。 - -在我们的根目录下,创建`app.js`初始化以下代码 - -```js -//app.js -var express = require('express'); -var app = express(); -var bodyParser = require('body-parser'); -var morgan = require('morgan'); - -var MongoClient = require('mongodb').MongoClient; -var mongoUrl = 'mongodb://localhost:27017/mission'; -var _db; - -app.use(morgan('dev')); -app.use(bodyParser.json()); -app.use(express.static('dist')); - -MongoClient.connect(mongoUrl, function (err, db) { - if(err) { - console.error(err); - return; - } - - console.log('connected to mongo'); - _db = db; - app.listen(8888, function () { - console.log('server is running...'); - }); -}); -``` - -解释下mongoUrl这行`mongodb://localhost:27017/mission` 连接相应的端口,并且使用mission表。此时你是没有`mission`数据库的,这不用在意。在我们后续操作中,它将会自动创建一个mission数据库。 - -上面代码的意思是,我们创建我们的一个mongo连接,当数据库连接上了后再启动我们的服务器。 - -接着先启动我们的mongo服务。在命令行里 `sudo mongo` 。 - -![](http://7xim8z.com1.z0.glb.clouddn.com/vue-tutorial-2-1.png) - -如果你用得是webstrom编辑器,可以直接运行`app.js`,如果是命令行,那就使用 `node app.js` - -如果看见命令行输出了 `connected to mongo` `server is running...` 就可以在`8888`端口访问我们的应用了。(在这之前别忘了build你的代码) - -由于我们讲得是跨域,所以我们讲在我们的dev环境下完成所有的请求。`npm run dev` - -关闭我们的8888端口页面,进入8080端口的开发环境。 - -写下我们第一个创建任务的请求。 - -```js -//app.js - -//使用post方法 -app.post('/create', function(req, res, next) { - //接收前端发送的字段 - var mission = req.body; - //选择一个表my_mission 此时没有没关系,也会自动创建 - var collection = _db.collection('my_mission'); - //如果我们需要的字段不存在,返回前端信息 - if(!mission.comment || !mission.totalTime || !mission.date) { - res.send({errcode:-1,errmsg:"params missed"}); - return; - } - //如果存在就插入数据库,返回OK - collection.insert({comment: mission.comment, totalTime: mission.totalTime,date:mission.date}, function (err, ret) { - if(err) { - console.error(err); - res.status(500).end(); - } else { - res.send({errcode:0,errmsg:"ok"}); - } - }); -}); +# build for production with minification +npm run build ``` -修改下我们的`LogTime.vue` - -```js -//LogTime.vue - - -methods: { - save () { - this.$http.post('http://localhost:8888/create',{ - comment : this.timeEntry.comment, - totalTime : this.timeEntry.totalTime, - date : this.timeEntry.date - }).then(function(ret) { - console.log(ret); - let timeEntry = this.timeEntry - console.log(timeEntry); - this.$dispatch('timeUpdate', timeEntry) - this.timeEntry = {} - }) - } -} - -``` - -输入好内容,点击保存按钮,会发现报了个错。这其实就是最常见的跨域请求错误。 - -![](http://7xim8z.com1.z0.glb.clouddn.com/vue-tutorial-2-2.png) -![](http://7xim8z.com1.z0.glb.clouddn.com/vue-tutorial-2-3.png) -但是我们明明写得是`post`请求为什么显示得是`options`呢? - -这其实是跨域请求前会先发起的一个`options`请求,需要先问问服务端,我需要一些操作可以吗?如果服务端那里是允许的,才会继续让你发送`post`请求。 - -我不知道那些使用`vue-resource`各种姿势也想满足跨域请求的人是怎么想的。想上天吗? - -所以我们需要服务端配置,而不是前端。 - -```js -//app.js -app.all("*", function (req, res, next) { - res.header('Access-Control-Allow-Origin', '*'); - res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With"); - res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS"); - if (req.method == 'OPTIONS') { - res.send(200); - } else { - next(); - } -}); - -``` - -`Access-Control-Allow-Origin`是设置你的来源域名,写`*`是很危险的操作。所以我们可以直接写成我们所需的域名和端口,别人就没法请求了。 - -另外几行就不解释了,一看就懂。 - -不出意外,可以发现发送了options后,马上发送了post,然后就创建成功了。看下mongo的表,也多了一条记录。 - -接着来让我们一口气写完剩下的三个请求。列表渲染,删除计划,获取总时长。 - -```js -//app.js -var ObjectID = require('mongodb').ObjectID - -//获取总时长 -app.get('/time', function(req, res, next) { - //获取数据表 - var collection = _db.collection('my_mission'); - var time = 0; - //查询出所有计划 - collection.find({}).toArray(function (err, ret) { - if(err) { - console.error(err); - return; - } - //所有计划累加时长 - ret.forEach(function (item, index) { - time += +item.totalTime; - }); - //返回时长 - res.json({errcode:0,errmsg:"ok",time:time}); - }); -}); - -//获取列表 -app.get('/time-entries', function(req, res, next) { - var collection = _db.collection('my_mission'); - collection.find({}).toArray(function (err, ret) { - if(err) { - console.error(err); - return; - } - res.json(ret); - }); -}); - -//删除计划 -app.delete('/delete/:id', function (req, res, next) { - var _id = req.params.id; - var collection = _db.collection('my_mission'); - console.log(_id) - //使用mongodb的唯一ObjectId字段查找出对应id删除记录 - collection.remove({_id: new ObjectID(_id)} ,function (err, result) { - if(err) { - console.error(err); - res.status(500).end(); - } else { - res.send({errcode:0,errmsg:"ok"}); - } - }); -}); -``` -前端部分 - -```js -//App.vue -ready() { - this.$http.get('http://localhost:8888/time') - .then(function(ret) { - this.totalTime = ret.data.time; - }) - .then(function(err) { - console.log(err); - }) -}, -``` -```js -//TimeEntries.vue -route : { - data(){ - this.$http.get('http://localhost:8888/time-entries') - .then(function(ret) { - this.timeEntries = ret.data; - }) - .then(function(err) { - console.log(err); - }) - } -}, -``` -```js -//TimeEntries.vue -
- -
- -deleteTimeEntry (timeEntry) { - // 删除 - let index = this.timeEntries.indexOf(timeEntry) - let _id = this.timeEntries[index]._id - if (window.confirm('确认删除?')) { - this.$http.delete('http://localhost:8888/delete/' + _id) - .then(function(ret) { - console.log(ret); - }) - .then(function(err) { - console.log(err) - }); - this.timeEntries.splice(index, 1) - this.$dispatch('deleteTime', timeEntry) - } -} - -``` - - -## 完结 - -到此,我们就将我们整个应用完成了。新增创建删除都可用了。 - -本来还想有上传头像等,那样觉得更多的是偏后端教学。既然我们是vue的简单入门教程就不过多介绍。 - -本系列让大家轻松的了解学习了vue,vue-router,vue-resource,express,mongodb的运用。 - -还是那句话,享受框架带来便利的同时,别忘了加强基础的训练。基本功才是真正的王道啊。玩电竞的玩家一定深有体会。 - -> 最后给有兴趣的同学留下两个简单的作业 - 1.完成头像昵称的字段 - 2.完成修改操作 - -源码地址:https://github.com/MeCKodo/vue-tutorial - - - - - - +For detailed explanation on how things work, checkout the [guide](http://vuejs-templates.github.io/webpack/) and [docs for vue-loader](http://vuejs.github.io/vue-loader). diff --git a/app.js b/app.js deleted file mode 100644 index 34c4999e..00000000 --- a/app.js +++ /dev/null @@ -1,99 +0,0 @@ -var express = require('express'); -var app = express(); -var bodyParser = require('body-parser'); -var morgan = require('morgan'); -var ObjectID = require('mongodb').ObjectID - -var MongoClient = require('mongodb').MongoClient; -var mongoUrl = 'mongodb://localhost:27017/mission'; -var _db; - -app.use(morgan('dev')); -app.use(bodyParser.json()); -app.use(express.static('dist')); - -MongoClient.connect(mongoUrl, function (err, db) { - if(err) { - console.error(err); - return; - } - - console.log('connected to mongo'); - _db = db; - app.listen(8888, function () { - console.log('server is running...'); - }); -}); - -app.all("*", function (req, res, next) { - res.header('Access-Control-Allow-Origin', '*'); - res.header("Access-Control-Allow-Headers", "Content-Type,Content-Length, Authorization, Accept,X-Requested-With"); - res.header("Access-Control-Allow-Methods","PUT,POST,GET,DELETE,OPTIONS"); - if (req.method == 'OPTIONS') { - res.send(200); - } else { - next(); - } -}); - -app.get('/time', function(req, res, next) { - var collection = _db.collection('my_mission'); - var time = 0; - collection.find({}).toArray(function (err, ret) { - if(err) { - console.error(err); - return; - } - - ret.forEach(function (item, index) { - time += +item.totalTime; - }); - res.json({errcode:0,errmsg:"ok",time:time}); - }); -}); - -app.get('/time-entries', function(req, res, next) { - var collection = _db.collection('my_mission'); - collection.find({}).toArray(function (err, ret) { - if(err) { - console.error(err); - return; - } - res.json(ret); - }); -}); - -app.post('/create', function(req, res, next) { - var mission = req.body; - var collection = _db.collection('my_mission'); - - if(!mission.comment || !mission.totalTime || !mission.date) { - res.send({errcode:-1,errmsg:"params missed"}); - return; - } - - collection.insert({comment: mission.comment, totalTime: mission.totalTime,date:mission.date}, function (err, ret) { - if(err) { - console.error(err); - res.status(500).end(); - } else { - res.send({errcode:0,errmsg:"ok"}); - } - }); -}); - -app.delete('/delete/:id', function (req, res, next) { - var _id = req.params.id; - var collection = _db.collection('my_mission'); - console.log(_id) - collection.remove({_id: new ObjectID(_id)} ,function (err, result) { - if(err) { - console.error(err); - res.status(500).end(); - } else { - res.send({errcode:0,errmsg:"ok"}); - } - }); -}); - - diff --git a/build/build.js b/build/build.js index 37f5a820..b3c9aad4 100644 --- a/build/build.js +++ b/build/build.js @@ -1,4 +1,5 @@ // https://github.com/shelljs/shelljs +require('./check-versions')() require('shelljs/global') env.NODE_ENV = 'production' @@ -20,7 +21,7 @@ spinner.start() var assetsPath = path.join(config.build.assetsRoot, config.build.assetsSubDirectory) rm('-rf', assetsPath) mkdir('-p', assetsPath) -cp('-R', 'static/', assetsPath) +cp('-R', 'static/*', assetsPath) webpack(webpackConfig, function (err, stats) { spinner.stop() diff --git a/build/check-versions.js b/build/check-versions.js new file mode 100644 index 00000000..e2b6cf74 --- /dev/null +++ b/build/check-versions.js @@ -0,0 +1,45 @@ +var semver = require('semver') +var chalk = require('chalk') +var packageConfig = require('../package.json') +var exec = function (cmd) { + return require('child_process') + .execSync(cmd).toString().trim() +} + +var versionRequirements = [ + { + name: 'node', + currentVersion: semver.clean(process.version), + versionRequirement: packageConfig.engines.node + }, + { + name: 'npm', + currentVersion: exec('npm --version'), + versionRequirement: packageConfig.engines.npm + } +] + +module.exports = function () { + var warnings = [] + for (var i = 0; i < versionRequirements.length; i++) { + var mod = versionRequirements[i] + if (!semver.satisfies(mod.currentVersion, mod.versionRequirement)) { + warnings.push(mod.name + ': ' + + chalk.red(mod.currentVersion) + ' should be ' + + chalk.green(mod.versionRequirement) + ) + } + } + + if (warnings.length) { + console.log('') + console.log(chalk.yellow('To use this template, you must update following to modules:')) + console.log() + for (var i = 0; i < warnings.length; i++) { + var warning = warnings[i] + console.log(' ' + warning) + } + console.log() + process.exit(1) + } +} diff --git a/build/dev-client.js b/build/dev-client.js index 89f00795..18aa1e21 100644 --- a/build/dev-client.js +++ b/build/dev-client.js @@ -1,3 +1,4 @@ +/* eslint-disable */ require('eventsource-polyfill') var hotClient = require('webpack-hot-middleware/client?noInfo=true&reload=true') diff --git a/build/dev-server.js b/build/dev-server.js index 35fb9424..dcba5d28 100644 --- a/build/dev-server.js +++ b/build/dev-server.js @@ -1,11 +1,12 @@ +require('./check-versions')() +var config = require('../config') +if (!process.env.NODE_ENV) process.env.NODE_ENV = JSON.parse(config.dev.env.NODE_ENV) var path = require('path') var express = require('express') var webpack = require('webpack') -var config = require('../config') +var opn = require('opn') var proxyMiddleware = require('http-proxy-middleware') -var webpackConfig = process.env.NODE_ENV === 'testing' - ? require('./webpack.prod.conf') - : require('./webpack.dev.conf') +var webpackConfig = require('./webpack.dev.conf') // default port where dev server listens for incoming traffic var port = process.env.PORT || config.dev.port @@ -53,7 +54,7 @@ app.use(devMiddleware) app.use(hotMiddleware) // serve pure static assets -var staticPath = path.join(config.build.assetsPublicPath, config.build.assetsSubDirectory) +var staticPath = path.posix.join(config.dev.assetsPublicPath, config.dev.assetsSubDirectory) app.use(staticPath, express.static('./static')) module.exports = app.listen(port, function (err) { @@ -61,5 +62,11 @@ module.exports = app.listen(port, function (err) { console.log(err) return } - console.log('Listening at http://localhost:' + port + '\n') + var uri = 'http://localhost:' + port + console.log('Listening at ' + uri + '\n') + + // when env is testing, don't need open it + if (process.env.NODE_ENV !== 'testing') { + opn(uri) + } }) diff --git a/build/css-loaders.js b/build/utils.js similarity index 55% rename from build/css-loaders.js rename to build/utils.js index b16ff9fe..dc3cdd01 100644 --- a/build/css-loaders.js +++ b/build/utils.js @@ -1,6 +1,15 @@ +var path = require('path') +var config = require('../config') var ExtractTextPlugin = require('extract-text-webpack-plugin') -module.exports = function (options) { +exports.assetsPath = function (_path) { + var assetsSubDirectory = process.env.NODE_ENV === 'production' + ? config.build.assetsSubDirectory + : config.dev.assetsSubDirectory + return path.posix.join(assetsSubDirectory, _path) +} + +exports.cssLoaders = function (options) { options = options || {} // generate loader string to be used with extract text plugin function generateLoaders (loaders) { @@ -16,6 +25,8 @@ module.exports = function (options) { return loader + (options.sourceMap ? extraParamChar + 'sourceMap' : '') }).join('!') + // Extract CSS when that option is specified + // (which is the case during production build) if (options.extract) { return ExtractTextPlugin.extract('vue-style-loader', sourceLoader) } else { @@ -23,7 +34,7 @@ module.exports = function (options) { } } - // http://vuejs.github.io/vue-loader/configurations/extract-css.html + // http://vuejs.github.io/vue-loader/en/configurations/extract-css.html return { css: generateLoaders(['css']), postcss: generateLoaders(['css']), @@ -34,3 +45,17 @@ module.exports = function (options) { styl: generateLoaders(['css', 'stylus']) } } + +// Generate loaders for standalone style files (outside of .vue) +exports.styleLoaders = function (options) { + var output = [] + var loaders = exports.cssLoaders(options) + for (var extension in loaders) { + var loader = loaders[extension] + output.push({ + test: new RegExp('\\.' + extension + '$'), + loader: loader + }) + } + return output +} diff --git a/build/webpack.base.conf.js b/build/webpack.base.conf.js index 5a4ed55b..931290b0 100644 --- a/build/webpack.base.conf.js +++ b/build/webpack.base.conf.js @@ -1,8 +1,14 @@ var path = require('path') var config = require('../config') -var cssLoaders = require('./css-loaders') +var utils = require('./utils') var projectRoot = path.resolve(__dirname, '../') -var ExtractTextPlugin = require('extract-text-webpack-plugin') + +var env = process.env.NODE_ENV +// check env & config/index.js to decide weither to enable CSS Sourcemaps for the +// various preprocessor loaders added to vue-loader at the end of this file +var cssSourceMapDev = (env === 'development' && config.dev.cssSourceMap) +var cssSourceMapProd = (env === 'production' && config.build.productionSourceMap) +var useCssSourceMap = cssSourceMapDev || cssSourceMapProd module.exports = { entry: { @@ -10,13 +16,14 @@ module.exports = { }, output: { path: config.build.assetsRoot, - publicPath: config.build.assetsPublicPath, + publicPath: process.env.NODE_ENV === 'production' ? config.build.assetsPublicPath : config.dev.assetsPublicPath, filename: '[name].js' }, resolve: { extensions: ['', '.js', '.vue'], fallback: [path.join(__dirname, '../node_modules')], alias: { + 'vue$': 'vue/dist/vue.common.js', 'src': path.resolve(__dirname, '../src'), 'assets': path.resolve(__dirname, '../src/assets'), 'components': path.resolve(__dirname, '../src/components') @@ -31,13 +38,10 @@ module.exports = { test: /\.vue$/, loader: 'vue' }, - { - test: /\.css$/, - loader: "style!css" - }, { test: /\.js$/, loader: 'babel', + include: projectRoot, exclude: /node_modules/ }, { @@ -45,44 +49,29 @@ module.exports = { loader: 'json' }, { - test: /\.(png|jpg)$/, + test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, loader: 'url', query: { limit: 10000, - name: '[name].[ext]?[hash:10]' + name: utils.assetsPath('img/[name].[hash:7].[ext]') } }, { - test: /\.svg(\?v=\d+\.\d+\.\d+)?$/, - loader: "url", - query: { - name: '[name].[ext]?mimetype=image/svg+xml' - } - }, - { - test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/, - loader: "url-loader?limit=10000&minetype=application/font-woff" - }, - { - test: /\.ttf(\?v=\d+\.\d+\.\d+)?$/, - loader: "url", - query: { - name: '[name].[ext]?mimetype=application/font-woff2' - } - }, - { - test: /\.eot(\?v=\d+\.\d+\.\d+)?$/, - loader: "url", + test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, + loader: 'url', query: { - name: '[name].[ext]?mimetype=application/font-woff2' + limit: 10000, + name: utils.assetsPath('fonts/[name].[hash:7].[ext]') } } ] }, vue: { - loaders: cssLoaders() - }, - eslint: { - formatter: require('eslint-friendly-formatter') + loaders: utils.cssLoaders({ sourceMap: useCssSourceMap }), + postcss: [ + require('autoprefixer')({ + browsers: ['last 2 versions'] + }) + ] } } diff --git a/build/webpack.dev.conf.js b/build/webpack.dev.conf.js index 932fd6d2..7e1a104f 100644 --- a/build/webpack.dev.conf.js +++ b/build/webpack.dev.conf.js @@ -1,5 +1,7 @@ +var config = require('../config') var webpack = require('webpack') var merge = require('webpack-merge') +var utils = require('./utils') var baseWebpackConfig = require('./webpack.base.conf') var HtmlWebpackPlugin = require('html-webpack-plugin') @@ -9,9 +11,15 @@ Object.keys(baseWebpackConfig.entry).forEach(function (name) { }) module.exports = merge(baseWebpackConfig, { + module: { + loaders: utils.styleLoaders({ sourceMap: config.dev.cssSourceMap }) + }, // eval-source-map is faster for development devtool: '#eval-source-map', plugins: [ + new webpack.DefinePlugin({ + 'process.env': config.dev.env + }), // https://github.com/glenjamin/webpack-hot-middleware#installation--usage new webpack.optimize.OccurenceOrderPlugin(), new webpack.HotModuleReplacementPlugin(), @@ -21,10 +29,6 @@ module.exports = merge(baseWebpackConfig, { filename: 'index.html', template: 'index.html', inject: true - }), - new webpack.ProvidePlugin({ - $: 'jquery', - jQuery: 'jquery', }) ] }) diff --git a/build/webpack.prod.conf.js b/build/webpack.prod.conf.js index 5646b19a..0ca54501 100644 --- a/build/webpack.prod.conf.js +++ b/build/webpack.prod.conf.js @@ -1,47 +1,47 @@ var path = require('path') var config = require('../config') +var utils = require('./utils') var webpack = require('webpack') var merge = require('webpack-merge') var baseWebpackConfig = require('./webpack.base.conf') -var cssLoaders = require('./css-loaders') var ExtractTextPlugin = require('extract-text-webpack-plugin') var HtmlWebpackPlugin = require('html-webpack-plugin') +var env = config.build.env -module.exports = merge(baseWebpackConfig, { +var webpackConfig = merge(baseWebpackConfig, { + module: { + loaders: utils.styleLoaders({ sourceMap: config.build.productionSourceMap, extract: true }) + }, devtool: config.build.productionSourceMap ? '#source-map' : false, output: { path: config.build.assetsRoot, - filename: path.join(config.build.assetsSubDirectory, '[name].[chunkhash].js'), - chunkFilename: path.join(config.build.assetsSubDirectory, '[id].[chunkhash].js') + filename: utils.assetsPath('js/[name].[chunkhash].js'), + chunkFilename: utils.assetsPath('js/[id].[chunkhash].js') }, vue: { - loaders: cssLoaders({ + loaders: utils.cssLoaders({ sourceMap: config.build.productionSourceMap, extract: true }) }, plugins: [ - // http://vuejs.github.io/vue-loader/workflow/production.html + // http://vuejs.github.io/vue-loader/en/workflow/production.html new webpack.DefinePlugin({ - 'process.env': { - NODE_ENV: '"production"' - } + 'process.env': env }), new webpack.optimize.UglifyJsPlugin({ compress: { warnings: false } }), - new webpack.optimize.OccurenceOrderPlugin(), + new webpack.optimize.OccurrenceOrderPlugin(), // extract css into its own file - new ExtractTextPlugin(path.join(config.build.assetsSubDirectory, '[name].[contenthash].css')), + new ExtractTextPlugin(utils.assetsPath('css/[name].[contenthash].css')), // generate dist index.html with correct asset hash for caching. // you can customize output by editing /index.html // see https://github.com/ampedandwired/html-webpack-plugin new HtmlWebpackPlugin({ - filename: process.env.NODE_ENV === 'testing' - ? 'index.html' - : config.build.index, + filename: config.build.index, template: 'index.html', inject: true, minify: { @@ -50,7 +50,49 @@ module.exports = merge(baseWebpackConfig, { removeAttributeQuotes: true // more options: // https://github.com/kangax/html-minifier#options-quick-reference + }, + // necessary to consistently work with multiple chunks via CommonsChunkPlugin + chunksSortMode: 'dependency' + }), + // split vendor js into its own file + new webpack.optimize.CommonsChunkPlugin({ + name: 'vendor', + minChunks: function (module, count) { + // any required modules inside node_modules are extracted to vendor + return ( + module.resource && + /\.js$/.test(module.resource) && + module.resource.indexOf( + path.join(__dirname, '../node_modules') + ) === 0 + ) } + }), + // extract webpack runtime and module manifest to its own file in order to + // prevent vendor hash from being updated whenever app bundle is updated + new webpack.optimize.CommonsChunkPlugin({ + name: 'manifest', + chunks: ['vendor'] }) ] }) + +if (config.build.productionGzip) { + var CompressionWebpackPlugin = require('compression-webpack-plugin') + + webpackConfig.plugins.push( + new CompressionWebpackPlugin({ + asset: '[path].gz[query]', + algorithm: 'gzip', + test: new RegExp( + '\\.(' + + config.build.productionGzipExtensions.join('|') + + ')$' + ), + threshold: 10240, + minRatio: 0.8 + }) + ) +} + +module.exports = webpackConfig diff --git a/config.js b/config.js deleted file mode 100644 index a83f2152..00000000 --- a/config.js +++ /dev/null @@ -1,16 +0,0 @@ -// see http://vuejs-templates.github.io/webpack for documentation. -var path = require('path') - -module.exports = { - build: { - index: path.resolve(__dirname, 'dist/index.html'), - assetsRoot: path.resolve(__dirname, 'dist'), - assetsSubDirectory: 'static', - assetsPublicPath: '/', - productionSourceMap: true - }, - dev: { - port: 8080, - proxyTable: {} - } -} diff --git a/config/dev.env.js b/config/dev.env.js new file mode 100644 index 00000000..efead7c8 --- /dev/null +++ b/config/dev.env.js @@ -0,0 +1,6 @@ +var merge = require('webpack-merge') +var prodEnv = require('./prod.env') + +module.exports = merge(prodEnv, { + NODE_ENV: '"development"' +}) diff --git a/config/index.js b/config/index.js new file mode 100644 index 00000000..207dfbd4 --- /dev/null +++ b/config/index.js @@ -0,0 +1,32 @@ +// see http://vuejs-templates.github.io/webpack for documentation. +var path = require('path') + +module.exports = { + build: { + env: require('./prod.env'), + index: path.resolve(__dirname, '../dist/index.html'), + assetsRoot: path.resolve(__dirname, '../dist'), + assetsSubDirectory: 'static', + assetsPublicPath: '/', + productionSourceMap: true, + // Gzip off by default as many popular static hosts such as + // Surge or Netlify already gzip all static assets for you. + // Before setting to `true`, make sure to: + // npm install --save-dev compression-webpack-plugin + productionGzip: false, + productionGzipExtensions: ['js', 'css'] + }, + dev: { + env: require('./dev.env'), + port: 8080, + assetsSubDirectory: 'static', + assetsPublicPath: '/', + proxyTable: {}, + // CSS Sourcemaps off by default because relative paths are "buggy" + // with this option, according to the CSS-Loader README + // (https://github.com/webpack/css-loader#sourcemaps) + // In our experience, they generally work as expected, + // just be aware of this issue when enabling this option. + cssSourceMap: false + } +} diff --git a/config/prod.env.js b/config/prod.env.js new file mode 100644 index 00000000..773d263d --- /dev/null +++ b/config/prod.env.js @@ -0,0 +1,3 @@ +module.exports = { + NODE_ENV: '"production"' +} diff --git a/index.html b/index.html index 17dfd4e1..863e2ffd 100644 --- a/index.html +++ b/index.html @@ -1,17 +1,15 @@ - - - 计划 - - -
- -
- - + + + vue-tutorial + + + +
+ + + + diff --git a/package.json b/package.json index 5621fa63..146fb059 100644 --- a/package.json +++ b/package.json @@ -1,81 +1,54 @@ { - "name": "test", - "version": "0.1.0", + "name": "vue-tutorial", + "version": "1.0.0", "description": "A Vue.js project", "author": "kodo <524580860@qq.com>", "private": true, "scripts": { "dev": "node build/dev-server.js", - "build": "node build/build.js", - "unit": "karma start test/unit/karma.conf.js --single-run", - "e2e": "node test/e2e/runner.js", - "test": "npm run unit && npm run e2e" + "build": "node build/build.js" }, "dependencies": { - "babel-runtime": "^5.8.0", - "vue": "^1.0.18", - "vue-resource": "^0.7.0", - "vue-router": "^0.7.13" + "bootstrap": "^3.3.7", + "vue": "^2.1.0", + "vue-resource": "^1.0.3", + "vue-router": "^2.0.3", + "vuex": "^2.0.0" }, "devDependencies": { + "autoprefixer": "^6.4.0", "babel-core": "^6.0.0", "babel-loader": "^6.0.0", "babel-plugin-transform-runtime": "^6.0.0", "babel-preset-es2015": "^6.0.0", "babel-preset-stage-2": "^6.0.0", - "body-parser": "^1.15.1", - "bootstrap": "^3.3.6", - "chai": "^3.5.0", - "chromedriver": "^2.21.2", + "babel-register": "^6.0.0", + "chalk": "^1.1.3", "connect-history-api-fallback": "^1.1.0", - "cross-spawn": "^2.1.5", - "css-loader": "^0.23.0", - "eslint": "^2.0.0", - "eslint-config-standard": "^5.1.0", - "eslint-friendly-formatter": "^1.2.2", - "eslint-loader": "^1.3.0", - "eslint-plugin-html": "^1.3.0", - "eslint-plugin-promise": "^1.0.8", - "eslint-plugin-standard": "^1.3.2", + "css-loader": "^0.25.0", "eventsource-polyfill": "^0.9.6", - "express": "^4.13.4", + "express": "^4.13.3", "extract-text-webpack-plugin": "^1.0.1", - "file-loader": "^0.8.4", + "file-loader": "^0.9.0", "function-bind": "^1.0.2", "html-webpack-plugin": "^2.8.1", - "http-proxy-middleware": "^0.12.0", - "inject-loader": "^2.0.1", - "isparta-loader": "^2.0.0", - "jquery": "^2.2.3", + "http-proxy-middleware": "^0.17.2", "json-loader": "^0.5.4", - "karma": "^0.13.15", - "karma-coverage": "^0.5.5", - "karma-mocha": "^0.2.2", - "karma-phantomjs-launcher": "^1.0.0", - "karma-sinon-chai": "^1.2.0", - "karma-sourcemap-loader": "^0.3.7", - "karma-spec-reporter": "0.0.24", - "karma-webpack": "^1.7.0", - "lolex": "^1.4.0", - "mocha": "^2.4.5", - "mongodb": "^2.1.19", - "morgan": "^1.7.0", - "nightwatch": "^0.8.18", - "ora": "^0.2.0", - "phantomjs-prebuilt": "^2.1.3", - "selenium-server": "2.53.0", - "shelljs": "^0.6.0", - "sinon": "^1.17.3", - "sinon-chai": "^2.8.0", - "style-loader": "^0.13.1", + "semver": "^5.3.0", + "opn": "^4.0.2", + "ora": "^0.3.0", + "shelljs": "^0.7.4", "url-loader": "^0.5.7", - "vue-hot-reload-api": "^1.2.0", - "vue-html-loader": "^1.0.0", - "vue-loader": "^8.2.1", + "vue-loader": "^10.0.0", "vue-style-loader": "^1.0.0", - "webpack": "^1.12.2", - "webpack-dev-middleware": "^1.4.0", - "webpack-hot-middleware": "^2.6.0", - "webpack-merge": "^0.8.3" + "vue-template-compiler": "^2.1.0", + "webpack": "^1.13.2", + "webpack-dev-middleware": "^1.8.3", + "webpack-hot-middleware": "^2.12.2", + "webpack-merge": "^0.14.1" + }, + "engines": { + "node": ">= 4.0.0", + "npm": ">= 3.0.0" } } diff --git a/src/App.vue b/src/App.vue index eb0fb34b..4a480bfa 100644 --- a/src/App.vue +++ b/src/App.vue @@ -7,14 +7,14 @@ 计划板
- +
@@ -22,36 +22,14 @@
- - diff --git a/src/components/404.vue b/src/components/404.vue new file mode 100644 index 00000000..7ec7bdc4 --- /dev/null +++ b/src/components/404.vue @@ -0,0 +1,19 @@ + + + diff --git a/src/components/Hello.vue b/src/components/Hello.vue new file mode 100644 index 00000000..2d805395 --- /dev/null +++ b/src/components/Hello.vue @@ -0,0 +1,53 @@ + + + + + + diff --git a/src/components/Home.vue b/src/components/Home.vue index d0a1b3e2..6945a2c3 100644 --- a/src/components/Home.vue +++ b/src/components/Home.vue @@ -3,19 +3,24 @@

任务追踪

- 创建一个任务. + 创建一个任务

+ - - diff --git a/src/components/LogTime.vue b/src/components/LogTime.vue index 16a14cff..bb872c5e 100644 --- a/src/components/LogTime.vue +++ b/src/components/LogTime.vue @@ -6,17 +6,17 @@
- +
@@ -26,13 +26,13 @@ - + 取消
@@ -41,33 +41,28 @@ diff --git a/src/components/Sidebar.vue b/src/components/Sidebar.vue index 8ef36da4..b2b414d2 100644 --- a/src/components/Sidebar.vue +++ b/src/components/Sidebar.vue @@ -10,9 +10,13 @@ - diff --git a/src/components/TimeEntries.vue b/src/components/TimeEntries.vue index c89b9f8a..5bfff654 100644 --- a/src/components/TimeEntries.vue +++ b/src/components/TimeEntries.vue @@ -1,11 +1,11 @@ + - diff --git a/src/main.js b/src/main.js index 95b728ca..bbc73129 100644 --- a/src/main.js +++ b/src/main.js @@ -1,33 +1,60 @@ import Vue from 'vue' -import App from './App.vue' -import Home from './components/Home.vue' +import VueRouter from 'vue-router' +import store from './store' +import App from './App' +import Home from './components/Home' import TimeEntries from './components/TimeEntries.vue' import LogTime from './components/LogTime.vue' -import VueRouter from 'vue-router' +import NotFound from './components/404' import VueResource from 'vue-resource' import 'bootstrap/dist/css/bootstrap.css' -Vue.use(VueResource) Vue.use(VueRouter) +Vue.use(VueResource) + +const routes = [{ + path : '/', + component : Home +},{ + path : '/home', + component : Home +},{ + path : '/time-entries', + component : TimeEntries, + children : [{ + path : 'log-time', + component : LogTime, + }] +},{ + path : '*', + component : NotFound +}]; -const router = new VueRouter() +const router = new VueRouter({ + routes +}); -router.map({ - '/Home': { - component: Home - }, - '/time-entries': { - component: TimeEntries, - subRoutes: { - '/log-time': { - component: LogTime - } - } - } -}) +/* eslint-disable no-new */ +// 这灵活得亮瞎了 +/*new Vue({ + el: '#app', + template: '', + router, + components: { App } +}); -router.redirect({ - '*': '/Home' -}) + new Vue(Vue.util.extend({ + router + }, App)).$mount('#app'); -router.start(App, '#app') +new Vue({ + el:'#app', + router, + render:h => h(App) +});*/ +var app = new Vue({ + el: '#app', + router, + store, + ...App, +}); diff --git a/src/store/actions.js b/src/store/actions.js new file mode 100644 index 00000000..36811d63 --- /dev/null +++ b/src/store/actions.js @@ -0,0 +1,16 @@ +import * as types from './mutation-types' + +export default { + addTotalTime({ commit }, time) { + commit(types.ADD_TOTAL_TIME, time) + }, + decTotalTime({ commit }, time) { + commit(types.DEC_TOTAL_TIME, time) + }, + savePlan({ commit }, plan) { + commit(types.SAVE_PLAN, plan); + }, + deletePlan({ commit }, plan) { + commit(types.DELETE_PLAN, plan) + } +}; diff --git a/src/store/index.js b/src/store/index.js new file mode 100644 index 00000000..37c745c2 --- /dev/null +++ b/src/store/index.js @@ -0,0 +1,18 @@ +import Vue from 'vue' +import Vuex from 'vuex' +import mutations from './mutations' +import actions from './actions' + +Vue.use(Vuex); + +const state = { + totalTime: 0, + list: [] +}; + +export default new Vuex.Store({ + state, + mutations, + actions +}) + diff --git a/src/store/mutation-types.js b/src/store/mutation-types.js new file mode 100644 index 00000000..32635751 --- /dev/null +++ b/src/store/mutation-types.js @@ -0,0 +1,7 @@ +// 增加总时间或者减少总时间 +export const ADD_TOTAL_TIME = 'ADD_TOTAL_TIME'; +export const DEC_TOTAL_TIME = 'DEC_TOTAL_TIME'; + +// 新增和删除一条计划 +export const SAVE_PLAN = 'SAVE_PLAN'; +export const DELETE_PLAN = 'DELETE_PLAN'; diff --git a/src/store/mutations.js b/src/store/mutations.js new file mode 100644 index 00000000..d03a9046 --- /dev/null +++ b/src/store/mutations.js @@ -0,0 +1,21 @@ +import * as types from './mutation-types' + +export default { + [types.ADD_TOTAL_TIME] (state, time) { + state.totalTime = state.totalTime + time + }, + [types.DEC_TOTAL_TIME] (state, time) { + state.totalTime = state.totalTime - time + }, + [types.SAVE_PLAN] (state, plan) { + // 设置默认值,未来我们可以做登入直接读取昵称和头像 + const avatar = 'https://sfault-avatar.b0.upaiyun.com/147/223/147223148-573297d0913c5_huge256'; + + state.list.push( + Object.assign({ name: '二哲', avatar: avatar }, plan) + ) + }, + [types.DELETE_PLAN] (state, idx) { + state.list.splice(idx, 1); + } +}; diff --git a/test/e2e/custom-assertions/elementCount.js b/test/e2e/custom-assertions/elementCount.js deleted file mode 100644 index c0d5fe00..00000000 --- a/test/e2e/custom-assertions/elementCount.js +++ /dev/null @@ -1,26 +0,0 @@ -// A custom Nightwatch assertion. -// the name of the method is the filename. -// can be used in tests like this: -// -// browser.assert.elementCount(selector, count) -// -// for how to write custom assertions see -// http://nightwatchjs.org/guide#writing-custom-assertions -exports.assertion = function (selector, count) { - this.message = 'Testing if element <' + selector + '> has count: ' + count - this.expected = count - this.pass = function (val) { - return val === this.expected - } - this.value = function (res) { - return res.value - } - this.command = function (cb) { - var self = this - return this.api.execute(function (selector) { - return document.querySelectorAll(selector).length - }, [selector], function (res) { - cb.call(self, res) - }) - } -} diff --git a/test/e2e/nightwatch.conf.js b/test/e2e/nightwatch.conf.js deleted file mode 100644 index b5d911ce..00000000 --- a/test/e2e/nightwatch.conf.js +++ /dev/null @@ -1,40 +0,0 @@ -// http://nightwatchjs.org/guide#settings-file -module.exports = { - "src_folders": ["test/e2e/specs"], - "output_folder": "test/e2e/reports", - "custom_assertions_path": ["test/e2e/custom-assertions"], - - "selenium": { - "start_process": true, - "server_path": "node_modules/selenium-server/lib/runner/selenium-server-standalone-2.53.0.jar", - "host": "127.0.0.1", - "port": 4444, - "cli_args": { - "webdriver.chrome.driver": require('chromedriver').path - } - }, - - "test_settings": { - "default": { - "selenium_port": 4444, - "selenium_host": "localhost", - "silent": true - }, - - "chrome": { - "desiredCapabilities": { - "browserName": "chrome", - "javascriptEnabled": true, - "acceptSslCerts": true - } - }, - - "firefox": { - "desiredCapabilities": { - "browserName": "firefox", - "javascriptEnabled": true, - "acceptSslCerts": true - } - } - } -} diff --git a/test/e2e/runner.js b/test/e2e/runner.js deleted file mode 100644 index b9f009c5..00000000 --- a/test/e2e/runner.js +++ /dev/null @@ -1,31 +0,0 @@ -// 1. start the dev server using production config -process.env.NODE_ENV = 'testing' -var server = require('../../build/dev-server.js') - -// 2. run the nightwatch test suite against it -// to run in additional browsers: -// 1. add an entry in test/e2e/nightwatch.conf.json under "test_settings" -// 2. add it to the --env flag below -// For more information on Nightwatch's config file, see -// http://nightwatchjs.org/guide#settings-file -var spawn = require('cross-spawn') -var runner = spawn( - './node_modules/.bin/nightwatch', - [ - '--config', 'test/e2e/nightwatch.conf.js', - '--env', 'chrome,firefox' - ], - { - stdio: 'inherit' - } -) - -runner.on('exit', function (code) { - server.close() - process.exit(code) -}) - -runner.on('error', function (err) { - server.close() - throw err -}) diff --git a/test/e2e/specs/test.js b/test/e2e/specs/test.js deleted file mode 100644 index 49bc7f70..00000000 --- a/test/e2e/specs/test.js +++ /dev/null @@ -1,14 +0,0 @@ -// For authoring Nightwatch tests, see -// http://nightwatchjs.org/guide#usage - -module.exports = { - 'default e2e tests': function (browser) { - browser - .url('http://localhost:8080') - .waitForElementVisible('#app', 5000) - .assert.elementPresent('.logo') - .assert.containsText('h1', 'Hello World!') - .assert.elementCount('p', 3) - .end() - } -} diff --git a/test/unit/.eslintrc b/test/unit/.eslintrc deleted file mode 100644 index 959a4f4b..00000000 --- a/test/unit/.eslintrc +++ /dev/null @@ -1,9 +0,0 @@ -{ - "env": { - "mocha": true - }, - "globals": { - "expect": true, - "sinon": true - } -} diff --git a/test/unit/index.js b/test/unit/index.js deleted file mode 100644 index 42202514..00000000 --- a/test/unit/index.js +++ /dev/null @@ -1,13 +0,0 @@ -// Polyfill fn.bind() for PhantomJS -/* eslint-disable no-extend-native */ -Function.prototype.bind = require('function-bind') - -// require all test files (files that ends with .spec.js) -var testsContext = require.context('./specs', true, /\.spec$/) -testsContext.keys().forEach(testsContext) - -// require all src files except main.js for coverage. -// you can also change this to match only the subset of files that -// you want coverage for. -var srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/) -srcContext.keys().forEach(srcContext) diff --git a/test/unit/karma.conf.js b/test/unit/karma.conf.js deleted file mode 100644 index b3348719..00000000 --- a/test/unit/karma.conf.js +++ /dev/null @@ -1,66 +0,0 @@ -// This is a karma config file. For more details see -// http://karma-runner.github.io/0.13/config/configuration-file.html -// we are also using it with karma-webpack -// https://github.com/webpack/karma-webpack - -var path = require('path') -var merge = require('webpack-merge') -var baseConfig = require('../../build/webpack.base.conf') -var projectRoot = path.resolve(__dirname, '../../') - -var webpackConfig = merge(baseConfig, { - // use inline sourcemap for karma-sourcemap-loader - devtool: '#inline-source-map', - vue: { - loaders: { - js: 'isparta' - } - } -}) - -// no need for app entry during tests -delete webpackConfig.entry - -// make sure isparta loader is applied before eslint -webpackConfig.module.preLoaders = webpackConfig.module.preLoaders || [] -webpackConfig.module.preLoaders.unshift({ - test: /\.js$/, - loader: 'isparta', - include: projectRoot, - exclude: /test\/unit|node_modules/ -}) - -// only apply babel for test files when using isparta -webpackConfig.module.loaders.some(function (loader, i) { - if (loader.loader === 'babel') { - loader.include = /test\/unit/ - return true - } -}) - -module.exports = function (config) { - config.set({ - // to run in additional browsers: - // 1. install corresponding karma launcher - // http://karma-runner.github.io/0.13/config/browsers.html - // 2. add it to the `browsers` array below. - browsers: ['PhantomJS'], - frameworks: ['mocha', 'sinon-chai'], - reporters: ['spec', 'coverage'], - files: ['./index.js'], - preprocessors: { - './index.js': ['webpack', 'sourcemap'] - }, - webpack: webpackConfig, - webpackMiddleware: { - noInfo: true - }, - coverageReporter: { - dir: './coverage', - reporters: [ - { type: 'lcov', subdir: '.' }, - { type: 'text-summary' } - ] - } - }) -} diff --git a/test/unit/specs/Hello.spec.js b/test/unit/specs/Hello.spec.js deleted file mode 100644 index 835ad99f..00000000 --- a/test/unit/specs/Hello.spec.js +++ /dev/null @@ -1,12 +0,0 @@ -import Vue from 'vue' -import Hello from 'src/components/Hello' - -describe('Hello.vue', () => { - it('should render correct contents', () => { - const vm = new Vue({ - template: '
', - components: { Hello } - }).$mount() - expect(vm.$el.querySelector('.hello h1').textContent).to.contain('Hello World!') - }) -})