├── static └── .gitkeep ├── .travis.yml ├── src ├── vuex │ ├── mutation-types.js │ ├── actions.js │ └── store.js ├── assets │ └── logo.png ├── main.js ├── App.vue ├── router │ └── index.js └── components │ ├── About.vue │ ├── Hello.vue │ └── Index.vue ├── test ├── unit │ ├── .eslintrc │ ├── specs │ │ └── Hello.spec.js │ ├── index.js │ └── karma.conf.js └── e2e │ ├── specs │ └── test.js │ ├── runner.js │ ├── custom-assertions │ └── elementCount.js │ └── nightwatch.conf.js ├── .babelrc ├── .gitignore ├── .editorconfig ├── index.html ├── .eslintrc.js ├── README.md └── package.json /static/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "4.2" 4 | -------------------------------------------------------------------------------- /src/vuex/mutation-types.js: -------------------------------------------------------------------------------- 1 | export const INCREMENT = 'INCREMENT' 2 | -------------------------------------------------------------------------------- /test/unit/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "jasmine": true 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/funkyLover/vue-boilerplate/HEAD/src/assets/logo.png -------------------------------------------------------------------------------- /.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": ["es2015", "stage-2"], 3 | "plugins": ["transform-runtime"], 4 | "comments": false 5 | } 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log 5 | selenium-debug.log 6 | test/unit/coverage 7 | test/e2e/reports 8 | -------------------------------------------------------------------------------- /src/vuex/actions.js: -------------------------------------------------------------------------------- 1 | import * as types from './mutation-types' 2 | 3 | export const increment = ({ dispatch }, x) => { 4 | dispatch(types.INCREMENT, x) 5 | } 6 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | vue-boilerplate 6 | 7 | 8 |
9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App' 3 | import { sync } from 'vuex-router-sync' 4 | import store from './vuex/store' 5 | import router from './router/index' 6 | 7 | // for debugging 8 | Vue.config.debug = true 9 | 10 | sync(store, router) 11 | 12 | router.start(App, '#app') 13 | -------------------------------------------------------------------------------- /src/vuex/store.js: -------------------------------------------------------------------------------- 1 | import Vuex from 'vuex' 2 | import Vue from 'vue' 3 | import { INCREMENT } from './mutation-types' 4 | 5 | Vue.use(Vuex) 6 | 7 | export default new Vuex.Store({ 8 | state: { 9 | count: 1 10 | }, 11 | mutations: { 12 | [INCREMENT] (state, x) { 13 | state.count += x 14 | } 15 | } 16 | }) 17 | -------------------------------------------------------------------------------- /test/e2e/specs/test.js: -------------------------------------------------------------------------------- 1 | // For authoring Nightwatch tests, see 2 | // http://nightwatchjs.org/guide#usage 3 | 4 | module.exports = { 5 | 'default e2e tests': function (browser) { 6 | browser 7 | .url('http://localhost:8080') 8 | .waitForElementVisible('#app', 5000) 9 | .assert.elementPresent('.logo') 10 | .assert.containsText('h1', 'Hello World!') 11 | .assert.elementCount('p', 3) 12 | .end() 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /src/App.vue: -------------------------------------------------------------------------------- 1 | 12 | 13 | 19 | 20 | 21 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style 4 | extends: 'standard', 5 | // required to lint *.vue files 6 | plugins: [ 7 | 'html' 8 | ], 9 | // add your custom rules here 10 | 'rules': { 11 | // allow paren-less arrow functions 12 | 'arrow-parens': 0, 13 | // allow debugger during development 14 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /src/router/index.js: -------------------------------------------------------------------------------- 1 | import VueRouter from 'vue-router' 2 | import Vue from 'vue' 3 | import Index from '../components/Index' 4 | import About from '../components/About' 5 | import Hello from '../components/Hello' 6 | 7 | Vue.use(VueRouter) 8 | 9 | var router = new VueRouter() 10 | 11 | router.map({ 12 | '/index': { 13 | component: Index 14 | }, 15 | '/about': { 16 | component: About 17 | }, 18 | '/hello': { 19 | component: Hello 20 | } 21 | }) 22 | 23 | export default router 24 | -------------------------------------------------------------------------------- /test/unit/specs/Hello.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import Hello from 'src/components/Hello' 3 | 4 | describe('Hello.vue', () => { 5 | it('should render correct contents', () => { 6 | const vm = new Vue({ 7 | template: '
', 8 | components: { Hello } 9 | }).$mount() 10 | expect(vm.$el.querySelector('.hello h1').textContent).toBe('Hello World!') 11 | }) 12 | }) 13 | 14 | // also see example testing a component with mocks at 15 | // https://github.com/vuejs/vue-loader-example/blob/master/test/unit/a.spec.js#L24-L49 16 | -------------------------------------------------------------------------------- /test/unit/index.js: -------------------------------------------------------------------------------- 1 | // Polyfill fn.bind() for PhantomJS 2 | /* eslint-disable no-extend-native */ 3 | Function.prototype.bind = require('function-bind') 4 | 5 | // require all test files (files that ends with .spec.js) 6 | var testsContext = require.context('./specs', true, /\.spec$/) 7 | testsContext.keys().forEach(testsContext) 8 | 9 | // require all src files except main.js for coverage. 10 | // you can also change this to match only the subset of files that 11 | // you want coverage for. 12 | var srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/) 13 | srcContext.keys().forEach(srcContext) 14 | -------------------------------------------------------------------------------- /src/components/About.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 33 | -------------------------------------------------------------------------------- /src/components/Hello.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 33 | -------------------------------------------------------------------------------- /src/components/Index.vue: -------------------------------------------------------------------------------- 1 | 6 | 7 | 33 | -------------------------------------------------------------------------------- /test/e2e/runner.js: -------------------------------------------------------------------------------- 1 | // 1. start the dev server 2 | var server = require('../../build/dev-server.js') 3 | 4 | // 2. run the nightwatch test suite against it 5 | // to run in additional browsers: 6 | // 1. add an entry in test/e2e/nightwatch.conf.json under "test_settings" 7 | // 2. add it to the --env flag below 8 | // For more information on Nightwatch's config file, see 9 | // http://nightwatchjs.org/guide#settings-file 10 | var spawn = require('cross-spawn') 11 | var runner = spawn( 12 | './node_modules/.bin/nightwatch', 13 | [ 14 | '--config', 'test/e2e/nightwatch.conf.js', 15 | '--env', 'chrome,firefox' 16 | ], 17 | { 18 | stdio: 'inherit' 19 | } 20 | ) 21 | 22 | runner.on('exit', function (code) { 23 | server.close() 24 | process.exit(code) 25 | }) 26 | 27 | runner.on('error', function (err) { 28 | server.close() 29 | throw err 30 | }) 31 | -------------------------------------------------------------------------------- /test/e2e/custom-assertions/elementCount.js: -------------------------------------------------------------------------------- 1 | // A custom Nightwatch assertion. 2 | // the name of the method is the filename. 3 | // can be used in tests like this: 4 | // 5 | // browser.assert.elementCount(selector, count) 6 | // 7 | // for how to write custom assertions see 8 | // http://nightwatchjs.org/guide#writing-custom-assertions 9 | exports.assertion = function (selector, count) { 10 | this.message = 'Testing if element <' + selector + '> has count: ' + count 11 | this.expected = count 12 | this.pass = function (val) { 13 | return val === this.expected 14 | } 15 | this.value = function (res) { 16 | return res.value 17 | } 18 | this.command = function (cb) { 19 | var self = this 20 | return this.api.execute(function (selector) { 21 | return document.querySelectorAll(selector).length 22 | }, [selector], function (res) { 23 | cb.call(self, res) 24 | }) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | > # outdated! please check [vue-spa](https://github.com/funkyLover/vue-spa) instead 2 | 3 | # vue-boilerplate 4 | 5 | > A boilerplate for building spa with vue, vuex, vue-router 6 | 7 | ## detail 8 | 9 | firstly, get `vue-webpack-boilerplate` by [vue-cli](https://github.com/vuejs/vue-cli). and then add the dependencies(`vuex`, `vue-router`, `vuex-router-sync`) for building spa. 10 | 11 | ## Build Setup 12 | 13 | ``` bash 14 | # install dependencies 15 | npm install 16 | 17 | # serve with hot reload at localhost:8080 18 | npm run dev 19 | 20 | # build for production with minification 21 | npm run build 22 | 23 | # run unit tests 24 | npm run unit 25 | 26 | # run e2e tests 27 | npm run e2e 28 | 29 | # run all tests 30 | npm test 31 | ``` 32 | 33 | For detailed explanation on how things work, checkout the [guide](https://github.com/vuejs-templates/webpack#vue-webpack-boilerplate) and [docs for vue-loader](http://vuejs.github.io/vue-loader). 34 | -------------------------------------------------------------------------------- /test/e2e/nightwatch.conf.js: -------------------------------------------------------------------------------- 1 | // http://nightwatchjs.org/guide#settings-file 2 | module.exports = { 3 | "src_folders": ["test/e2e/specs"], 4 | "output_folder": "test/e2e/reports", 5 | "custom_assertions_path": ["test/e2e/custom-assertions"], 6 | 7 | "selenium": { 8 | "start_process": true, 9 | "server_path": "node_modules/selenium-server/lib/runner/selenium-server-standalone-2.52.0.jar", 10 | "host": "127.0.0.1", 11 | "port": 4444, 12 | "cli_args": { 13 | "webdriver.chrome.driver": require('chromedriver').path 14 | } 15 | }, 16 | 17 | "test_settings": { 18 | "default": { 19 | "selenium_port": 4444, 20 | "selenium_host": "localhost", 21 | "silent": true 22 | }, 23 | 24 | "chrome": { 25 | "desiredCapabilities": { 26 | "browserName": "chrome", 27 | "javascriptEnabled": true, 28 | "acceptSslCerts": true 29 | } 30 | }, 31 | 32 | "firefox": { 33 | "desiredCapabilities": { 34 | "browserName": "firefox", 35 | "javascriptEnabled": true, 36 | "acceptSslCerts": true 37 | } 38 | } 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /test/unit/karma.conf.js: -------------------------------------------------------------------------------- 1 | // This is a karma config file. For more details see 2 | // http://karma-runner.github.io/0.13/config/configuration-file.html 3 | // we are also using it with karma-webpack 4 | // https://github.com/webpack/karma-webpack 5 | 6 | var path = require('path') 7 | var merge = require('webpack-merge') 8 | var baseConfig = require('../../build/webpack.base.conf') 9 | var projectRoot = path.resolve(__dirname, '../../') 10 | 11 | var webpackConfig = merge(baseConfig, { 12 | // use inline sourcemap for karma-sourcemap-loader 13 | devtool: '#inline-source-map', 14 | vue: { 15 | loaders: { 16 | js: 'isparta' 17 | } 18 | } 19 | }) 20 | 21 | // no need for app entry during tests 22 | delete webpackConfig.entry 23 | 24 | // make sure isparta loader is applied before eslint 25 | webpackConfig.module.preLoaders.unshift({ 26 | test: /\.js$/, 27 | loader: 'isparta', 28 | include: projectRoot, 29 | exclude: /test\/unit|node_modules/ 30 | }) 31 | 32 | // only apply babel for test files when using isparta 33 | webpackConfig.module.loaders.some(function (loader, i) { 34 | if (loader.loader === 'babel') { 35 | loader.include = /test\/unit/ 36 | return true 37 | } 38 | }) 39 | 40 | module.exports = function (config) { 41 | config.set({ 42 | // to run in additional browsers: 43 | // 1. install corresponding karma launcher 44 | // http://karma-runner.github.io/0.13/config/browsers.html 45 | // 2. add it to the `browsers` array below. 46 | browsers: ['PhantomJS'], 47 | frameworks: ['jasmine'], 48 | reporters: ['spec', 'coverage'], 49 | files: ['./index.js'], 50 | preprocessors: { 51 | './index.js': ['webpack', 'sourcemap'] 52 | }, 53 | webpack: webpackConfig, 54 | webpackMiddleware: { 55 | noInfo: true 56 | }, 57 | coverageReporter: { 58 | dir: './coverage', 59 | reporters: [ 60 | { type: 'lcov', subdir: '.' }, 61 | { type: 'text-summary' } 62 | ] 63 | } 64 | }) 65 | } 66 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-boilerplate", 3 | "version": "0.1.0", 4 | "description": "A boilerplate for building spa with vue, vuex, vue-router", 5 | "author": "funkyLover ", 6 | "scripts": { 7 | "dev": "node build/dev-server.js", 8 | "build": "rimraf dist && mkdirp dist && ncp static dist/static && cross-env NODE_ENV=production webpack --progress --hide-modules --config build/webpack.prod.conf.js", 9 | "unit": "karma start test/unit/karma.conf.js --single-run", 10 | "e2e": "node test/e2e/runner.js", 11 | "test": "npm run unit && npm run e2e" 12 | }, 13 | "dependencies": { 14 | "vue": "^1.0.17", 15 | "vue-router": "^0.7.11", 16 | "vuex": "^0.6.2", 17 | "vuex-router-sync": "^1.0.0" 18 | }, 19 | "devDependencies": { 20 | "babel-core": "^6.0.0", 21 | "babel-loader": "^6.0.0", 22 | "babel-plugin-transform-runtime": "^6.0.0", 23 | "babel-preset-es2015": "^6.0.0", 24 | "babel-preset-stage-2": "^6.0.0", 25 | "babel-runtime": "^5.8.0", 26 | "chromedriver": "^2.21.2", 27 | "connect-history-api-fallback": "^1.1.0", 28 | "cross-env": "^1.0.7", 29 | "cross-spawn": "^2.1.5", 30 | "css-loader": "^0.23.1", 31 | "eslint": "^2.0.0", 32 | "eslint-config-standard": "^5.1.0", 33 | "eslint-friendly-formatter": "^1.2.2", 34 | "eslint-loader": "^1.3.0", 35 | "eslint-plugin-html": "^1.3.0", 36 | "eslint-plugin-promise": "^1.0.8", 37 | "eslint-plugin-standard": "^1.3.2", 38 | "eventsource-polyfill": "^0.9.6", 39 | "express": "^4.13.3", 40 | "extract-text-webpack-plugin": "^1.0.1", 41 | "file-loader": "^0.8.4", 42 | "function-bind": "^1.0.2", 43 | "html-webpack-plugin": "^2.8.1", 44 | "http-proxy-middleware": "^0.11.0", 45 | "inject-loader": "^2.0.1", 46 | "isparta-loader": "^2.0.0", 47 | "jasmine-core": "^2.4.1", 48 | "json-loader": "^0.5.4", 49 | "karma": "^0.13.15", 50 | "karma-coverage": "^0.5.5", 51 | "karma-jasmine": "^0.3.6", 52 | "karma-phantomjs-launcher": "^1.0.0", 53 | "karma-sourcemap-loader": "^0.3.7", 54 | "karma-spec-reporter": "0.0.24", 55 | "karma-webpack": "^1.7.0", 56 | "less": "^2.6.1", 57 | "less-loader": "^2.2.2", 58 | "mkdirp": "^0.5.1", 59 | "ncp": "^2.0.0", 60 | "nightwatch": "^0.8.18", 61 | "node-sass": "^3.4.2", 62 | "phantomjs-prebuilt": "^2.1.3", 63 | "rimraf": "^2.5.0", 64 | "sass-loader": "^3.2.0", 65 | "selenium-server": "2.52.0", 66 | "style-loader": "^0.13.1", 67 | "stylus-loader": "^1.5.1", 68 | "url-loader": "^0.5.7", 69 | "vue-hot-reload-api": "^1.2.0", 70 | "vue-html-loader": "^1.0.0", 71 | "vue-loader": "^8.1.3", 72 | "vue-style-loader": "^1.0.0", 73 | "webpack": "^1.12.2", 74 | "webpack-dev-middleware": "^1.4.0", 75 | "webpack-hot-middleware": "^2.6.0", 76 | "webpack-merge": "^0.8.3" 77 | } 78 | } 79 | --------------------------------------------------------------------------------