├── static
└── .gitkeep
├── .eslintignore
├── config
├── prod.env.js
├── test.env.js
├── dev.env.js
└── index.js
├── src
├── assets
│ └── logo.png
├── components
│ ├── About.vue
│ └── Hello.vue
├── main.js
├── App.vue
└── router
│ └── index.js
├── test
├── unit
│ ├── .eslintrc
│ ├── specs
│ │ └── Hello.spec.js
│ ├── index.js
│ └── karma.conf.js
└── e2e
│ ├── specs
│ └── test.js
│ ├── custom-assertions
│ └── elementCount.js
│ ├── runner.js
│ └── nightwatch.conf.js
├── .gitignore
├── .editorconfig
├── .postcssrc.js
├── index.html
├── .babelrc
├── LICENSE
├── .eslintrc.js
├── package.json
└── README.md
/static/.gitkeep:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.eslintignore:
--------------------------------------------------------------------------------
1 | build/*.js
2 | config/*.js
3 |
--------------------------------------------------------------------------------
/config/prod.env.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | NODE_ENV: '"production"'
3 | }
4 |
--------------------------------------------------------------------------------
/src/assets/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/adgang/vue-tutorial/HEAD/src/assets/logo.png
--------------------------------------------------------------------------------
/test/unit/.eslintrc:
--------------------------------------------------------------------------------
1 | {
2 | "env": {
3 | "mocha": true
4 | },
5 | "globals": {
6 | "expect": true,
7 | "sinon": true
8 | }
9 | }
10 |
--------------------------------------------------------------------------------
/config/test.env.js:
--------------------------------------------------------------------------------
1 | var merge = require('webpack-merge')
2 | var devEnv = require('./dev.env')
3 |
4 | module.exports = merge(devEnv, {
5 | NODE_ENV: '"testing"'
6 | })
7 |
--------------------------------------------------------------------------------
/config/dev.env.js:
--------------------------------------------------------------------------------
1 | var merge = require('webpack-merge')
2 | var prodEnv = require('./prod.env')
3 |
4 | module.exports = merge(prodEnv, {
5 | NODE_ENV: '"development"'
6 | })
7 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules/
3 | dist/
4 | npm-debug.log*
5 | yarn-debug.log*
6 | yarn-error.log*
7 | test/unit/coverage
8 | test/e2e/reports
9 | selenium-debug.log
10 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/.postcssrc.js:
--------------------------------------------------------------------------------
1 | // https://github.com/michael-ciniawsky/postcss-load-config
2 |
3 | module.exports = {
4 | "plugins": {
5 | // to edit target browsers: use "browserlist" field in package.json
6 | "autoprefixer": {}
7 | }
8 | }
9 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | vue-tutorial
6 |
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/.babelrc:
--------------------------------------------------------------------------------
1 | {
2 | "presets": [
3 | ["env", { "modules": false }],
4 | "stage-2"
5 | ],
6 | "plugins": ["transform-runtime"],
7 | "comments": false,
8 | "env": {
9 | "test": {
10 | "presets": ["env", "stage-2"],
11 | "plugins": [ "istanbul" ]
12 | }
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/src/components/About.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ msg }}
4 |
5 |
6 |
17 |
--------------------------------------------------------------------------------
/test/unit/specs/Hello.spec.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Hello from '@/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 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | // The Vue build version to load with the `import` command
2 | // (runtime-only or standalone) has been set in webpack.base.conf with an alias.
3 | import Vue from 'vue'
4 | import App from './App'
5 | import router from './router'
6 |
7 | Vue.config.productionTip = false
8 |
9 | /* eslint-disable no-new */
10 | new Vue({
11 | el: '#app',
12 | router,
13 | template: '',
14 | components: { App }
15 | })
16 |
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |

4 |
5 |
6 |
7 |
8 |
13 |
14 |
24 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | ```
2 | DO WHAT THE FUCK YOU WANT TO, DONT BLAME ME PUBLIC LICENSE
3 | Version 1, May 2017
4 |
5 | Copyright (C) 2017 Aditya Gangipamula
6 |
7 | Everyone is permitted to copy and distribute verbatim or modified
8 | copies of this license document, and changing it is allowed as long
9 | as the name is changed.
10 |
11 | DO WHAT THE FUCK YOU WANT TO, DONT BLAME ME PUBLIC LICENSE
12 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
13 |
14 | 0. You just DO WHAT THE FUCK YOU WANT TO.
15 | 1. You DONT BLAME ME if some shit happens.
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 | // automatically uses dev Server port from /config.index.js
7 | // default: http://localhost:8080
8 | // see nightwatch.conf.js
9 | const devServer = browser.globals.devServerURL
10 |
11 | browser
12 | .url(devServer)
13 | .waitForElementVisible('#app', 5000)
14 | .assert.elementPresent('.hello')
15 | .assert.containsText('h1', 'Welcome to Your Vue.js App')
16 | .assert.elementCount('img', 1)
17 | .end()
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/router/index.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue'
2 | import Router from 'vue-router'
3 | import Hello from '@/components/Hello'
4 | import About from '@/components/About'
5 |
6 | Vue.use(Router)
7 |
8 | export default new Router({
9 | // History mode works fine in dev. But be sure to
10 | // get your web server config right when deploying
11 | // in production environments. Also I suspect there
12 | // could be browser support issues
13 | // mode: 'history',
14 | routes: [
15 | {
16 | path: '/',
17 | name: 'Hello',
18 | component: Hello
19 | },
20 | {
21 | path: '/about',
22 | name: 'About',
23 | component: About
24 | }
25 | ]
26 | })
27 |
--------------------------------------------------------------------------------
/.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 | // https://github.com/feross/standard/blob/master/RULES.md#javascript-standard-style
13 | extends: 'standard',
14 | // required to lint *.vue files
15 | plugins: [
16 | 'html'
17 | ],
18 | // add your custom rules here
19 | 'rules': {
20 | // allow paren-less arrow functions
21 | 'arrow-parens': 0,
22 | // allow async-await
23 | 'generator-star-spacing': 0,
24 | // allow debugger during development
25 | 'no-debugger': process.env.NODE_ENV === 'production' ? 2 : 0
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/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 |
--------------------------------------------------------------------------------
/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 webpackConfig = require('../../build/webpack.test.conf')
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 |
--------------------------------------------------------------------------------
/test/e2e/runner.js:
--------------------------------------------------------------------------------
1 | // 1. start the dev server using production config
2 | process.env.NODE_ENV = 'testing'
3 | var server = require('../../build/dev-server.js')
4 |
5 | server.ready.then(() => {
6 | // 2. run the nightwatch test suite against it
7 | // to run in additional browsers:
8 | // 1. add an entry in test/e2e/nightwatch.conf.json under "test_settings"
9 | // 2. add it to the --env flag below
10 | // or override the environment flag, for example: `npm run e2e -- --env chrome,firefox`
11 | // For more information on Nightwatch's config file, see
12 | // http://nightwatchjs.org/guide#settings-file
13 | var opts = process.argv.slice(2)
14 | if (opts.indexOf('--config') === -1) {
15 | opts = opts.concat(['--config', 'test/e2e/nightwatch.conf.js'])
16 | }
17 | if (opts.indexOf('--env') === -1) {
18 | opts = opts.concat(['--env', 'chrome'])
19 | }
20 |
21 | var spawn = require('cross-spawn')
22 | var runner = spawn('./node_modules/.bin/nightwatch', opts, { stdio: 'inherit' })
23 |
24 | runner.on('exit', function (code) {
25 | server.close()
26 | process.exit(code)
27 | })
28 |
29 | runner.on('error', function (err) {
30 | server.close()
31 | throw err
32 | })
33 | })
34 |
--------------------------------------------------------------------------------
/test/e2e/nightwatch.conf.js:
--------------------------------------------------------------------------------
1 | require('babel-register')
2 | var config = require('../../config')
3 |
4 | // http://nightwatchjs.org/gettingstarted#settings-file
5 | module.exports = {
6 | src_folders: ['test/e2e/specs'],
7 | output_folder: 'test/e2e/reports',
8 | custom_assertions_path: ['test/e2e/custom-assertions'],
9 |
10 | selenium: {
11 | start_process: true,
12 | server_path: require('selenium-server').path,
13 | host: '127.0.0.1',
14 | port: 4444,
15 | cli_args: {
16 | 'webdriver.chrome.driver': require('chromedriver').path
17 | }
18 | },
19 |
20 | test_settings: {
21 | default: {
22 | selenium_port: 4444,
23 | selenium_host: 'localhost',
24 | silent: true,
25 | globals: {
26 | devServerURL: 'http://localhost:' + (process.env.PORT || config.dev.port)
27 | }
28 | },
29 |
30 | chrome: {
31 | desiredCapabilities: {
32 | browserName: 'chrome',
33 | javascriptEnabled: true,
34 | acceptSslCerts: true
35 | }
36 | },
37 |
38 | firefox: {
39 | desiredCapabilities: {
40 | browserName: 'firefox',
41 | javascriptEnabled: true,
42 | acceptSslCerts: true
43 | }
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/config/index.js:
--------------------------------------------------------------------------------
1 | // see http://vuejs-templates.github.io/webpack for documentation.
2 | var path = require('path')
3 |
4 | module.exports = {
5 | build: {
6 | env: require('./prod.env'),
7 | index: path.resolve(__dirname, '../dist/index.html'),
8 | assetsRoot: path.resolve(__dirname, '../dist'),
9 | assetsSubDirectory: 'static',
10 | assetsPublicPath: '/',
11 | productionSourceMap: true,
12 | // Gzip off by default as many popular static hosts such as
13 | // Surge or Netlify already gzip all static assets for you.
14 | // Before setting to `true`, make sure to:
15 | // npm install --save-dev compression-webpack-plugin
16 | productionGzip: false,
17 | productionGzipExtensions: ['js', 'css'],
18 | // Run the build command with an extra argument to
19 | // View the bundle analyzer report after build finishes:
20 | // `npm run build --report`
21 | // Set to `true` or `false` to always turn it on or off
22 | bundleAnalyzerReport: process.env.npm_config_report
23 | },
24 | dev: {
25 | env: require('./dev.env'),
26 | port: 18080,
27 | autoOpenBrowser: true,
28 | assetsSubDirectory: 'static',
29 | assetsPublicPath: '/',
30 | proxyTable: {},
31 | // CSS Sourcemaps off by default because relative paths are "buggy"
32 | // with this option, according to the CSS-Loader README
33 | // (https://github.com/webpack/css-loader#sourcemaps)
34 | // In our experience, they generally work as expected,
35 | // just be aware of this issue when enabling this option.
36 | cssSourceMap: false
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/src/components/Hello.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
{{ msg }}
4 |
Essential Links
5 |
13 |
Ecosystem
14 |
20 |
21 |
22 |
23 |
24 |
25 |
37 |
38 |
39 |
58 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "vue-tutorial",
3 | "version": "1.0.0",
4 | "description": "A sample step by step, commit by commit Vue tutorial",
5 | "author": "adgang@tuta.io",
6 | "private": true,
7 | "scripts": {
8 | "dev": "node build/dev-server.js",
9 | "start": "node build/dev-server.js",
10 | "build": "node build/build.js",
11 | "unit": "cross-env BABEL_ENV=test karma start test/unit/karma.conf.js --single-run",
12 | "e2e": "node test/e2e/runner.js",
13 | "test": "npm run unit && npm run e2e",
14 | "lint": "eslint --ext .js,.vue src test/unit/specs test/e2e/specs"
15 | },
16 | "dependencies": {
17 | "vue": "^2.3.3",
18 | "vue-router": "^2.3.1"
19 | },
20 | "devDependencies": {
21 | "autoprefixer": "^6.7.2",
22 | "babel-core": "^6.22.1",
23 | "babel-eslint": "^7.1.1",
24 | "babel-loader": "^6.2.10",
25 | "babel-plugin-transform-runtime": "^6.22.0",
26 | "babel-preset-env": "^1.3.2",
27 | "babel-preset-stage-2": "^6.22.0",
28 | "babel-register": "^6.22.0",
29 | "chalk": "^1.1.3",
30 | "connect-history-api-fallback": "^1.3.0",
31 | "copy-webpack-plugin": "^4.0.1",
32 | "css-loader": "^0.28.0",
33 | "eslint": "^3.19.0",
34 | "eslint-friendly-formatter": "^2.0.7",
35 | "eslint-loader": "^1.7.1",
36 | "eslint-plugin-html": "^2.0.0",
37 | "eslint-config-standard": "^6.2.1",
38 | "eslint-plugin-promise": "^3.4.0",
39 | "eslint-plugin-standard": "^2.0.1",
40 | "eventsource-polyfill": "^0.9.6",
41 | "express": "^4.14.1",
42 | "extract-text-webpack-plugin": "^2.0.0",
43 | "file-loader": "^0.11.1",
44 | "friendly-errors-webpack-plugin": "^1.1.3",
45 | "html-webpack-plugin": "^2.28.0",
46 | "http-proxy-middleware": "^0.17.3",
47 | "webpack-bundle-analyzer": "^2.2.1",
48 | "cross-env": "^4.0.0",
49 | "karma": "^1.4.1",
50 | "karma-coverage": "^1.1.1",
51 | "karma-mocha": "^1.3.0",
52 | "karma-phantomjs-launcher": "^1.0.2",
53 | "karma-phantomjs-shim": "^1.4.0",
54 | "karma-sinon-chai": "^1.3.1",
55 | "karma-sourcemap-loader": "^0.3.7",
56 | "karma-spec-reporter": "0.0.30",
57 | "karma-webpack": "^2.0.2",
58 | "lolex": "^1.5.2",
59 | "mocha": "^3.2.0",
60 | "chai": "^3.5.0",
61 | "sinon": "^2.1.0",
62 | "sinon-chai": "^2.8.0",
63 | "inject-loader": "^3.0.0",
64 | "babel-plugin-istanbul": "^4.1.1",
65 | "phantomjs-prebuilt": "^2.1.14",
66 | "chromedriver": "^2.27.2",
67 | "cross-spawn": "^5.0.1",
68 | "nightwatch": "^0.9.12",
69 | "selenium-server": "^3.0.1",
70 | "semver": "^5.3.0",
71 | "shelljs": "^0.7.6",
72 | "opn": "^4.0.2",
73 | "optimize-css-assets-webpack-plugin": "^1.3.0",
74 | "ora": "^1.2.0",
75 | "rimraf": "^2.6.0",
76 | "url-loader": "^0.5.8",
77 | "vue-loader": "^12.1.0",
78 | "vue-style-loader": "^3.0.1",
79 | "vue-template-compiler": "^2.3.3",
80 | "webpack": "^2.6.1",
81 | "webpack-dev-middleware": "^1.10.0",
82 | "webpack-hot-middleware": "^2.18.0",
83 | "webpack-merge": "^4.1.0"
84 | },
85 | "engines": {
86 | "node": ">= 4.0.0",
87 | "npm": ">= 3.0.0"
88 | },
89 | "browserslist": [
90 | "> 1%",
91 | "last 2 versions",
92 | "not ie <= 8"
93 | ]
94 | }
95 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vue-tutorial
2 |
3 | > A sample step by step, commit by commit Vue tutorial. We are really only looking to learn writing a simple app using vue-cli. The following are the things we demo in each commit.
4 |
5 | 1. vue-cli installation
6 | 2. Creating a vue project
7 | 3. Getting the root controller or the controller on path `/` running with an App.
8 | 4. Writing a simple Component and assign a route to it.
9 | 5. Writing two components and using composition(using one component in another).
10 |
11 | ## 1. vue-cli installation
12 | First, we global install vue-cli like so:
13 | > npm install -g vue-cli
14 |
15 | Depending on your npm setup, you might need sudo on above command.
16 |
17 | ## 2. Create a Vue project
18 | ```
19 | vue init webpack
20 | ```
21 |
22 | I chose the webpack template here. There are other options available. The init command creates a Vue app and a component called Hello, with a route path `/` assigned to it. You can run
23 | > npm run dev
24 |
25 | to check that the app is running. Be sure to run `npm install` before running the app. Change the port in `config/index.js` if necessary. I changed it to 18080.
26 |
27 | ## 3. Getting the App working
28 |
29 | To understand how the app is working check the following files in that order.
30 | ```
31 | index.html => The single page application's, well, single page.
32 | src/main.js => The main javascript file which creates a Vue object(App) and binds it to a div on the page. Also defines where to find routes(./router).
33 | src/App.vue => The vue file which defines the template and logic to inject page specific stuff based on path. The `router-view` element will inject the stuff from the relevant Vue component.
34 | src/router/index.js => Defines routes mapping Controllers to paths
35 | src/components/Hello.vue => The Hello component which renders the welcome message and all the links.
36 | ```
37 |
38 | First run `npm run dev`
39 | Keep `localhost:18080` open on a browser.
40 | Let us customize stuff a bit. Let's replace the welcome message in Hello.vue with:
41 | > Welcome to My Vue.js Tutorial App
42 |
43 | Magically the browser will change its welcome message in a split second. Vue's tooling takes care of the update as long as `npm run dev` is running. The update is definitely way faster than in Angular.
44 |
45 | ## 4. Writing a new component
46 |
47 | Now lets try and hit the page `http://localhost:18080/#/about` in browser. Obviously there is no route mapped to the path. So all you see would be the Vue logo. This becomes apparent from the check list of files above. The router-view is not able to render anything for this path, so the page only shows the logo which is rendered by the App directly.
48 |
49 | Now its time to write a new component which will render something when we hit the about url `/about`. If you had examined the files in the above checklist, it is easy to guess what to change. The steps are simple:
50 |
51 | #### a. Assign a route:
52 |
53 | Add a new route in `src/route/index.js`
54 | ```
55 | {
56 | path: '/about',
57 | name: 'About',
58 | component: About
59 | }
60 | ```
61 | #### b. Write a new component:
62 | Obviously the router will not be able to find the component called About. So we write a new file called About.vue in `src/components` with the following contents.
63 |
64 | ```
65 |
66 |
67 |
{{ msg }}
68 |
69 |
70 |
80 | ```
81 |
82 | Now the `localhost:18080/#/about` page shows the line about our app. Why is the hideous # in our path? Wait, is it not possible to get clean old path like `localhost:18080/about` for our page?! For that just make the router use [history mode](https://router.vuejs.org/en/essentials/history-mode.html). But history mode comes with its own quirks. Be sure to stich up things for using such paths. We will continue our tutorial in the default mode(called hash mode after the hideous hash).
83 |
84 | ## 5. Composing Components
85 | Vue offers amazingly powerful ways to compose components(use one component in another). It's simplicity is like a fresh breathe of air coming from Angular world. Here let us try using the About component in our home page component(Hello component). All we have to do is tell Hello component that we are going to use the About component from so-and-so file using a custom element(similar to directive in Angular). And the simply use the custom element in the component template.
86 |
87 | So in the script section of Hello.vue, we import About and include it in components used by Hello like so:
88 | ```
89 |
97 | ```
98 | Now we can use element in Hello's template as many times as we want:
99 | ```
100 |
101 |
102 | ...
103 |
104 |
105 |
106 |
107 | ```
108 | And we already can see two identical `about` messages. But they are both showing the same boring message. What is the point of having subcomponents(called child components in documentation) if they can only ever bind to same data? It's like a class whose instances have all the same data. This is why Vue provides props.
109 |
110 | On a small detour, the Vue philosophy is [props down, events up](https://vuejs.org/v2/guide/components.html#Composing-Components) which means child components receive props from parents and then emit events back to parents. Thats it! A child cannot(or rather should not) access parent's data.
111 |
112 | So now we have to make our parent Hello component set props of About child components. Two steps:
113 |
114 | a. First, `About` component should explicitly declare the props it accepts. In About.vue, lets make `msg` a prop.
115 | ```
116 |
124 | ```
125 |
126 | b. The parent Hello component should pass on the prop values for each child component. In Hello.vue where we show about component, pass on msg as needed.
127 | ```
128 |
129 |
130 | ...
131 |
132 |
133 |
134 |
135 |
136 | ```
137 |
138 | That's it we have resused a component within another.
139 |
140 |
141 | ## Build Setup
142 |
143 | ``` bash
144 | # install dependencies
145 | npm install
146 |
147 | # serve with hot reload at localhost:8080
148 | npm run dev
149 |
150 | # build for production with minification
151 | npm run build
152 |
153 | # build for production and view the bundle analyzer report
154 | npm run build --report
155 |
156 | # run unit tests
157 | npm run unit
158 |
159 | # run e2e tests
160 | npm run e2e
161 |
162 | # run all tests
163 | npm test
164 | ```
165 |
166 | 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).
167 |
168 | ## A Note on File Structure
169 | Vue does not need cli and the file structure that it creates. We could simply source the vue.js from build or some CDN and write our own javascript to spin off Vue objects with routes. It is as simple as:
170 | ```
171 |
172 |
180 | ```
181 |
182 | Vue is not opinionated about the file organisation(unlike Angular where you better put components as suggested by the docs or face a hard time wiring them together). `vue-cli` and hence this tutorial is.
183 |
184 | ## End Note
185 | I have recently tried learning Vue 2.0 and wanted to see how the framework allows certain very specific things. Like, define a route, create component and use composition. Though I am satisfied with the framework beyond expectation, I faced a few question marks which blocked my way. These surprises probably should not waste time of others. This tutorial is for such friends who want to explore Vue fast from the basics they already know.
186 |
--------------------------------------------------------------------------------