├── template ├── static │ └── .gitkeep ├── src │ ├── js │ │ ├── utils │ │ │ └── .gitkeep │ │ ├── views │ │ │ └── .gitkeep │ │ ├── router │ │ │ └── index.js │ │ ├── App.vue │ │ ├── main.js │ │ └── components │ │ │ └── Hello.vue │ ├── assets │ │ └── logo.png │ └── scss │ │ └── style.scss ├── .eslintignore ├── test │ └── unit │ │ ├── .eslintrc │ │ ├── specs │ │ └── Hello.spec.js │ │ ├── index.js │ │ └── karma.conf.js ├── .editorconfig ├── .gitignore ├── config │ ├── config.app.js │ ├── config.base.js │ ├── index.js │ ├── config.production.js │ └── config.development.js ├── webpack.config.js ├── .babelrc ├── index.html ├── README.md ├── build │ ├── webpack.development.js │ ├── webpack.testing.js │ ├── webpack.base.js │ └── webpack.production.js ├── .eslintrc.js └── package.json ├── .gitignore ├── circle.yml ├── test.sh ├── deploy-docs.sh ├── docs ├── SUMMARY.md ├── linter.md ├── README.md ├── prerender.md ├── commands.md ├── unit.md ├── pre-processors.md ├── backend.md ├── static.md └── structure.md ├── package.json ├── LICENSE ├── meta.js └── README.md /template/static/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /template/src/js/utils/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /template/src/js/views/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /template/.eslintignore: -------------------------------------------------------------------------------- 1 | build/*.js 2 | config/*.js 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | .DS_Store 3 | docs/_book 4 | -------------------------------------------------------------------------------- /circle.yml: -------------------------------------------------------------------------------- 1 | machine: 2 | node: 3 | version: 6 4 | 5 | test: 6 | override: 7 | - bash test.sh 8 | -------------------------------------------------------------------------------- /template/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rohitkrai03/vue-starter/HEAD/template/src/assets/logo.png -------------------------------------------------------------------------------- /test.sh: -------------------------------------------------------------------------------- 1 | set -e 2 | 3 | yes "" | ./node_modules/.bin/vue init . test 4 | 5 | cd test 6 | npm install 7 | npm run lint 8 | npm test 9 | npm run build 10 | -------------------------------------------------------------------------------- /template/test/unit/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "mocha": true 4 | }, 5 | "globals": { 6 | "expect": true, 7 | "sinon": true 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /deploy-docs.sh: -------------------------------------------------------------------------------- 1 | cd docs 2 | rm -rf _book 3 | gitbook build 4 | cd _book 5 | git init 6 | git add -A 7 | git commit -m 'update book' 8 | git push -f git@github.com:rohitkrai03/vue-starter.git master:gh-pages 9 | -------------------------------------------------------------------------------- /template/.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 | -------------------------------------------------------------------------------- /template/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | dist/ 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | {{#unit}} 8 | test/unit/coverage 9 | {{/unit}} 10 | 11 | 12 | # Editor directories and files 13 | .idea 14 | *.suo 15 | *.ntvs* 16 | *.njsproj 17 | *.sln 18 | -------------------------------------------------------------------------------- /template/config/config.app.js: -------------------------------------------------------------------------------- 1 | const API_URL = '//app.example.com/api'; 2 | const API_VERSION = '2.0'; 3 | const BASE_URL = `${API_URL}/${API_VERSION}`; 4 | 5 | exports.getURL = url => BASE_URL + url; 6 | 7 | module.exports = { 8 | appName: 'Some App Specific Mode', 9 | otherAPI: exports.getURL('/something/') 10 | }; 11 | -------------------------------------------------------------------------------- /template/src/js/router/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Router from 'vue-router'; 3 | import Hello from '../components/Hello'; 4 | 5 | Vue.use(Router); 6 | 7 | export default new Router({ 8 | routes: [ 9 | { 10 | path: '/', 11 | name: 'Hello', 12 | component: Hello, 13 | }, 14 | ], 15 | }); 16 | -------------------------------------------------------------------------------- /docs/SUMMARY.md: -------------------------------------------------------------------------------- 1 | # Summary 2 | 3 | - [Project Structure](structure.md) 4 | - [Build Commands](commands.md) 5 | - [Linter Configuration](linter.md) 6 | - [Pre-Processors](pre-processors.md) 7 | - [Handling Static Assets](static.md) 8 | - [Integrate with Backend Framework](backend.md) 9 | - [Unit Testing](unit.md) 10 | - [Prerendering for SEO](prerender.md) 11 | -------------------------------------------------------------------------------- /template/webpack.config.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | const webpackMerge = require('webpack-merge'); 3 | 4 | module.exports = () => { 5 | const env = process.env.NODE_ENV; 6 | 7 | const baseConfig = require('./build/webpack.base'); 8 | const envConfig = require(`./build/webpack.${env}`); 9 | 10 | return webpackMerge(baseConfig, envConfig); 11 | }; 12 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-starter", 3 | "version": "0.1.0", 4 | "license": "MIT", 5 | "description": "A Vue.js starter kit that lets you focus on more programming and less configruation.", 6 | "scripts": { 7 | "docs": "cd docs && gitbook serve", 8 | "docs:deploy": "bash ./deploy-docs.sh" 9 | }, 10 | "devDependencies": { 11 | "vue-cli": "^2.8.2" 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /template/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { "modules": false }] 4 | ], 5 | "plugins": [ 6 | {{#lodash}} 7 | "lodash", 8 | {{/lodash}} 9 | {{#if_eq uiLibrary "element"}} 10 | ["component", [ 11 | { 12 | "libraryName": "element-ui", 13 | "styleLibraryName": "theme-default" 14 | } 15 | ]] 16 | {{/if_eq}} 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /template/config/config.base.js: -------------------------------------------------------------------------------- 1 | const API_URL = '//app.example.com/api'; 2 | const API_VERSION = '1.0'; 3 | const BASE_URL = `${API_URL}/${API_VERSION}`; 4 | 5 | exports.getURL = url => BASE_URL + url; 6 | 7 | module.exports = { 8 | appName: 'Default App', 9 | debug: false, 10 | sessionName: 'session_id', 11 | credential: 'same-origin', 12 | exampleAPI: exports.getURL('/thing/') 13 | }; 14 | -------------------------------------------------------------------------------- /template/test/unit/specs/Hello.spec.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import Hello from '../../../src/js/components/Hello'; 3 | 4 | describe('Hello.vue', () => { 5 | it('should render correct contents', () => { 6 | const Constructor = Vue.extend(Hello); 7 | const vm = new Constructor().$mount(); 8 | expect(vm.$el.querySelector('.hello h1').textContent) 9 | .to.equal('Welcome to Your Vue.js App'); 10 | }); 11 | }); 12 | -------------------------------------------------------------------------------- /template/src/scss/style.scss: -------------------------------------------------------------------------------- 1 | #app { 2 | font-family: 'Avenir', Helvetica, Arial, sans-serif; 3 | -webkit-font-smoothing: antialiased; 4 | -moz-osx-font-smoothing: grayscale; 5 | text-align: center; 6 | color: #2c3e50; 7 | margin-top: 60px; 8 | } 9 | 10 | h1, h2 { 11 | font-weight: normal; 12 | } 13 | 14 | ul { 15 | list-style-type: none; 16 | padding: 0; 17 | } 18 | 19 | li { 20 | display: inline-block; 21 | margin: 0 10px; 22 | } 23 | 24 | a { 25 | color: #42b983; 26 | } 27 | -------------------------------------------------------------------------------- /template/test/unit/index.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | 3 | Vue.config.productionTip = false; 4 | 5 | // require all test files (files that ends with .spec.js) 6 | const 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 | const srcContext = require.context('../../src', true, /^\.\/(?!main(\.js)?$)/); 13 | srcContext.keys().forEach(srcContext); 14 | -------------------------------------------------------------------------------- /template/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {{ name }} 7 | {{#ui}} 8 | {{#if_eq uiLibrary "foundation"}} 9 | 10 | {{/if_eq}} 11 | {{/ui}} 12 | 13 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /template/config/index.js: -------------------------------------------------------------------------------- 1 | const merge = require('webpack-merge'); 2 | 3 | const DEV = 'development'; 4 | const PROD = 'production'; 5 | const env = process.env.NODE_ENV || DEV; 6 | const isDev = env === DEV; 7 | const isProd = env === PROD; 8 | 9 | const appMode = process.env.NODE_APP_MODE || 'app'; 10 | 11 | const defaults = { 12 | env, 13 | isProd, 14 | isDev, 15 | appMode, 16 | }; 17 | 18 | const baseConfig = require('./config.base'); 19 | const envConfig = require(`./config.${env}`); 20 | const appConfig = require(`./config.${appMode}`); 21 | 22 | const config = merge(defaults, baseConfig, envConfig, appConfig); 23 | 24 | module.exports = config; 25 | -------------------------------------------------------------------------------- /template/README.md: -------------------------------------------------------------------------------- 1 | # vue-starter 2 | 3 | > A Vue.js starter kit that lets you focus on more programming and less configruation. 4 | 5 | ## Build Setup 6 | 7 | ``` bash 8 | # install dependencies 9 | npm install 10 | 11 | # serve with hot reload at localhost:8080 12 | npm run dev 13 | 14 | # build for production with minification 15 | npm run build 16 | ``` 17 | # build for production and view the bundle analyzer report 18 | npm run build --report 19 | 20 | {{#unit}} 21 | 22 | # run unit tests 23 | npm run unit 24 | {{/unit}} 25 | 26 | 27 | For detailed explanation on how things work, consult the [docs for vue-loader](http://vuejs.github.io/vue-loader). 28 | ======= 29 | -------------------------------------------------------------------------------- /docs/linter.md: -------------------------------------------------------------------------------- 1 | # Linter Configuration 2 | 3 | This boilerplate uses [ESLint](http://eslint.org/) as the linter, and uses the [eslint-config-airbnb](https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb) preset with some small customizations. 4 | 5 | If you are not happy with the default linting rules, you have several options: 6 | 7 | 1. Overwrite individual rules in `.eslintrc.js`. For example, you can add the following rule to enforce semicolons instead of omitting them: 8 | 9 | ``` js 10 | // .eslintrc.js 11 | "semi": [2, "always"] 12 | ``` 13 | 14 | 2. Pick "none" for ESLint preset when generating the project and define your own rules. See [ESLint documentation](http://eslint.org/docs/rules/) for more details. 15 | -------------------------------------------------------------------------------- /template/src/js/App.vue: -------------------------------------------------------------------------------- 1 | 11 | 12 | 23 | 24 | 34 | -------------------------------------------------------------------------------- /template/src/js/main.js: -------------------------------------------------------------------------------- 1 | {{#if_eq build "standalone"}} 2 | // The Vue build version to load with the `import` command 3 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias. 4 | {{/if_eq}} 5 | import Vue from 'vue'; 6 | {{#if_eq uiLibrary "element"}} 7 | import 'element-ui/lib/theme-default/index.css'; 8 | {{/if_eq}} 9 | import App from './App'; 10 | {{#router}} 11 | import router from './router'; 12 | {{/router}} 13 | 14 | Vue.config.productionTip = false; 15 | 16 | /* eslint-disable no-new */ 17 | new Vue({ 18 | el: '#app', 19 | {{#router}} 20 | router, 21 | {{/router}} 22 | {{#if_eq build "runtime"}} 23 | render: h => h(App); 24 | {{/if_eq}} 25 | {{#if_eq build "standalone"}} 26 | template: '', 27 | components: { 28 | App, 29 | }, 30 | {{/if_eq}} 31 | }); 32 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Introduction 2 | 3 | > A Vue.js starter kit that lets you focus on more programming and less configruation. 4 | 5 | > A full-featured Webpack setup with hot-reload, lint-on-save, unit testing & css extraction. 6 | 7 | > This template is Vue 2.0 compatible. 8 | 9 | This boilerplate is targeted towards large, serious projects and assumes you are somewhat familiar with Webpack and `vue-loader`. Make sure to also read [`vue-loader`'s documentation](http://vuejs.github.io/vue-loader/index.html) for common workflow recipes. 10 | 11 | If you just want to try out `vue-loader` or whip out a quick prototype, use the [webpack-simple](https://github.com/vuejs-templates/webpack-simple) template instead. 12 | 13 | 14 | ## Quickstart 15 | 16 | To use this template, scaffold a project with [vue-cli](https://github.com/vuejs/vue-cli). **It is recommended to use npm 3+ for a more efficient dependency tree.** 17 | 18 | ``` bash 19 | $ npm install -g vue-cli 20 | $ vue init webpack my-project 21 | $ cd my-project 22 | $ npm install 23 | $ npm run dev 24 | ``` 25 | -------------------------------------------------------------------------------- /template/build/webpack.development.js: -------------------------------------------------------------------------------- 1 | const webpack = require('webpack'); 2 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 3 | const FriendlyErrorsPlugin = require('friendly-errors-webpack-plugin'); 4 | 5 | const webpackConfig = { 6 | devtool: '#cheap-module-eval-source-map', 7 | devServer: { 8 | historyApiFallback: true, 9 | noInfo: true, 10 | }, 11 | performance: { 12 | hints: false, 13 | }, 14 | module: { 15 | rules: [ 16 | { 17 | test: /\.scss$/, 18 | loaders: ['style-loader', 'css-loader', 'sass-loader'], 19 | }, 20 | { 21 | test: /\.css$/, 22 | loaders: ['style-loader', 'css-loader'], 23 | }, 24 | ], 25 | }, 26 | plugins: [ 27 | new webpack.NoEmitOnErrorsPlugin(), 28 | // https://github.com/ampedandwired/html-webpack-plugin 29 | new HtmlWebpackPlugin({ 30 | filename: 'index.html', 31 | template: 'index.html', 32 | inject: true, 33 | }), 34 | new FriendlyErrorsPlugin(), 35 | ], 36 | }; 37 | 38 | module.exports = webpackConfig; 39 | -------------------------------------------------------------------------------- /template/config/config.production.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const API_URL = '//app.production.com/api'; 3 | const API_VERSION = '2.0'; 4 | const BASE_URL = `${API_URL}/${API_VERSION}`; 5 | 6 | exports.getURL = url => BASE_URL + url; 7 | 8 | module.exports = { 9 | appName: 'Prod App', 10 | index: path.resolve(__dirname, '../dist/index.html'), 11 | assetsRoot: path.resolve(__dirname, '../dist'), 12 | assetsSubDirectory: 'assets', 13 | assetsPublicPath: '/', 14 | // Gzip off by default as many popular static hosts such as 15 | // Surge or Netlify already gzip all static assets for you. 16 | // Before setting to `true`, make sure to: 17 | // npm install --save-dev compression-webpack-plugin 18 | productionGzip: false, 19 | productionGzipExtensions: ['js', 'css'], 20 | // Run the build command with an extra argument to 21 | // View the bundle analyzer report after build finishes: 22 | // `npm run build --report` 23 | // Set to `true` or `false` to always turn it on or off 24 | bundleAnalyzerReport: process.env.npm_config_report, 25 | }; 26 | -------------------------------------------------------------------------------- /template/config/config.development.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const API_URL = '//localhost:7000/api'; 3 | const API_VERSION = '1.0'; 4 | const BASE_URL = `${API_URL}/${API_VERSION}`; 5 | 6 | exports.getURL = url => BASE_URL + url; 7 | 8 | module.exports = { 9 | appName: 'Dev App', 10 | debug: true, 11 | index: path.resolve(__dirname, '../dist/index.html'), 12 | assetsRoot: path.resolve(__dirname, '../dist'), 13 | assetsSubDirectory: 'assets', 14 | assetsPublicPath: '/', 15 | // Gzip off by default as many popular static hosts such as 16 | // Surge or Netlify already gzip all static assets for you. 17 | // Before setting to `true`, make sure to: 18 | // npm install --save-dev compression-webpack-plugin 19 | productionGzip: false, 20 | productionGzipExtensions: ['js', 'css'], 21 | // Run the build command with an extra argument to 22 | // View the bundle analyzer report after build finishes: 23 | // `npm run build --report` 24 | // Set to `true` or `false` to always turn it on or off 25 | bundleAnalyzerReport: process.env.npm_config_report, 26 | }; 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Rohit Kumar Rai 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /template/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 | const webpackConfig = require('../../build/webpack.testing.js'); 7 | 8 | module.exports = function (config) { 9 | config.set({ 10 | // to run in additional browsers: 11 | // 1. install corresponding karma launcher 12 | // http://karma-runner.github.io/0.13/config/browsers.html 13 | // 2. add it to the `browsers` array below. 14 | browsers: ['PhantomJS'], 15 | frameworks: ['mocha', 'sinon-chai', 'phantomjs-shim'], 16 | reporters: ['spec', 'coverage'], 17 | files: ['./index.js'], 18 | preprocessors: { 19 | './index.js': ['webpack', 'sourcemap'] 20 | }, 21 | webpack: webpackConfig, 22 | webpackMiddleware: { 23 | noInfo: true, 24 | }, 25 | coverageReporter: { 26 | dir: './coverage', 27 | reporters: [ 28 | { type: 'lcov', subdir: '.' }, 29 | { type: 'text-summary' }, 30 | ] 31 | }, 32 | }); 33 | }; 34 | -------------------------------------------------------------------------------- /template/build/webpack.testing.js: -------------------------------------------------------------------------------- 1 | // This is the webpack config used for unit tests. 2 | 3 | const webpack = require('webpack'); 4 | const merge = require('webpack-merge'); 5 | const baseConfig = require('./webpack.base'); 6 | 7 | const webpackConfig = merge(baseConfig, { 8 | // use inline sourcemap for karma-sourcemap-loader 9 | module: { 10 | rules: [ 11 | { 12 | test: /\.scss$/, 13 | loaders: ['style-loader', 'css-loader', 'sass-loader'], 14 | }, 15 | { 16 | test: /\.css$/, 17 | loaders: ['style-loader', 'css-loader'], 18 | }, 19 | ], 20 | }, 21 | devtool: "#inline-source-map", 22 | resolveLoader: { 23 | alias: { 24 | // necessary to to make lang="scss" work in test when using vue-loader's ?inject option 25 | // see discussion at https://github.com/vuejs/vue-loader/issues/724 26 | "scss-loader": "sass-loader" 27 | } 28 | }, 29 | plugins: [ 30 | new webpack.DefinePlugin({ 31 | "process.env.NODE_ENV": '"testing"' 32 | }) 33 | ] 34 | }); 35 | 36 | // no need for app entry during tests 37 | delete webpackConfig.entry; 38 | 39 | module.exports = webpackConfig; 40 | -------------------------------------------------------------------------------- /docs/prerender.md: -------------------------------------------------------------------------------- 1 | # Prerendering for SEO 2 | 3 | If you want to prerender routes that will not significantly change once pushed to production, use this Webpack plugin: [prerender-spa-plugin](https://www.npmjs.com/package/prerender-spa-plugin), which has been tested for use with Vue. For pages that _do_ frequently change, [Prerender.io](https://prerender.io/) and [Netlify](https://www.netlify.com/pricing) both offer plans for regularly re-prerendering your content for search engines. 4 | 5 | ## Using `prerender-spa-plugin` 6 | 7 | 1. Install it as a dev dependency: 8 | 9 | ```bash 10 | npm install --save-dev prerender-spa-plugin 11 | ``` 12 | 13 | 2. Require it in **build/webpack.production.js**: 14 | 15 | ```js 16 | // This line should go at the top of the file where other 'imports' live in 17 | var PrerenderSpaPlugin = require('prerender-spa-plugin'); 18 | ``` 19 | 20 | 3. Configure it in the `plugins` array (also in **build/webpack.production.js**): 21 | 22 | ```js 23 | new PrerenderSpaPlugin( 24 | // Path to compiled app 25 | path.join(__dirname, '../dist'), 26 | // List of endpoints you wish to prerender 27 | [ '/' ] 28 | ) 29 | ``` 30 | 31 | If you also wanted to prerender `/about` and `/contact`, then that array would be `[ '/', '/about', '/contact' ]`. 32 | 33 | 4. Enable history mode for `vue-router`: 34 | ```js 35 | const router = new VueRouter({ 36 | mode: 'history', 37 | routes: [...] 38 | }) 39 | ``` 40 | -------------------------------------------------------------------------------- /docs/commands.md: -------------------------------------------------------------------------------- 1 | # Build Commands 2 | 3 | All build commands are executed via [NPM Scripts](https://docs.npmjs.com/misc/scripts). 4 | 5 | ### `npm run dev` 6 | 7 | > Starts a Node.js local development server. 8 | 9 | - Webpack + `vue-loader` for single file Vue components. 10 | - State preserving hot-reload 11 | - State preserving compilation error overlay 12 | - Lint-on-save with ESLint 13 | - Source maps 14 | 15 | ### `npm run build` 16 | 17 | > Build assets for production. See [Integrating with Backend Framework](backend.md) for more details. 18 | 19 | - JavaScript minified with [UglifyJS](https://github.com/mishoo/UglifyJS2). 20 | - HTML minified with [html-minifier](https://github.com/kangax/html-minifier). 21 | - CSS across all components extracted into a single file and minified with [cssnano](https://github.com/ben-eb/cssnano). 22 | - All static assets compiled with version hashes for efficient long-term caching, and a production `index.html` is auto-generated with proper URLs to these generated assets. 23 | 24 | ### `npm run unit` 25 | 26 | > Run unit tests in PhantomJS with [Karma](https://karma-runner.github.io/). See [Unit Testing](unit.md) for more details. 27 | 28 | - Supports ES2015+ in test files. 29 | - Supports all webpack loaders. 30 | - Easy [mock injection](http://vuejs.github.io/vue-loader/en/workflow/testing-with-mocks.html). 31 | 32 | ### `npm run lint` 33 | 34 | > Run eslint for all the given js files in your src folder and show the result. 35 | -------------------------------------------------------------------------------- /template/.eslintrc.js: -------------------------------------------------------------------------------- 1 | // http://eslint.org/docs/user-guide/configuring 2 | 3 | module.exports = { 4 | root: true, 5 | parser: 'babel-eslint', 6 | parserOptions: { 7 | sourceType: 'module' 8 | }, 9 | env: { 10 | browser: true, 11 | }, 12 | {{#if_eq lintConfig "airbnb"}} 13 | extends: 'airbnb-base', 14 | {{/if_eq}} 15 | // required to lint *.vue files 16 | plugins: [ 17 | 'html' 18 | ], 19 | {{#if_eq lintConfig "airbnb"}} 20 | // check if imports actually resolve 21 | 'settings': { 22 | 'import/resolver': { 23 | 'webpack': { 24 | 'config': 'build/webpack.base.js' 25 | } 26 | } 27 | }, 28 | {{/if_eq}} 29 | // add your custom rules here 30 | 'rules': { 31 | {{#if_eq lintConfig "airbnb"}} 32 | // don't require .vue extension when importing 33 | 'import/extensions': ['error', 'always', { 34 | 'js': 'never', 35 | 'vue': 'never' 36 | }], 37 | // allow optionalDependencies 38 | 'import/no-extraneous-dependencies': ['error', { 39 | 'optionalDependencies': ['test/unit/index.js'] 40 | }], 41 | {{/if_eq}} 42 | // allow debugger during development 43 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0 44 | }, 45 | "globals": { 46 | "describe": true, 47 | "it": true, 48 | "expect": true, 49 | "window": true, 50 | "document": true, 51 | "__DEV__": true, 52 | "__PROD__": true, 53 | "__APP_MODE__": "" 54 | }, 55 | }; 56 | -------------------------------------------------------------------------------- /template/src/js/components/Hello.vue: -------------------------------------------------------------------------------- 1 | 22 | 23 | 33 | 34 | 35 | 54 | -------------------------------------------------------------------------------- /docs/unit.md: -------------------------------------------------------------------------------- 1 | # Unit Testing 2 | 3 | An overview of the tools used by this boilerplate for unit testing: 4 | 5 | - [Karma](https://karma-runner.github.io/): the test runner that launches browsers, runs the tests and reports the results to us. 6 | - [karma-webpack](https://github.com/webpack/karma-webpack): the plugin for Karma that bundles our tests using Webpack. 7 | - [Mocha](https://mochajs.org/): the test framework that we write test specs with. 8 | - [Chai](http://chaijs.com/): test assertion library that provides better assertion syntax. 9 | - [Sinon](http://sinonjs.org/): test utility library that provides spies, stubs and mocks. 10 | 11 | Chai and Sinon are integrated using [karma-sinon-chai](https://github.com/kmees/karma-sinon-chai), so all Chai interfaces (`should`, `expect`, `assert`) and `sinon` are globally available in test files. 12 | 13 | And the files: 14 | 15 | - `index.js` 16 | 17 | This is the entry file used by `karma-webpack` to bundle all the test code and source code (for coverage purposes). You can ignore it for the most part. 18 | 19 | - `specs/` 20 | 21 | This directory is where you write your actual tests. You can use full ES2015+ and all supported Webpack loaders in your tests. 22 | 23 | - `karma.conf.js` 24 | 25 | This is the Karma configuration file. See [Karma docs](https://karma-runner.github.io/) for more details. 26 | 27 | ## Running Tests in More Browsers 28 | 29 | You can run the tests in multiple real browsers by installing more [karma launchers](https://karma-runner.github.io/1.0/config/browsers.html) and adjusting the `browsers` field in `test/unit/karma.conf.js`. 30 | 31 | ## Mocking Dependencies 32 | 33 | This boilerplate comes with [inject-loader](https://github.com/plasticine/inject-loader) installed by default. For usage with `*.vue` components, see [vue-loader docs on testing with mocks](http://vue-loader.vuejs.org/en/workflow/testing-with-mocks.html). 34 | -------------------------------------------------------------------------------- /docs/pre-processors.md: -------------------------------------------------------------------------------- 1 | # Pre-Processors 2 | 3 | This boilerplate has pre-configured CSS extraction for most popular CSS pre-processors including LESS, SASS, Stylus, and PostCSS. To use a pre-processor, all you need to do is installing the appropriate webpack loader for it. For example, to use SASS: 4 | 5 | ``` bash 6 | npm install sass-loader node-sass --save-dev 7 | ``` 8 | 9 | Note you also need to install `node-sass` because `sass-loader` depends on it as a peer dependency. 10 | 11 | ### Using Pre-Processors inside Components 12 | 13 | Once installed, you can use the pre-processors inside your `*.vue` components using the `lang` attribute on ` 19 | ``` 20 | 21 | ### A note on SASS syntax 22 | 23 | - `lang="scss"` corresponds to the CSS-superset syntax (with curly braces and semicolons). 24 | - `lang="sass"` corresponds to the indentation-based syntax. 25 | 26 | ### PostCSS 27 | 28 | Styles in `*.vue` files are piped through PostCSS by default, so you don't need to use a specific loader for it. You can simply add PostCSS plugins you want to use in `build/webpack.base.conf.js` under the `vue` block: 29 | 30 | ``` js 31 | // build/webpack.base.conf.js 32 | module.exports = { 33 | // ... 34 | vue: { 35 | postcss: [/* your plugins */] 36 | } 37 | } 38 | ``` 39 | 40 | See [vue-loader's related documentation](http://vuejs.github.io/vue-loader/en/features/postcss.html) for more details. 41 | 42 | ### Standalone CSS Files 43 | 44 | To ensure consistent extraction and processing, it is recommended to import global, standalone style files from your root `App.vue` component, for example: 45 | 46 | ``` html 47 | 48 | 49 | ``` 50 | 51 | Note you should probably only do this for the styles written by yourself for your application. For existing libraries e.g. Bootstrap or Semantic UI, you can place them inside `/static` and reference them directly in `index.html`. This avoids extra build time and also is better for browser caching. (See [Static Asset Handling](static.md)) 52 | -------------------------------------------------------------------------------- /docs/backend.md: -------------------------------------------------------------------------------- 1 | # Integrating with Backend Framework 2 | 3 | If you are building a purely-static app (one that is deployed separately from the backend API), then you probably don't even need to edit `config/index.js`. However, if you want to integrate this template with an existing backend framework, e.g. Rails/Django/Laravel, which comes with their own project structures, you can edit `config.production.js` or `config.development.js` to directly generate front-end assets into your backend project. 4 | 5 | 6 | Inside the `config.production.js` section, we have the following options: 7 | 8 | ### `index` 9 | 10 | > Must be an absolute path on your local file system. 11 | 12 | This is where the `index.html` (with injected asset URLs) will be generated. 13 | 14 | If you are using this template with a backend-framework, you can edit `index.html` accordingly and point this path to a view file rendered by your backend app, e.g. `app/views/layouts/application.html.erb` for a Rails app, or `resources/views/index.blade.php` for a Laravel app. 15 | 16 | ### `assetsRoot` 17 | 18 | > Must be an absolute path on your local file system. 19 | 20 | This should point to the root directory that contains all the static assets for your app. For example, `public/` for both Rails/Laravel. 21 | 22 | ### `assetsSubDirectory` 23 | 24 | Nest webpack-generated assets under this directory in `build.assetsRoot`, so that they are not mixed with other files you may have in `build.assetsRoot`. For example, if `build.assetsRoot` is `/path/to/dist`, and `build.assetsSubDirectory` is `static`, then all Webpack assets will be generated in `path/to/dist/static`. 25 | 26 | This directory will be cleaned before each build, so it should only contain assets generated by the build. 27 | 28 | Files inside `static/` will be copied into this directory as-is during build. This means if you change this prefix, all your absolute URLs referencing files in `static/` will also need to be changed. See [Handling Static Assets](static.md) for more details. 29 | 30 | ### `assetsPublicPath` 31 | 32 | This should be the URL path where your `build.assetsRoot` will be served from over HTTP. In most cases, this will be root (`/`). Only change this if your backend framework serves static assets with a path prefix. Internally, this is passed to Webpack as `output.publicPath`. 33 | -------------------------------------------------------------------------------- /template/build/webpack.base.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const config = require('../config'); 3 | const webpack = require('webpack'); 4 | {{#lint}} 5 | const ESlintFormatter = require('eslint-friendly-formatter'); 6 | {{/lint}} 7 | 8 | const defaults = { 9 | __DEV__: JSON.stringify(config.isDev), 10 | __PROD__: JSON.stringify(config.isProd), 11 | 'process.env.NODE_ENV': `"${config.env}"`, 12 | __APP_MODE__: `"${config.appMode}"`, 13 | }; 14 | 15 | const webpackConfig = { 16 | entry: './src/js/main.js', 17 | output: { 18 | path: config.assetsRoot, 19 | publicPath: config.assetsPublicPath, 20 | filename: config.isDev ? './js/[name].js' : './js/[name].[chunkhash].js', 21 | chunkFilename: config.isDev ? './js/[id].js' : './js/chunk.[chunkhash].js', 22 | }, 23 | resolve: { 24 | extensions: ['.js', '.vue', '.json'], 25 | alias: { 26 | {{#if_eq build "standalone"}} 27 | vue$: 'vue/dist/vue.esm.js', 28 | {{/if_eq}} 29 | }, 30 | }, 31 | plugins: [ 32 | new webpack.DefinePlugin(defaults), 33 | ], 34 | module: { 35 | rules: [ 36 | {{#lint}} 37 | { 38 | test: /\.(js|vue)$/, 39 | loader: 'eslint-loader', 40 | enforce: 'pre', 41 | exclude: /node_modules/, 42 | options: { 43 | formatter: ESlintFormatter, 44 | }, 45 | }, 46 | {{/lint}} 47 | { 48 | test: /\.js$/, 49 | loader: 'babel-loader', 50 | exclude: /node_modules/, 51 | }, 52 | { 53 | test: /\.vue$/, 54 | loader: 'vue-loader', 55 | options: { 56 | extractCSS: config.isProd, 57 | }, 58 | }, 59 | { 60 | test: /\.(png|jpe?g|gif|svg)(\?.*)?$/, 61 | loader: 'url-loader', 62 | options: { 63 | limit: 100, 64 | name: path.posix.join(config.assetsSubDirectory, './img/[name].[hash:7].[ext]'), 65 | }, 66 | }, 67 | { 68 | test: /\.(mp4|webm|ogg|mp3|wav|flac|aac)(\?.*)?$/, 69 | loader: 'url-loader', 70 | options: { 71 | limit: 10000, 72 | name: path.posix.join(config.assetsSubDirectory, './media/[name].[hash:7].[ext]'), 73 | }, 74 | }, 75 | { 76 | test: /\.(woff2?|eot|ttf|otf)(\?.*)?$/, 77 | loader: 'url-loader', 78 | options: { 79 | limit: 10000, 80 | name: path.posix.join(config.assetsSubDirectory, './fonts/[name].[hash:7].[ext]'), 81 | }, 82 | }, 83 | ], 84 | }, 85 | }; 86 | 87 | module.exports = webpackConfig; 88 | -------------------------------------------------------------------------------- /template/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "{{ name }}", 3 | "description": "{{ description }}", 4 | "version": "1.0.0", 5 | "author": "{{ author }}", 6 | "private": true, 7 | "scripts": { 8 | "dev": "cross-env NODE_ENV=development NODE_APP_MODE=app webpack-dev-server --open --hot", 9 | "build": "cross-env NODE_ENV=production NODE_APP_MODE=app webpack --progress --hide-modules"{{#unit}}, 10 | "unit": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run", 11 | "test": "npm run unit"{{/unit}}{{#lint}}, 12 | "lint": "eslint --ext .js,.vue src test/unit/specs"{{/lint}} 13 | }, 14 | "dependencies": { 15 | "vue": "^2.4.2"{{#router}}, 16 | "vue-router": "^2.7.0"{{/router}} 17 | }, 18 | "devDependencies": { 19 | {{#axios}} 20 | "axios": "^0.16.2", 21 | {{/axios}} 22 | "babel-core": "^6.25.0", 23 | {{#lint}} 24 | "babel-eslint": "^7.2.3", 25 | {{/lint}} 26 | "babel-loader": "^7.1.1", 27 | "babel-preset-env": "^1.6.0", 28 | "compression-webpack-plugin": "^1.0.0", 29 | "copy-webpack-plugin": "^4.0.1", 30 | "cross-env": "^5.0.5", 31 | "css-loader": "^0.28.4", 32 | {{#lint}} 33 | "eslint": "^4.4.1", 34 | "eslint-loader": "^1.9.0", 35 | "eslint-friendly-formatter": "^3.0.0", 36 | "eslint-plugin-html": "^3.2.0", 37 | {{#if_eq lintConfig "airbnb"}} 38 | "eslint-config-airbnb-base": "^11.3.1", 39 | "eslint-import-resolver-webpack": "^0.8.3", 40 | "eslint-plugin-import": "^2.7.0", 41 | {{/if_eq}} 42 | {{/lint}} 43 | "extract-text-webpack-plugin": "^3.0.0", 44 | "file-loader": "^0.11.2", 45 | {{#ui}} 46 | {{#if_eq uiLibrary "foundation"}} 47 | "foundation-sites": "^6.4.2", 48 | {{/if_eq}} 49 | {{#if_eq uiLibrary "element"}} 50 | "element-ui": "^1.4.2", 51 | "babel-plugin-component": "^0.10.0", 52 | {{/if_eq}} 53 | {{/ui}} 54 | "friendly-errors-webpack-plugin": "^1.6.1", 55 | "html-webpack-plugin": "^2.30.1", 56 | {{#unit}} 57 | "karma": "^1.4.1", 58 | "karma-coverage": "^1.1.1", 59 | "karma-mocha": "^1.3.0", 60 | "karma-phantomjs-launcher": "^1.0.2", 61 | "karma-phantomjs-shim": "^1.4.0", 62 | "karma-sinon-chai": "^1.3.1", 63 | "karma-sourcemap-loader": "^0.3.7", 64 | "karma-spec-reporter": "0.0.31", 65 | "karma-webpack": "^2.0.2", 66 | "lolex": "^1.5.2", 67 | "mocha": "^3.2.0", 68 | "chai": "^3.5.0", 69 | "sinon": "^2.1.0", 70 | "sinon-chai": "^2.8.0", 71 | "inject-loader": "^3.0.0", 72 | "babel-plugin-istanbul": "^4.1.1", 73 | "phantomjs-prebuilt": "^2.1.14", 74 | {{/unit}} 75 | {{#lodash}} 76 | "lodash": "^4.17.4", 77 | "babel-plugin-lodash": "^3.2.11", 78 | "lodash-webpack-plugin": "^0.11.4", 79 | {{/lodash}} 80 | "node-sass": "^4.5.3", 81 | "optimize-css-assets-webpack-plugin": "^3.0.0", 82 | "sass-loader": "^6.0.6", 83 | "style-loader": "^0.18.2", 84 | "url-loader": "^0.5.9", 85 | "vue-loader": "^13.0.4", 86 | "vue-template-compiler": "^2.4.2", 87 | "webpack": "^3.5.4", 88 | "webpack-bundle-analyzer": "^2.9.0", 89 | "webpack-dev-server": "^2.7.1", 90 | "webpack-merge": "^4.1.0" 91 | }, 92 | "engines": { 93 | "node": ">= 4.0.0", 94 | "npm": ">= 3.0.0" 95 | }, 96 | "browserslist": [ 97 | "> 1%", 98 | "last 2 versions", 99 | "not ie <= 8" 100 | ] 101 | } 102 | -------------------------------------------------------------------------------- /meta.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | "helpers": { 3 | "if_or": function (v1, v2, options) { 4 | if (v1 || v2) { 5 | return options.fn(this); 6 | } 7 | 8 | return options.inverse(this); 9 | } 10 | }, 11 | "prompts": { 12 | "name": { 13 | "type": "string", 14 | "required": true, 15 | "message": "Project name" 16 | }, 17 | "description": { 18 | "type": "string", 19 | "required": false, 20 | "message": "Project description", 21 | "default": "A Vue.js project" 22 | }, 23 | "author": { 24 | "type": "string", 25 | "message": "Author" 26 | }, 27 | "build": { 28 | "type": "list", 29 | "message": "Vue build", 30 | "choices": [ 31 | { 32 | "name": "Runtime + Compiler: recommended for most users", 33 | "value": "standalone", 34 | "short": "standalone" 35 | }, 36 | { 37 | "name": "Runtime-only: about 6KB lighter min+gzip, but templates (or any Vue-specific HTML) are ONLY allowed in .vue files - render functions are required elsewhere", 38 | "value": "runtime", 39 | "short": "runtime" 40 | } 41 | ] 42 | }, 43 | "router": { 44 | "type": "confirm", 45 | "message": "Install vue-router?" 46 | }, 47 | "lint": { 48 | "type": "confirm", 49 | "message": "Use ESLint to lint your code?" 50 | }, 51 | "lintConfig": { 52 | "when": "lint", 53 | "type": "list", 54 | "message": "Pick an ESLint preset", 55 | "choices": [ 56 | { 57 | "name": "Airbnb (https://github.com/airbnb/javascript)", 58 | "value": "airbnb", 59 | "short": "Airbnb" 60 | }, 61 | { 62 | "name": "none (configure it yourself)", 63 | "value": "none", 64 | "short": "none" 65 | } 66 | ] 67 | }, 68 | "unit": { 69 | "type": "confirm", 70 | "message": "Setup unit tests with Karma + Mocha?" 71 | }, 72 | "lodash": { 73 | "type": "confirm", 74 | "message": "Install lodash into the project?" 75 | }, 76 | "axios": { 77 | "type": "confirm", 78 | "message": "Install axios into the project?" 79 | }, 80 | "ui": { 81 | "type": "confirm", 82 | "message": "Use a UI library to help with basic styles and components?" 83 | }, 84 | "uiLibrary": { 85 | "when": "ui", 86 | "type": "list", 87 | "message": "Pick a UI Library", 88 | "choices": [ 89 | { 90 | "name": "Element - A Vue based component library (http://element.eleme.io/#/en-US)", 91 | "value": "element", 92 | "short": "Element" 93 | }, 94 | { 95 | "name": "Foundation - Responsive front-end framework (http://foundation.zurb.com/)", 96 | "value": "foundation", 97 | "short": "Foundation" 98 | } 99 | ] 100 | 101 | } 102 | }, 103 | "filters": { 104 | ".eslintrc.js": "lint", 105 | ".eslintignore": "lint", 106 | "test/unit/**/*": "unit", 107 | "build/webpack.testing.js": "unit", 108 | "src/router/**/*": "router" 109 | }, 110 | "completeMessage": "To get started:\n\n {{^inPlace}}cd {{destDirName}}\n {{/inPlace}}npm install\n npm run dev\n\nDocumentation can be found at https://vuejs-templates.github.io/webpack" 111 | }; 112 | -------------------------------------------------------------------------------- /docs/static.md: -------------------------------------------------------------------------------- 1 | # Handling Static Assets 2 | 3 | You will notice in the project structure we have two directories for static assets: `src/assets` and `static/`. What is the difference between them? 4 | 5 | ### Webpacked Assets 6 | 7 | To answer this question, we first need to understand how Webpack deals with static assets. In `*.vue` components, all your templates and CSS are parsed by `vue-html-loader` and `css-loader` to look for asset URLs. For example, in `` and `background: url(./logo.png)`, `"./logo.png"` is a relative asset path and will be **resolved by Webpack as a module dependency**. 8 | 9 | Because `logo.png` is not JavaScript, when treated as a module dependency, we need to use `url-loader` and `file-loader` to process it. This boilerplate has already configured these loaders for you, so you basically get features such as filename fingerprinting and conditional base64 inlining for free, while being able to use relative/module paths without worrying about deployment. 10 | 11 | Since these assets may be inlined/copied/renamed during build, they are essentially part of your source code. This is why it is recommended to place Webpack-processed static assets inside `/src`, along side other source files. In fact, you don't even have to put them all in `/src/assets`: you can organize them based on the module/component using them. For example, you can put each component in its own directory, with its static assets right next to it. 12 | 13 | ### Asset Resolving Rules 14 | 15 | - **Relative URLs**, e.g. `./assets/logo.png` will be interpreted as a module dependency. They will be replaced with an auto-generated URL based on your Webpack output configuration. 16 | 17 | - **Non-prefixed URLs**, e.g. `assets/logo.png` will be treated the same as the relative URLs and translated into `./assets/logo.png`. 18 | 19 | - **URLs prefixed with `~`** are treated as a module request, similar to `require('some-module/image.png')`. You need to use this prefix if you want to leverage Webpack's module resolving configurations. For example if you have a resolve alias for `assets`, you need to use `` to ensure that alias is respected. 20 | 21 | - **Root-relative URLs**, e.g. `/assets/logo.png` are not processed at all. 22 | 23 | ### Getting Asset Paths in JavaScript 24 | 25 | In order for Webpack to return the correct asset paths, you need to use `require('./relative/path/to/file.jpg')`, which will get processed by `file-loader` and returns the resolved URL. For example: 26 | 27 | ``` js 28 | computed: { 29 | background () { 30 | return require('./bgs/' + this.id + '.jpg') 31 | } 32 | } 33 | ``` 34 | 35 | **Note the above example will include every image under `./bgs/` in the final build.** This is because Webpack cannot guess which of them will be used at runtime, so it includes them all. 36 | 37 | ### "Real" Static Assets 38 | 39 | In comparison, files in `static/` are not processed by Webpack at all: they are directly copied to their final destination as-is, with the same filename. You must reference these files using absolute paths, which is determined by joining `build.assetsPublicPath` and `build.assetsSubDirectory` in `config.js`. 40 | 41 | As an example, with the following default values: 42 | 43 | ``` js 44 | // config/index.js 45 | module.exports = { 46 | // ... 47 | build: { 48 | assetsPublicPath: '/', 49 | assetsSubDirectory: 'static' 50 | } 51 | } 52 | ``` 53 | 54 | Any file placed in `static/` should be referenced using the absolute URL `/static/[filename]`. If you change `assetSubDirectory` to `assets`, then these URLs will need to be changed to `/assets/[filename]`. 55 | 56 | We will learn more about the config file in the section about [backend integration](backend.md). 57 | -------------------------------------------------------------------------------- /docs/structure.md: -------------------------------------------------------------------------------- 1 | # Project Structure 2 | 3 | ```bash 4 | . 5 | ├── build # webpack config files 6 | │   ├── webpack.base.js 7 | │   ├── webpack.development.js 8 | │   ├── webpack.production.js 9 | │   └── webpack.testing.js 10 | ├── config # main project config 11 | │   ├── config.app.js # contains app specific values. {app} can be any name eg - scroll, st 12 | │   ├── config.base.js # contains default values 13 | │   ├── config.development.js # contains values used in dev environment 14 | │   ├── config.production.js # conatins values used in prod environment 15 | │   └── index.js 16 | ├── dist 17 | ├── src 18 | │   ├── assets # module assets (processed by webpack) 19 | │   │   └── logo.png 20 | │   ├── js 21 | │   │   ├── components # ui components 22 | │   │   │   └── Hello.vue 23 | │   │   ├── router 24 | │   │   │   └── index.js 25 | │   │   ├── utils 26 | │   │   │   └── .gitkeep 27 | │   │   ├── views 28 | │   │   │   └── .gitkeep 29 | │   │   ├── App.vue # main app component 30 | │   │   └── main.js # app entry file 31 | │   └── scss 32 | │   └── style.scss 33 | ├── static # pure static assets (directly copied) 34 | │   └── .gitkeep 35 | ├── test 36 | │   └── unit # unit tests 37 | │   ├── specs 38 | │   │   └── Hello.spec.js # test spec files 39 | │   ├── .eslintrc 40 | │   ├── index.js # test build entry file 41 | │   └── karma.conf.js # test runner config file 42 | ├── .babelrc # babel config 43 | ├── .editorconfig # editor config 44 | ├── .eslintignore # config for ignored files and dirs for eslint 45 | ├── .eslintrc.js # eslint config 46 | ├── .gitignore 47 | ├── README.md 48 | ├── index.html # index.html template 49 | ├── package.json # build scripts and dependencies 50 | └── webpack.config.js # webpack config entry point 51 | ``` 52 | 53 | 54 | ### `build/` 55 | 56 | This directory holds the actual configurations for both the development server and the production webpack build. Normally you don't need to touch these files unless you want to customize Webpack loaders, in which case you should probably look at `build/webpack.base.js`. 57 | 58 | ### `config/index.js` 59 | 60 | This is the main configuration file that exposes some of the most common configuration options for the build setup. It merges three different config files to give a unified configuration management based on the environaments and app modes. 61 | 62 | - baseConfig (`config.base.js`) 63 | - envConfig (`config.${env}.js` based on the environment (dev, prod) the app is running) 64 | - appConfig (`config.${appMode}.js` based on the appMode. This file can be renamed as per your app name like `config.app1.js` or added a new file for `config.app2.js`) 65 | 66 | 67 | ### `src/` 68 | 69 | This is where most of your application code will live in. How to structure everything inside this directory is largely up to you; if you are using Vuex, you can consult the [recommendations for Vuex applications](http://vuex.vuejs.org/en/structure.html). 70 | 71 | ### `static/` 72 | 73 | This directory is an escape hatch for static assets that you do not want to process with Webpack. They will be directly copied into the same directory where webpack-built assets are generated. 74 | 75 | See [Handling Static Assets](static.md) for more details. 76 | 77 | ### `test/unit` 78 | 79 | Contains unit test related files. See [Unit Testing](unit.md) for more details. 80 | 81 | ### `index.html` 82 | 83 | This is the **template** `index.html` for our single page application. During development and builds, Webpack will generate assets, and the URLs for those generated assets will be automatically injected into this template to render the final HTML. 84 | 85 | ### `package.json` 86 | 87 | The NPM package meta file that contains all the build dependencies and [build commands](commands.md). 88 | -------------------------------------------------------------------------------- /template/build/webpack.production.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const config = require('../config'); 3 | const webpack = require('webpack'); 4 | 5 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 6 | const HtmlWebpackPlugin = require('html-webpack-plugin'); 7 | const ExtractTextPlugin = require('extract-text-webpack-plugin'); 8 | const OptimizeCSSPlugin = require('optimize-css-assets-webpack-plugin'); 9 | {{#lodash}} 10 | const LodashModuleReplacementPlugin = require('lodash-webpack-plugin'); 11 | {{/lodash}} 12 | 13 | const webpackConfig = { 14 | devtool: '#source-map', 15 | module: { 16 | rules: [ 17 | { 18 | test: /\.scss$/i, 19 | use: ExtractTextPlugin.extract({ 20 | fallback: 'style-loader', 21 | // resolve-url-loader may be chained before sass-loader if necessary 22 | use: ['css-loader', 'sass-loader'], 23 | }), 24 | }, 25 | { 26 | test: /\.css$/i, 27 | use: ExtractTextPlugin.extract({ 28 | fallback: 'style-loader', 29 | use: 'css-loader', 30 | }), 31 | }, 32 | ], 33 | }, 34 | plugins: [ 35 | new webpack.optimize.UglifyJsPlugin({ 36 | sourceMap: true, 37 | output: { 38 | comments: false, 39 | }, 40 | debug: false, 41 | compress: { 42 | warnings: false, 43 | dead_code: true, 44 | }, 45 | }), 46 | {{#lodash}} 47 | new LodashModuleReplacementPlugin(), 48 | {{/lodash}} 49 | // extract css into its own file 50 | new ExtractTextPlugin({ 51 | filename: './css/[name].[contenthash].css', 52 | }), 53 | // Compress extracted CSS. We are using this plugin so that possible 54 | // duplicated CSS from different components can be deduped. 55 | new OptimizeCSSPlugin({ 56 | cssProcessorOptions: { 57 | safe: true, 58 | }, 59 | }), 60 | // generate dist index.html with correct asset hash for caching. 61 | // you can customize output by editing /index.html 62 | // see https://github.com/ampedandwired/html-webpack-plugin 63 | new HtmlWebpackPlugin({ 64 | filename: config.index, 65 | template: 'index.html', 66 | inject: true, 67 | minify: { 68 | removeComments: true, 69 | collapseWhitespace: true, 70 | removeAttributeQuotes: true, 71 | // more options: 72 | // https://github.com/kangax/html-minifier#options-quick-reference 73 | }, 74 | // necessary to consistently work with multiple chunks via CommonsChunkPlugin 75 | chunksSortMode: 'dependency', 76 | }), 77 | // split vendor js into its own file 78 | new webpack.optimize.CommonsChunkPlugin({ 79 | name: 'vendor', 80 | minChunks(module) { 81 | // any required modules inside node_modules are extracted to vendor 82 | return ( 83 | module.resource && /\.js$/.test(module.resource) && 84 | module.resource.indexOf(path.join(__dirname, '../node_modules')) === 0 85 | ); 86 | }, 87 | }), 88 | // extract webpack runtime and module manifest to its own file in order to 89 | // prevent vendor hash from being updated whenever app bundle is updated 90 | new webpack.optimize.CommonsChunkPlugin({ 91 | name: 'manifest', 92 | chunks: ['vendor'], 93 | }), 94 | // copy custom static assets 95 | new CopyWebpackPlugin([ 96 | { 97 | from: path.resolve(__dirname, '../static'), 98 | to: config.assetsSubDirectory, 99 | ignore: ['.*'], 100 | }, 101 | ]), 102 | new webpack.LoaderOptionsPlugin({ 103 | minimize: true, 104 | }), 105 | ], 106 | }; 107 | 108 | 109 | if (config.productionGzip) { 110 | const CompressionWebpackPlugin = require('compression-webpack-plugin'); 111 | 112 | webpackConfig.plugins.push( 113 | new CompressionWebpackPlugin({ 114 | asset: '[path].gz[query]', 115 | algorithm: 'gzip', 116 | test: new RegExp(`\\.(${config.productionGzipExtensions.join('|')})$`), 117 | threshold: 10240, 118 | minRatio: 0.8, 119 | })); 120 | } 121 | 122 | if (config.bundleAnalyzerReport) { 123 | const BundleAnalyzerPlugin = require('webpack-bundle-analyzer').BundleAnalyzerPlugin; 124 | webpackConfig.plugins.push(new BundleAnalyzerPlugin()); 125 | } 126 | 127 | module.exports = webpackConfig; 128 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-starter 2 | 3 | > A Vue.js starter kit that lets you focus on more programming and less configuration. 4 | 5 | > A full-featured Webpack setup with hot-reload, lint-on-save, unit testing & css extraction. 6 | 7 | > This template is Vue 2.0 compatible. 8 | 9 | 10 | ## Why? 11 | 12 | At [Scroll.in](https://scroll.in), we have chosen Vue.js as our primary JS framework. So, while working on various Vue.js projects we felt like we needed a template for all our projects which can be used for better consistency and coding style across developers. 13 | 14 | We could always use the in built templates that come with vue-cli, but somehow I felt [webpack-simple](https://github.com/vuejs-templates/webpack-simple) was too simple and lacked certain necessary features to be opted as a standard boilerplate for our projects. On the other hand, [webpack](https://github.com/vuejs-templates/webpack-simple) seemed too complex to understand what's going on inside it specially for a junior dev it would be nightmare to make some config changes to it. 15 | 16 | This is why this project came to life. With certain decisions already made to make life easier for programmers and certain feature built in right out of the box. 17 | 18 | This project started as a webpack-simple template with incremental addition of features and configs to suit the needs of a medium to large vue.js project. It is inspired by the webpack template but without all the complexity. 19 | 20 | 21 | ## Documentation 22 | 23 | - [For this template](http://arkpod.in/vue-starter): common questions specific to this template are answered and each part is described in greater detail 24 | - [For Vue 2.0](http://vuejs.org/guide/): general information about how to work with Vue, not specific to this template 25 | 26 | ## Usage 27 | 28 | This is a project template for [vue-cli](https://github.com/vuejs/vue-cli). **It is recommended to use npm 3+ for a more efficient dependency tree.** 29 | 30 | ``` bash 31 | $ npm install -g vue-cli 32 | $ vue init rohitkrai03/vue-starter my-project 33 | $ cd my-project 34 | $ npm install 35 | $ npm run dev 36 | ``` 37 | 38 | ## What's Included 39 | 40 | - `npm run dev`: first-in-class development experience. 41 | - Webpack + `vue-loader` for single file Vue components. 42 | - State preserving hot-reload 43 | - State preserving compilation error overlay 44 | - Lint-on-save with ESLint 45 | - Source maps 46 | 47 | - `npm run build`: Production ready build. 48 | - JavaScript minified with [UglifyJS](https://github.com/mishoo/UglifyJS2). 49 | - HTML minified with [html-minifier](https://github.com/kangax/html-minifier). 50 | - CSS across all components extracted into a single file and minified with [cssnano](https://github.com/ben-eb/cssnano). 51 | - All static assets compiled with version hashes for efficient long-term caching, and a production `index.html` is auto-generated with proper URLs to these generated assets. 52 | - Use `npm run build --report`to build with bundle size analytics. 53 | 54 | - `npm run unit`: Unit tests run in PhantomJS with [Karma](http://karma-runner.github.io/0.13/index.html) + [Mocha](http://mochajs.org/) + [karma-webpack](https://github.com/webpack/karma-webpack). 55 | - Supports ES2015+ in test files. 56 | - Supports all webpack loaders. 57 | - Easy mock injection. 58 | 59 | - This boilerplate uses [ESLint](http://eslint.org/) as the linter, and uses the [eslint-config-airbnb](https://github.com/airbnb/javascript/tree/master/packages/eslint-config-airbnb) preset with some small customizations. 60 | 61 | - Option to install and setup [vue-router](https://github.com/vuejs/vue-router) 62 | 63 | - Utilities like `lodash` and `axios` come installed out of the box. You can opt out while installing template from vue-cli as well. Also, webpack will be configured accordingly to make use of only the modules that are used and not the whole library to reduce bundle size. 64 | 65 | - An option to install a UI Library 66 | - [Element](http://element.eleme.io/#/en-US) A Vue 2.0 based component library for developers, designers and product managers. Also, configured to use only the required modules and components in the final bundle. 67 | - [Foundation](http://foundation.zurb.com/) A responsive front-end framework. Imported minified css file in index.html. Js file can be imported as per the need as well. 68 | 69 | - A converge like config management system which merges different config files based on environment and app mode. 70 | 71 | - A well defined folder structure for medium to large Vue.js projects. 72 | 73 | 74 | ### Fork It And Make Your Own 75 | 76 | You can fork this repo to create your own boilerplate, and use it with `vue-cli`: 77 | 78 | ``` bash 79 | vue init username/repo my-project 80 | ``` 81 | --------------------------------------------------------------------------------