diff --git a/.editorconfig b/.editorconfig
new file mode 100644
index 0000000000..94ce435b38
--- /dev/null
+++ b/.editorconfig
@@ -0,0 +1,7 @@
+[*]
+charset = utf-8
+indent_style = space
+indent_size = 2
+end_of_line = lf
+insert_final_newline = true
+trim_trailing_whitespace = true
diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md
new file mode 100644
index 0000000000..09f46ce8c4
--- /dev/null
+++ b/.github/pull_request_template.md
@@ -0,0 +1,3 @@
+Note
+====
+This repository is for Vue 1.x and 2.x only. Issues and pull requests related to 3.x are managed in the v3 doc repo: https://github.com/vuejs/docs-next.
diff --git a/.gitignore b/.gitignore
index 7c13a2dbcd..8b7ec505e3 100644
--- a/.gitignore
+++ b/.gitignore
@@ -6,3 +6,4 @@ node_modules/
public/
.deploy*/
src/_drafts
+package-lock.json
diff --git a/README.md b/README.md
index 52c0fbd096..bed7c6049c 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,13 @@
-# vuejs.org
+# v2.vuejs.org
+
+> Important: This repository is for Vue 1.x and 2.x only. Issues and pull requests related to 3.x are managed in the [v3 doc repo](https://github.com/vuejs/docs-next).
This site is built with [hexo](http://hexo.io/). Site content is written in Markdown format located in `src`. Pull requests welcome!
+## Writing
+
+See the [Vue Docs Writing Guide](https://github.com/vuejs/v2.vuejs.org/blob/master/writing-guide.md) for our rules and recommendations on writing and maintaining documentation.
+
## Developing
``` bash
@@ -17,13 +23,21 @@ If you are the maintainer of a community translation fork and would like to depl
## On Translations
-Translation for this documentation project are currently maintained in separate repositories forked from this original one.
+Translations for this documentation project are currently maintained in separate repositories forked from this original one.
+
+### Arabic
+
+Arabic translation is maintained by [Interstellar Club](https://github.com/InterstellarClub)
+
+* Translation Repo - [/interstellarClub/ar.vuejs.org](https://github.com/interstellarClub/ar.vuejs.org)
+* Primary Maintainers :
+ * [Ilyes Chouia](https://github.com/celyes)
+ * [Ahmed Aissaoui](https://github.com/Aissaoui-Ahmed)
### French
French translation is maintained by Vuejs-FR.
-
-* Translation Repo — [/vuejs-fr/vuejs.org](https://github.com/vuejs-fr/vuejs.org)
+* Translation Repo - [/vuejs-fr/vuejs.org](https://github.com/vuejs-fr/vuejs.org)
### Italian
@@ -38,6 +52,7 @@ Japanese translation is maintained by [Vue.js japan user group](https://github.c
* Secondary Maintainers:
* [re-fort](https://github.com/re-fort)
* [potato4d](https://github.com/potato4d)
+ * [oohira](https://github.com/oohira)
### Korean
@@ -50,6 +65,13 @@ Korean translation is maintained by [Vue.js Korean User group](https://github.co
* Translation Repo - [/vuejs/cn.vuejs.org](https://github.com/vuejs/cn.vuejs.org)
+### Persian (Farsi)
+
+Persian translation is maintained by VueJS-fa.
+
+* Translation Repo - [/vuejs-fa/fa.vuejs.org](https://github.com/vuejs-fa/fa.vuejs.org)
+* Primary maintainer - [Pooya Parsa](https://github.com/pi0)
+
### Português-Br
Português-Br translation is maintained by [Vuejs-Br](https://github.com/vuejs-br).
@@ -60,25 +82,47 @@ Português-Br translation is maintained by [Vuejs-Br](https://github.com/vuejs-b
Russian translation is maintained by Translation Gang.
-* Translation Repo — [/translation-gang/ru.vuejs.org](https://github.com/translation-gang/ru.vuejs.org)
+* Translation Repo - [/translation-gang/ru.vuejs.org](https://github.com/translation-gang/ru.vuejs.org)
* Primary maintainer - [Grigoriy Beziuk](https://gbezyuk.github.io)
### Spanish
-Spanish translation is maintained by VueJS-ES.
+* Translation Repo - [/1950Labs/vuejs.org](https://github.com/1950Labs/vuejs.org)
+* Spanish translation is maintained by:
-* Translation Repo - [/vuejs-es/vuejs.org](https://github.com/vuejs-es/vuejs.org)
+[1950Labs](https://1950labs.com) & [Vue.js Montevideo](https://www.meetup.com/Montevideo-Vue-JS-Meetup/):
-### Persian (Farsi)
+- [Leonel More](https://github.com/leonelmore) | [Twitter](https://twitter.com/leonelmore)
+- [Sebastián Camacho](https://github.com/sxcamacho) | [Twitter](https://twitter.com/sxcamacho)
+- [Diana Rodríguez](https://github.com/alphacentauri82) | [Twitter](https://twitter.com/cotufa82)
+- [Alejandro Parada](https://github.com/alejandro8605)
+- [José Javier Señaris](https://github.com/pepesenaris) | [Twitter](https://twitter.com/pepesenaris)
+- [Federico Kauffman](https://github.com/fedekau) | [Twitter](https://twitter.com/fedekauffman)
+- [Fabián Larrañaga](https://github.com/FLarra) | [Twitter](https://twitter.com/FLarraa)
+- [Pablo Marcano](https://github.com/Pablosky12) | [Twitter](https://twitter.com/stiv_ml)
+- [Nicolás Tinte](https://github.com/Tintef) | [Twitter](https://twitter.com/NicoTinte)
+- [Diego Barreiro](https://github.com/faliure)
+- [Matías Verdier](https://github.com/MatiasVerdier) | [Twitter](https://twitter.com/matiasvj)
+- [Pablo Kz](https://github.com/pabloKz)
+- [Leonardo Fagundez](https://github.com/lfgdzdev) | [Twitter](https://twitter.com/Lfgdz)
-Persian translation is maintained by VueJS-fa.
-* Translation Repo - [/vuejs-fa/fa.vuejs.org](https://github.com/vuejs-fa/fa.vuejs.org)
-* Primary maintainer - [Pooya Parsa](https://github.com/pi0)
+### Vietnamese
+
+Vietnamese translation is maintained by [Vue.js Vietnam User group](https://github.com/vuejs-vn/).
+
+* Translation Repo: [/vuejs-vn/vuejs.org](https://github.com/vuejs-vn/vuejs.org)
+* Primary maintainer - [phanan](https://github.com/phanan)
+
+### Bahasa Indonesia
+
+Bahasa Indonesia translation is maintained by [Vue.js Indonesia](https://github.com/vuejs-id/).
+
+* Translation Repo: [/vuejs-id/docs](https://github.com/vuejs-id/docs)
### Want to help with the translation?
-If you feel okay with translating sorta alone, you can fork the repo, create a "work-in-progress" issue to inform others that you're doing the translation, and go for it.
+If you feel okay with translating quite alone, you can fork the repo, post a comment on the [Community Translation Announcements](https://github.com/vuejs/v2.vuejs.org/issues/2015) issue page to inform others that you're doing the translation and go for it.
If you are more of a team player, Translation Gang might be for you. Let us know somehow that you're ready to join this international open-source translators community. Feel free to contact [Grigoriy Beziuk](https://gbezyuk.github.io) or anybody else from [the team](https://github.com/orgs/translation-gang/people).
diff --git a/_config.yml b/_config.yml
index 2eb260398d..38ce868cd3 100644
--- a/_config.yml
+++ b/_config.yml
@@ -1,6 +1,6 @@
# Hexo Configuration
-## Docs: http://zespia.tw/hexo/docs/configuration.html
-## Source: https://github.com/tommy351/hexo/
+## Docs: https://hexo.io/docs/
+## Source: https://github.com/hexojs/hexo
# Site
title: Vue.js
@@ -12,7 +12,7 @@ language:
# URL
## If your site is put in a subdirectory, set url as 'http://yoursite.com/child' and root as '/child/'
-url: https://vuejs.org
+url: https://v2.vuejs.org
root: /
permalink: :year/:month/:day/:title/
tag_dir: tags
@@ -29,7 +29,8 @@ new_post_name: :title.md # File name of new posts
default_layout: post
auto_spacing: false # Add spaces between asian characters and western characters
titlecase: false # Transform title into titlecase
-external_link: true # Open external links in new tab
+external_link:
+ enable: true # Open external links in new tab
max_open_file: 100
multi_thread: true
filename_case: 0
@@ -39,6 +40,7 @@ highlight:
enable: true
line_number: false
tab_replace:
+ hljs: true
# Category & Tag
default_category: uncategorized
@@ -76,9 +78,14 @@ pagination_dir: page
# Disqus
disqus_shortname:
+# Include/Exclude Files/Folders
+exclude:
+## Exclude example code from Nunjucks
+ - "v2/examples/vue-20-*/*"
+
# Extensions
-## Plugins: https://github.com/tommy351/hexo/wiki/Plugins
-## Themes: https://github.com/tommy351/hexo/wiki/Themes
+## Plugins: https://github.com/hexojs/hexo/wiki/Plugins
+## Themes: https://github.com/hexojs/hexo/wiki/Themes
theme: vue
exclude_generator:
@@ -96,49 +103,49 @@ markdown:
# Offline
## Config passed to sw-precache
## https://github.com/JLHwung/hexo-offline
-offline:
- maximumFileSizeToCacheInBytes: 10485760
- staticFileGlobs:
- - public/**/*.{js,html,css,png,jpg,jpeg,gif,svg,eot,ttf,woff,woff2,json,xml}
- stripPrefix: public
- verbose: true
- runtimeCaching:
- # Ad Sources - should be networkFirst
- - urlPattern: /*
- handler: networkFirst
- options:
- origin: sendgrid.sp1.convertro.com
- - urlPattern: /*
- handler: networkFirst
- options:
- origin: ad.doubleclick.net
- # CDNs - should be cacheFirst, since they should be used specific versions so should not change
- - urlPattern: /*
- handler: cacheFirst
- options:
- origin: cdn.jsdelivr.net
- - urlPattern: /*
- handler: cacheFirst
- options:
- origin: fonts.googleapis.com
- - urlPattern: /*
- handler: cacheFirst
- options:
- origin: fonts.gstatic.com
- - urlPattern: /*
- handler: cacheFirst
- options:
- origin: cdnjs.cloudflare.com
- - urlPattern: /*
- handler: cacheFirst
- options:
- origin: maxcdn.bootstrapcdn.com
+# offline:
+# maximumFileSizeToCacheInBytes: 10485760
+# staticFileGlobs:
+# - public/**/*.{js,html,css,png,jpg,jpeg,gif,svg,eot,ttf,woff,woff2,json,xml}
+# stripPrefix: public
+# verbose: true
+# runtimeCaching:
+# # Ad Sources - should be networkFirst
+# - urlPattern: /*
+# handler: networkFirst
+# options:
+# origin: sendgrid.sp1.convertro.com
+# - urlPattern: /*
+# handler: networkFirst
+# options:
+# origin: ad.doubleclick.net
+# # CDNs - should be cacheFirst, since they should be used specific versions so should not change
+# - urlPattern: /*
+# handler: cacheFirst
+# options:
+# origin: cdn.jsdelivr.net
+# - urlPattern: /*
+# handler: cacheFirst
+# options:
+# origin: fonts.googleapis.com
+# - urlPattern: /*
+# handler: cacheFirst
+# options:
+# origin: fonts.gstatic.com
+# - urlPattern: /*
+# handler: cacheFirst
+# options:
+# origin: cdnjs.cloudflare.com
+# - urlPattern: /*
+# handler: cacheFirst
+# options:
+# origin: maxcdn.bootstrapcdn.com
# Deployment
-## Docs: http://zespia.tw/hexo/docs/deployment.html
+## Docs: https://hexo.io/docs/one-command-deployment
deploy:
type: git
- repository: git@github.com:vuejs/vuejs.org.git
+ repository: git@github.com:vuejs/v2.vuejs.org.git
feed:
type: atom
@@ -187,4 +194,3 @@ alias:
examples/svg.html: v2/examples/svg.html
examples/todomvc.html: v2/examples/todomvc.html
examples/tree-view.html: v2/examples/tree-view.html
-
diff --git a/_scripts/pre-deploy.js b/_scripts/pre-deploy.js
new file mode 100644
index 0000000000..bf435118ed
--- /dev/null
+++ b/_scripts/pre-deploy.js
@@ -0,0 +1,61 @@
+// udpate to latest built files of Vue
+require('./sync-sponsors')
+
+const fs = require('fs')
+const zlib = require('zlib')
+const axios = require('axios')
+const execSync = require('child_process').execSync
+
+const themeconfPath = 'themes/vue/_config.yml'
+const installPath = 'src/v2/guide/installation.md'
+const themeconfig = fs.readFileSync(themeconfPath, 'utf-8')
+const installation = fs.readFileSync(installPath, 'utf-8')
+
+// get latest Vue version
+console.log(`Checking latest Vue version...`)
+const localVersion = themeconfig.match(/vue_version: (.*)/)[1]
+const version = execSync('npm view vue@v2-latest version').toString().trim()
+
+if (localVersion === version) {
+ console.log(`Version is up-to-date.`)
+ process.exit(0)
+}
+
+console.log(`Latest version: ${version}. Downloading dist files...`)
+
+// replace version in theme config
+fs.writeFileSync(
+ themeconfPath,
+ themeconfig.replace(/vue_version: .*/, 'vue_version: ' + version)
+)
+
+// grab it from unpkg
+Promise.all([download(`vue.js`), download(`vue.min.js`)])
+ .then(([devSize, prodSize]) => {
+ // replace installation page version and size
+ fs.writeFileSync(
+ installPath,
+ installation
+ .replace(/vue_version: .*/, 'vue_version: ' + version)
+ .replace(/gz_size:.*/g, `gz_size: "${prodSize}"`)
+ .replace(/\/vue@[\d\.]+/g, `/vue@${version}`)
+ )
+ console.log(
+ `\nSuccessfully updated Vue version (${version}) and gzip file size (${prodSize}kb).\n`
+ )
+ })
+ .catch((err) => {
+ console.error(err)
+ process.exit(1)
+ })
+
+function download(file) {
+ return axios({
+ url: `http://unpkg.com/vue@${version}/dist/${file}`,
+ method: 'get'
+ }).then((res) => {
+ fs.writeFileSync(`themes/vue/source/js/${file}`, res.data)
+ const zipped = zlib.gzipSync(Buffer.from(res.data))
+ return (zipped.length / 1024).toFixed(2)
+ })
+}
diff --git a/_scripts/sync-sponsors.js b/_scripts/sync-sponsors.js
new file mode 100644
index 0000000000..60c726da62
--- /dev/null
+++ b/_scripts/sync-sponsors.js
@@ -0,0 +1,18 @@
+// sync latest data from sponsor.vuejs.org
+const fs = require('fs')
+const path = require('path')
+const axios = require('axios')
+const yaml = require('js-yaml')
+
+const configPath = path.resolve(__dirname, '../themes/vue/_config.yml')
+
+;(async () => {
+ const { data } = await axios(`https://sponsors.vuejs.org/data.json`)
+ const yml = yaml.dump(data)
+ const config = fs.readFileSync(configPath, 'utf-8')
+ const updated = config.replace(
+ /(# START SPONSORS)[^]*(# END SPONSORS)/,
+ `$1\n${yml}$2`
+ )
+ fs.writeFileSync(configPath, updated)
+})()
diff --git a/assets/why-vue/arabic.js.srt b/assets/why-vue/arabic.js.srt
new file mode 100644
index 0000000000..af61b3d07c
--- /dev/null
+++ b/assets/why-vue/arabic.js.srt
@@ -0,0 +1,586 @@
+1
+00:00:00,000 --> 00:00:02,418
+- على مدى السنوات الـ10 الماضية
+أصبحت صفحات الويب الخاصة بنا
+
+2
+00:00:02,418 --> 00:00:05,600
+أكثر ديناميكية وقوة
+بفضل جافا سكريبت.
+
+3
+00:00:05,600 --> 00:00:07,541
+لقد قمنا بنقل الكثير من
+الأكواد التي كانت عادة في
+
+4
+00:00:07,541 --> 00:00:10,120
+جهة الخادوم إلى متصفحاتنا،
+
+5
+00:00:10,120 --> 00:00:13,051
+مما تركنا مع آلاف
+من أسطر رموز جافا سكريبت
+
+6
+00:00:13,051 --> 00:00:15,691
+مرتبطة بمختلف ملفات HTML و CSS
+
+7
+00:00:15,691 --> 00:00:17,821
+دون تنظيم رسمي.
+
+8
+00:00:17,821 --> 00:00:19,781
+هذا هو السبب وراء استخدام المزيد
+والمزيد من المطورين
+
+9
+00:00:19,781 --> 00:00:23,948
+أطر عمل جافا سكريبت
+مثل Angular أو React أو Vue.
+
+10
+00:00:24,821 --> 00:00:27,829
+Vue يسر التعامل
+فعال وعملي
+
+11
+00:00:27,829 --> 00:00:29,860
+و هو إطار جافا سكريبت
+يساعدك على إنشاء
+
+12
+00:00:29,860 --> 00:00:33,381
+كود أكثر قابلية للإصلاح وللإختبار.
+
+13
+00:00:33,381 --> 00:00:36,229
+Vue هو إطار عمل جافا سكريبت تقدمي،
+مما يعني أنه،
+
+14
+00:00:36,229 --> 00:00:38,621
+إذا كان لديك تطبيق
+يعمل على الخادوم.
+
+15
+00:00:38,621 --> 00:00:41,627
+يمكنك توصيل Vue
+في جزء من تطبيقك
+
+16
+00:00:41,627 --> 00:00:44,381
+الذي يحتاج إلى تجربة أكثر
+ثراء وتفاعل.
+
+17
+00:00:44,381 --> 00:00:46,269
+أو، إذا كنت ترغب في بناء
+واجهات ذات توجه تجاري
+
+18
+00:00:46,269 --> 00:00:48,240
+إلى واجهتك الأمامية من البداية،
+
+19
+00:00:48,240 --> 00:00:50,611
+فلدى Vue المكتبات الأساسية
+و النظام المتكامل
+
+20
+00:00:50,611 --> 00:00:52,421
+الذي تحتاج للتوسع.
+
+21
+00:00:52,421 --> 00:00:53,829
+مثل غيرها من أطر الواجهة الأمامية،
+
+22
+00:00:53,829 --> 00:00:55,960
+تسمح لك Vue بأخذ
+صفحة ويب وتقسيمها
+
+23
+00:00:55,960 --> 00:01:00,000
+إلى مكونات قابلة لإعادة الاستخدام،
+كل منها يحتوي على HTML،
+
+24
+00:01:00,000 --> 00:01:02,291
+CSS، و جافا سكريبت اللازمة لإستخراج
+
+25
+00:01:02,291 --> 00:01:04,269
+ذلك الجزء من الصفحة.
+
+26
+00:01:04,269 --> 00:01:06,260
+التالي، سنلقي نظرة
+على Vue عن كثب ب
+
+27
+00:01:06,260 --> 00:01:08,301
+بناء صفحة جرد منتج،
+
+28
+00:01:08,301 --> 00:01:10,187
+لكن ابقوا معنا حتى نهاية الفيديو
+
+29
+00:01:10,187 --> 00:01:13,571
+لرسالة من
+منشئ Vue، إيفان يوو.
+
+30
+00:01:13,571 --> 00:01:15,301
+لن نعلمك كيفية استخدام Vue،
+
+31
+00:01:15,301 --> 00:01:16,981
+لكننا سنقدم بعض المفاهيم الأساسية
+
+32
+00:01:16,981 --> 00:01:19,460
+التي تجعل من Vue مفيدة للغاية.
+
+33
+00:01:19,460 --> 00:01:21,200
+كما هو الحال مع العديد من تطبيقات جافا سكريبت،
+
+34
+00:01:21,200 --> 00:01:24,272
+نبدأ من الحاجة إلى
+عرض البيانات على صفحة الويب الخاصة بنا.
+
+35
+00:01:24,272 --> 00:01:26,591
+مع Vue، يبدأ الأمر بسهولة تامة.
+
+36
+00:01:26,591 --> 00:01:29,745
+نقوم بتضمين مكتبة Vue،
+إنشاء مثيل Vue،
+
+37
+00:01:29,745 --> 00:01:33,673
+و توصيله بالعنصر الأساسي
+بمعرّف التطبيق app.
+
+38
+00:01:33,673 --> 00:01:36,032
+EL تعني عُنصر وهي اختصار لكلمة element الإنجليزية.
+
+39
+00:01:36,032 --> 00:01:39,505
+سنقوم أيضًا بنقل بياناتنا داخل كائن
+
+40
+00:01:39,505 --> 00:01:41,993
+و تغيير X إلى صيغة برمجية
+
+41
+00:01:41,993 --> 00:01:44,544
+مع الأقواس المزدوجة المتعرجة.
+
+42
+00:01:44,544 --> 00:01:46,945
+كما ترون، إنه يعمل.
+
+43
+00:01:46,945 --> 00:01:50,695
+رائع جدًا، لكن سحر Vue
+يبدأ عندما تتغير البيانات.
+
+44
+00:01:50,695 --> 00:01:51,975
+إذا ذهبنا إلى سطر الأوامر،
+
+45
+00:01:51,975 --> 00:01:54,735
+سنقوم بتغيير قيمة منتجنا.
+
+46
+00:01:54,735 --> 00:01:57,324
+لاحظ أنه بمجرد
+تغير قيمة المنتج،
+
+47
+00:01:57,324 --> 00:01:59,953
+قام Vue بتحديث HTML الخاص بنا تلقائيًا.
+
+48
+00:01:59,953 --> 00:02:01,745
+هذا لأن Vue إطار تفاعلي،
+
+49
+00:02:01,745 --> 00:02:03,273
+يعني أنه عندما تتغير بياناتنا،
+
+50
+00:02:03,273 --> 00:02:05,193
+يهتم Vue بتحديث جميع الأماكن
+
+51
+00:02:05,193 --> 00:02:07,255
+التي نستخدمها في صفحة الويب الخاصة بنا.
+
+52
+00:02:07,255 --> 00:02:10,305
+هذا الأمر يعمل مع كافة أنواع البيانات،
+وليس النصوص فقط.
+
+53
+00:02:10,305 --> 00:02:11,604
+لذلك بدلا من منتج واحد،
+
+54
+00:02:11,604 --> 00:02:14,604
+دعونا نستخدم مجموعة من المنتجات.
+
+55
+00:02:14,604 --> 00:02:17,865
+ثم سنقوم بتحديث
+H2 إلى قائمة غير مرتبة،
+
+56
+00:02:17,865 --> 00:02:20,535
+و إنشاء عنصر قائمة جديد
+لكل منتج في المصفوفة
+
+57
+00:02:20,535 --> 00:02:22,618
+باستخدام التوجيه v-for لVue.
+
+58
+00:02:24,353 --> 00:02:26,615
+بهذه الطريقة، يحصل كل منتج
+على عنصر قائمة خاص به
+
+59
+00:02:26,615 --> 00:02:28,495
+كما ترون هنا.
+
+60
+00:02:28,495 --> 00:02:30,352
+لكن هذا لا يزال يبدو مختلق ذو بيانات معدة مسبقاً بعض الشيء.
+
+61
+00:02:30,352 --> 00:02:32,312
+لذلك دعونا نبدأ بقائمتنا فارغة
+
+62
+00:02:32,312 --> 00:02:34,815
+بعدها سنجلب أحدث منتجاتنا من واجهة برمجة تطبيقات حقيقية
+
+63
+00:02:34,815 --> 00:02:37,433
+التي يمكن أن تأتي
+من قاعدة بيانات في مكان ما.
+
+64
+00:02:37,433 --> 00:02:38,863
+عندما يتم إنشاء تطبيقنا،
+
+65
+00:02:38,863 --> 00:02:41,866
+سنجلب أحدث المنتجات
+من واجهة برمجة التطبيقات هذه.
+
+66
+00:02:41,866 --> 00:02:43,199
+كل ماعليك معرفته هنا هو أننا
+
+67
+00:02:43,199 --> 00:02:45,063
+نجلب قائمتنا من المنتجات
+
+68
+00:02:45,063 --> 00:02:46,923
+ومن ثم تحديثها في بياناتنا.
+
+69
+00:02:46,923 --> 00:02:48,281
+كما ترون على صفحة الويب لدينا،
+
+70
+00:02:48,281 --> 00:02:51,435
+كل عنصر قائمة يعرض
+الكائن الذي تم إرجاعه.
+
+71
+00:02:51,435 --> 00:02:53,474
+حسنا، يبدو أنه غير قابل للقراءة بعد،
+
+72
+00:02:53,474 --> 00:02:56,265
+لذلك دعونا نغير الطريقة التي يتم عرضها فيها.
+
+73
+00:02:56,265 --> 00:02:59,643
+سنقوم بطباعة الكمية والاسم.
+
+74
+00:02:59,643 --> 00:03:02,265
+و هاهو ذا، طبع بشكل جيد.
+
+75
+00:03:02,265 --> 00:03:03,563
+قد نرغب في لفت الانتباه إلى
+
+76
+00:03:03,563 --> 00:03:05,675
+العناصر التي لا تحتوي على كمية.
+
+77
+00:03:05,675 --> 00:03:09,595
+لذلك دعونا نضيف وسم span
+يحمل النص، منتهي من المخزون.
+
+78
+00:03:09,595 --> 00:03:13,334
+يجب أن يظهر هذا فقط إذا
+كانت كمية العنصر تساوي صفرًا.
+
+79
+00:03:13,334 --> 00:03:16,134
+سنستخدم التوجيه v-if.
+
+80
+00:03:16,134 --> 00:03:20,362
+لأن سترتنا لديها كمية
+صفر، فهي خارج المخزون.
+
+81
+00:03:20,362 --> 00:03:22,081
+ماذا لو أردنا
+طباعة الرقم الإجمالي
+
+82
+00:03:22,081 --> 00:03:24,641
+من المنتجات تحت قائمتنا؟
+
+83
+00:03:24,641 --> 00:03:26,468
+لجعل هذا يعمل، نحتاج إلى إنشاء
+
+84
+00:03:26,468 --> 00:03:29,570
+خاصية محسوبة تسمى totalProducts
+
+85
+00:03:29,570 --> 00:03:34,228
+و التي تعيد الكمية
+الإجمالية لمنتجاتنا.
+
+86
+00:03:34,228 --> 00:03:36,490
+إذا كنت غير معتاد
+على دالة reduce في جافا سكريبت،
+
+87
+00:03:36,490 --> 00:03:40,468
+فهي تجمع كل الكميات لكل منتج.
+
+88
+00:03:40,468 --> 00:03:41,851
+كما ترون، في متصفحنا،
+
+89
+00:03:41,851 --> 00:03:45,308
+فهي أضافت بشكل صحيح
+جميع الكميات.
+
+90
+00:03:45,308 --> 00:03:47,588
+هنا في المتصفح، أريد
+أن اريك إضافة Vue
+
+91
+00:03:47,588 --> 00:03:51,380
+لمتصفح Chrome حيث يمكننا
+مشاهدة مصفوفة بياناتنا
+
+92
+00:03:51,380 --> 00:03:53,547
+وفحصها هنا.
+
+93
+00:03:55,108 --> 00:03:57,460
+بما أننا في سطر الأوامر، وللمتعة فقط،
+
+94
+00:03:57,460 --> 00:03:59,850
+دعنا نلغي العنصر الأخير من المصفوفة
+
+95
+00:03:59,850 --> 00:04:01,828
+ونرى ما سيحدث.
+
+96
+00:04:01,828 --> 00:04:04,359
+كما ترى، لم يتم
+تحديث قائمتنا فقط،
+
+97
+00:04:04,359 --> 00:04:07,940
+ولكن مجموعنا كذلك، كما قد تأمل.
+
+98
+00:04:07,940 --> 00:04:10,410
+بعد ذلك، دعنا نضيف بعض
+التفاعل إلى هذه الصفحة
+
+99
+00:04:10,410 --> 00:04:12,346
+من خلال استخدام زر.
+
+100
+00:04:12,346 --> 00:04:14,490
+سنقوم بإنشاء و إضافة
+زر لكل منتج
+
+101
+00:04:14,490 --> 00:04:15,850
+وعند حدوث نقرة،
+
+102
+00:04:15,850 --> 00:04:18,850
+سنزيد الكمية بمقدار واحد.
+
+103
+00:04:19,959 --> 00:04:22,279
+بالعودة إلى المتصفح، لاحظ
+كيف أنه عندما نضيف عنصرًا،
+
+104
+00:04:22,279 --> 00:04:25,159
+لا يتم تحديث
+المخزون الإجمالي فقط،
+
+105
+00:04:25,159 --> 00:04:27,780
+ولكن أيضًا إذا قمنا بزيادة
+منتج السترة الخاص بنا،
+
+106
+00:04:27,780 --> 00:04:30,300
+فإن رسالة منتهي من المخزون تختفي.
+
+107
+00:04:30,300 --> 00:04:31,860
+النقر على هذا الزر مليون مرة
+
+108
+00:04:31,860 --> 00:04:33,890
+أمر متعب،
+لذلك ماذا لو أردنا
+
+109
+00:04:33,890 --> 00:04:37,719
+كتابة كمية
+السترات أو الجوارب؟
+
+110
+00:04:37,719 --> 00:04:40,580
+نقوم فقط بإنشاء حقل إدخال
+جديد و إلزامه بـ
+
+111
+00:04:40,580 --> 00:04:43,867
+حقل كمية المنتج
+بواسطة التوجيه v-model
+
+112
+00:04:43,867 --> 00:04:46,519
+و تحديد أنه دائمًا رقم.
+
+113
+00:04:46,519 --> 00:04:48,060
+ستلاحظ الآن، أنه يمكنني إدخال إجمالي
+
+114
+00:04:48,060 --> 00:04:52,450
+كمية كل عنصر و
+يتم تحديثها على الفور.
+
+115
+00:04:52,450 --> 00:04:54,500
+يمكنني حتى ضبط الكمية إلى الصفر
+
+116
+00:04:54,500 --> 00:04:57,899
+وأحصل على رسالة، انتهاء المخزون.
+
+117
+00:04:57,899 --> 00:05:01,232
+ولا تزال أزرار الإضافة تعمل على ما يرام.
+
+118
+00:05:02,259 --> 00:05:03,999
+إذا كنا نبني تطبيقا أكبر،
+
+119
+00:05:03,999 --> 00:05:05,839
+قد نرغب في تقسيم
+الأمور في هذه المرحلة
+
+120
+00:05:05,839 --> 00:05:09,290
+إلى المكونات والملفات الخاصة بهم.
+
+121
+00:05:09,290 --> 00:05:11,827
+لدى Vue واجهة سطر أوامر أيضا
+
+122
+00:05:11,827 --> 00:05:15,828
+مما يجعل من السهل
+بدء مشاريع حقيقية بسرعة.
+
+123
+00:05:15,828 --> 00:05:18,879
+يمكننا حتى استخدام
+مكونات الملف الواحد في Vue
+
+124
+00:05:18,879 --> 00:05:21,770
+الذي يحتوي على HTML، جافا سكريبت،
+
+125
+00:05:21,770 --> 00:05:23,687
+و Scoped CSS، أو SCSS.
+
+126
+00:05:25,599 --> 00:05:28,926
+- مرحبًا، أنا إيفان يو، منشئ Vue.js.
+
+127
+00:05:28,926 --> 00:05:31,587
+ما رأيته هنا
+بالكاد خدش سطح
+
+128
+00:05:31,587 --> 00:05:33,065
+ما يمكن لVue أن تفعله.
+
+129
+00:05:33,065 --> 00:05:34,856
+هناك أكثر من ذالك بكثير في النظام المتكامل
+
+130
+00:05:34,856 --> 00:05:36,555
+لمساعدتك في البناء، التنظيم،
+
+131
+00:05:36,555 --> 00:05:39,076
+و التوسع بتطبيقات الواجهة الأمامية الخاصة بك.
+
+132
+00:05:39,076 --> 00:05:42,457
+للحصول على فكرة أفضل وأشمل،
+اقرأ وثائقنا البرمجية اليوم.
+
+133
+00:05:42,457 --> 00:05:44,708
+أعتقد أنك ستستمتع بالعرض.
diff --git a/package-lock.json b/package-lock.json
deleted file mode 100644
index 048dfd31bc..0000000000
--- a/package-lock.json
+++ /dev/null
@@ -1,4116 +0,0 @@
-{
- "name": "vuejs.org",
- "version": "1.0.18",
- "lockfileVersion": 1,
- "requires": true,
- "dependencies": {
- "JSONStream": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.1.tgz",
- "integrity": "sha1-cH92HgHa6eFvG8+TcDt4xwlmV5o=",
- "requires": {
- "jsonparse": "1.3.1",
- "through": "2.3.8"
- }
- },
- "a-sync-waterfall": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/a-sync-waterfall/-/a-sync-waterfall-1.0.0.tgz",
- "integrity": "sha1-OOgxnXk3niRiiEW1O5ZyKyng5Hw="
- },
- "abab": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/abab/-/abab-1.0.4.tgz",
- "integrity": "sha1-X6rZwsB/YN12dw9xzwJbYqY8/U4=",
- "optional": true
- },
- "abbrev": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
- "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
- },
- "accepts": {
- "version": "1.3.4",
- "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.4.tgz",
- "integrity": "sha1-hiRnWMfdbSGmR0/whKR0DsBesh8=",
- "requires": {
- "mime-types": "2.1.16",
- "negotiator": "0.6.1"
- }
- },
- "acorn": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/acorn/-/acorn-2.7.0.tgz",
- "integrity": "sha1-q259nYhqrKiwhbwzEreaGYQz8Oc="
- },
- "acorn-globals": {
- "version": "1.0.9",
- "resolved": "https://registry.npmjs.org/acorn-globals/-/acorn-globals-1.0.9.tgz",
- "integrity": "sha1-VbtemGkVB7dFedBRNBMhfDgMVM8=",
- "optional": true,
- "requires": {
- "acorn": "2.7.0"
- }
- },
- "ajv": {
- "version": "5.5.0",
- "resolved": "https://registry.npmjs.org/ajv/-/ajv-5.5.0.tgz",
- "integrity": "sha1-6yhAdG6dxIvV4GOjbj/UAMXqtak=",
- "requires": {
- "co": "4.6.0",
- "fast-deep-equal": "1.0.0",
- "fast-json-stable-stringify": "2.0.0",
- "json-schema-traverse": "0.3.1"
- }
- },
- "amdefine": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz",
- "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU="
- },
- "ansi-align": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/ansi-align/-/ansi-align-1.1.0.tgz",
- "integrity": "sha1-LwwWWIKXOa3V67FeawxuNCPwFro=",
- "requires": {
- "string-width": "1.0.2"
- }
- },
- "ansi-regex": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
- },
- "ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4="
- },
- "anymatch": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-1.3.2.tgz",
- "integrity": "sha512-0XNayC8lTHQ2OI8aljNCN3sSx6hsr/1+rlcDAotXJR7C1oZZHCNsfpbKwMjRA3Uqb5tF1Rae2oloTr4xpq+WjA==",
- "requires": {
- "micromatch": "2.3.11",
- "normalize-path": "2.1.1"
- }
- },
- "archy": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz",
- "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA="
- },
- "argparse": {
- "version": "1.0.9",
- "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.9.tgz",
- "integrity": "sha1-c9g7wmP4bpf4zE9rrhsOkKfSLIY=",
- "requires": {
- "sprintf-js": "1.0.3"
- }
- },
- "arr-diff": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-2.0.0.tgz",
- "integrity": "sha1-jzuCf5Vai9ZpaX5KQlasPOrjVs8=",
- "requires": {
- "arr-flatten": "1.1.0"
- }
- },
- "arr-flatten": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
- "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg=="
- },
- "array-find-index": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz",
- "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E="
- },
- "array-unique": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.2.1.tgz",
- "integrity": "sha1-odl8yvy8JiXMcPrc6zalDFiwGlM="
- },
- "asap": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz",
- "integrity": "sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY="
- },
- "asn1": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.3.tgz",
- "integrity": "sha1-2sh4dxPJlmhJ/IGAd36+nB3fO4Y="
- },
- "assert-plus": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz",
- "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU="
- },
- "async": {
- "version": "0.2.10",
- "resolved": "https://registry.npmjs.org/async/-/async-0.2.10.tgz",
- "integrity": "sha1-trvgsGdLnXGXCMo43owjfLUmw9E="
- },
- "async-each": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz",
- "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0="
- },
- "asynckit": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz",
- "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k="
- },
- "aws-sign2": {
- "version": "0.7.0",
- "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz",
- "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg="
- },
- "aws4": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.6.0.tgz",
- "integrity": "sha1-g+9cqGCysy5KDe7e6MdxudtXRx4="
- },
- "babel-code-frame": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-code-frame/-/babel-code-frame-6.26.0.tgz",
- "integrity": "sha1-Y/1D99weO7fONZR9uP42mj9Yx0s=",
- "requires": {
- "chalk": "1.1.3",
- "esutils": "2.0.2",
- "js-tokens": "3.0.2"
- }
- },
- "babel-eslint": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/babel-eslint/-/babel-eslint-7.2.3.tgz",
- "integrity": "sha1-sv4tgBJkcPXBlELcdXJTqJdxCCc=",
- "requires": {
- "babel-code-frame": "6.26.0",
- "babel-traverse": "6.26.0",
- "babel-types": "6.26.0",
- "babylon": "6.18.0"
- }
- },
- "babel-messages": {
- "version": "6.23.0",
- "resolved": "https://registry.npmjs.org/babel-messages/-/babel-messages-6.23.0.tgz",
- "integrity": "sha1-8830cDhYA1sqKVHG7F7fbGLyYw4=",
- "requires": {
- "babel-runtime": "6.26.0"
- }
- },
- "babel-runtime": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-runtime/-/babel-runtime-6.26.0.tgz",
- "integrity": "sha1-llxwWGaOgrVde/4E/yM3vItWR/4=",
- "requires": {
- "core-js": "2.5.1",
- "regenerator-runtime": "0.11.0"
- },
- "dependencies": {
- "core-js": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/core-js/-/core-js-2.5.1.tgz",
- "integrity": "sha1-rmh03GaTd4m4B1T/VCjfZoGcpQs="
- }
- }
- },
- "babel-traverse": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-traverse/-/babel-traverse-6.26.0.tgz",
- "integrity": "sha1-RqnL1+3MYsjlwGTi0tjQ9ANXZu4=",
- "requires": {
- "babel-code-frame": "6.26.0",
- "babel-messages": "6.23.0",
- "babel-runtime": "6.26.0",
- "babel-types": "6.26.0",
- "babylon": "6.18.0",
- "debug": "2.6.9",
- "globals": "9.18.0",
- "invariant": "2.2.2",
- "lodash": "4.17.4"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.9",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
- "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
- "requires": {
- "ms": "2.0.0"
- }
- }
- }
- },
- "babel-types": {
- "version": "6.26.0",
- "resolved": "https://registry.npmjs.org/babel-types/-/babel-types-6.26.0.tgz",
- "integrity": "sha1-o7Bz+Uq0nrb6Vc1lInozQ4BjJJc=",
- "requires": {
- "babel-runtime": "6.26.0",
- "esutils": "2.0.2",
- "lodash": "4.17.4",
- "to-fast-properties": "1.0.3"
- }
- },
- "babylon": {
- "version": "6.18.0",
- "resolved": "https://registry.npmjs.org/babylon/-/babylon-6.18.0.tgz",
- "integrity": "sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ=="
- },
- "balanced-match": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
- "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
- },
- "basic-auth": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/basic-auth/-/basic-auth-1.1.0.tgz",
- "integrity": "sha1-RSIe5Cn37h5QNb4/UVM/HN/SmIQ="
- },
- "bcrypt-pbkdf": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.1.tgz",
- "integrity": "sha1-Y7xdy2EzG5K8Bf1SiVPDNGKgb40=",
- "optional": true,
- "requires": {
- "tweetnacl": "0.14.5"
- }
- },
- "binary-extensions": {
- "version": "1.11.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.11.0.tgz",
- "integrity": "sha1-RqoXUftqL5PuXmibsQh9SxTGwgU="
- },
- "bluebird": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.0.tgz",
- "integrity": "sha1-eRQg1/VR7qKJdFOop3ZT+WYG1nw="
- },
- "boolbase": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz",
- "integrity": "sha1-aN/1++YMUes3cl6p4+0xDcwed24="
- },
- "boom": {
- "version": "4.3.1",
- "resolved": "https://registry.npmjs.org/boom/-/boom-4.3.1.tgz",
- "integrity": "sha1-T4owBctKfjiJ90kDD9JbluAdLjE=",
- "requires": {
- "hoek": "4.2.0"
- }
- },
- "boxen": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/boxen/-/boxen-0.6.0.tgz",
- "integrity": "sha1-g2TUJIrDT/DvGy8r9JpsYM4NgbY=",
- "requires": {
- "ansi-align": "1.1.0",
- "camelcase": "2.1.1",
- "chalk": "1.1.3",
- "cli-boxes": "1.0.0",
- "filled-array": "1.1.0",
- "object-assign": "4.1.1",
- "repeating": "2.0.1",
- "string-width": "1.0.2",
- "widest-line": "1.0.0"
- }
- },
- "brace-expansion": {
- "version": "1.1.8",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.8.tgz",
- "integrity": "sha1-wHshHHyVLsH479Uad+8NHTmQopI=",
- "requires": {
- "balanced-match": "1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "braces": {
- "version": "1.8.5",
- "resolved": "https://registry.npmjs.org/braces/-/braces-1.8.5.tgz",
- "integrity": "sha1-uneWLhLf+WnWt2cR6RS3N4V79qc=",
- "requires": {
- "expand-range": "1.8.2",
- "preserve": "0.2.0",
- "repeat-element": "1.1.2"
- }
- },
- "browser-fingerprint": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/browser-fingerprint/-/browser-fingerprint-0.0.1.tgz",
- "integrity": "sha1-jfPNyiW/fVs1QtYVRdcwBT/OYEo="
- },
- "builtin-modules": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz",
- "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8="
- },
- "bytes": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-2.5.0.tgz",
- "integrity": "sha1-TJQj6i0lLCcMQbK97+/5u2tiwGo="
- },
- "camel-case": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/camel-case/-/camel-case-3.0.0.tgz",
- "integrity": "sha1-yjw2iKTpzzpM2nd9xNy8cTJJz3M=",
- "requires": {
- "no-case": "2.3.2",
- "upper-case": "1.1.3"
- }
- },
- "camelcase": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz",
- "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8="
- },
- "camelcase-keys": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz",
- "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=",
- "requires": {
- "camelcase": "2.1.1",
- "map-obj": "1.0.1"
- }
- },
- "capture-stack-trace": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/capture-stack-trace/-/capture-stack-trace-1.0.0.tgz",
- "integrity": "sha1-Sm+gc5nCa7pH8LJJa00PtAjFVQ0="
- },
- "caseless": {
- "version": "0.12.0",
- "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz",
- "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
- },
- "chalk": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=",
- "requires": {
- "ansi-styles": "2.2.1",
- "escape-string-regexp": "1.0.5",
- "has-ansi": "2.0.0",
- "strip-ansi": "3.0.1",
- "supports-color": "2.0.0"
- }
- },
- "cheerio": {
- "version": "0.20.0",
- "resolved": "https://registry.npmjs.org/cheerio/-/cheerio-0.20.0.tgz",
- "integrity": "sha1-XHEPK6uVZTJyhCugHG6mGzVF7DU=",
- "requires": {
- "css-select": "1.2.0",
- "dom-serializer": "0.1.0",
- "entities": "1.1.1",
- "htmlparser2": "3.8.3",
- "jsdom": "7.2.2",
- "lodash": "4.17.4"
- }
- },
- "chokidar": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-1.7.0.tgz",
- "integrity": "sha1-eY5ol3gVHIB2tLNg5e3SjNortGg=",
- "requires": {
- "anymatch": "1.3.2",
- "async-each": "1.0.1",
- "fsevents": "1.1.3",
- "glob-parent": "2.0.0",
- "inherits": "2.0.3",
- "is-binary-path": "1.0.1",
- "is-glob": "2.0.1",
- "path-is-absolute": "1.0.1",
- "readdirp": "2.1.0"
- }
- },
- "cli-boxes": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/cli-boxes/-/cli-boxes-1.0.0.tgz",
- "integrity": "sha1-T6kXw+WclKAEzWH47lCdplFocUM="
- },
- "cliui": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz",
- "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=",
- "requires": {
- "string-width": "1.0.2",
- "strip-ansi": "3.0.1",
- "wrap-ansi": "2.1.0"
- }
- },
- "co": {
- "version": "4.6.0",
- "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz",
- "integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
- },
- "code-point-at": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
- "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
- },
- "combined-stream": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.5.tgz",
- "integrity": "sha1-k4NwpXtKUd6ix3wV1cX9+JUWQAk=",
- "requires": {
- "delayed-stream": "1.0.0"
- }
- },
- "command-exists": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/command-exists/-/command-exists-1.2.2.tgz",
- "integrity": "sha1-EoGcZPr5VEbsCuB/5sr7brNwiyI="
- },
- "compressible": {
- "version": "2.0.11",
- "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.11.tgz",
- "integrity": "sha1-FnGKdd4oPtjmBAQWJaIGRYZ5fYo=",
- "requires": {
- "mime-db": "1.29.0"
- }
- },
- "compression": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.0.tgz",
- "integrity": "sha1-AwyfGY8WQ6BX13anOOki2kNzAS0=",
- "requires": {
- "accepts": "1.3.4",
- "bytes": "2.5.0",
- "compressible": "2.0.11",
- "debug": "2.6.8",
- "on-headers": "1.0.1",
- "safe-buffer": "5.1.1",
- "vary": "1.1.1"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.8",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
- "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
- "requires": {
- "ms": "2.0.0"
- }
- }
- }
- },
- "concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
- },
- "configstore": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/configstore/-/configstore-2.1.0.tgz",
- "integrity": "sha1-c3o6cDbpiGECqmCZ5HuzOrGroaE=",
- "requires": {
- "dot-prop": "3.0.0",
- "graceful-fs": "4.1.11",
- "mkdirp": "0.5.1",
- "object-assign": "4.1.1",
- "os-tmpdir": "1.0.2",
- "osenv": "0.1.4",
- "uuid": "2.0.3",
- "write-file-atomic": "1.3.4",
- "xdg-basedir": "2.0.0"
- },
- "dependencies": {
- "uuid": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-2.0.3.tgz",
- "integrity": "sha1-Z+LoY3lyFVMN/zGOW/nc6/1Hsho="
- }
- }
- },
- "connect": {
- "version": "3.6.3",
- "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.3.tgz",
- "integrity": "sha512-GLSZqgjVxPvGYVD/2vz//gS201MEXk4b7t3nHV6OVnTdDNWi/Gm7Rpxs/ybvljPWvULys/wrzIV3jB3YvEc3nQ==",
- "requires": {
- "debug": "2.6.8",
- "finalhandler": "1.0.4",
- "parseurl": "1.3.1",
- "utils-merge": "1.0.0"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.8",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
- "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
- "requires": {
- "ms": "2.0.0"
- }
- }
- }
- },
- "core-js": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/core-js/-/core-js-1.2.7.tgz",
- "integrity": "sha1-ZSKUwUZR2yj6k70tX/KYOk8IxjY="
- },
- "core-util-is": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
- },
- "create-error-class": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/create-error-class/-/create-error-class-3.0.2.tgz",
- "integrity": "sha1-Br56vvlHo/FKMP1hBnHUAbyot7Y=",
- "requires": {
- "capture-stack-trace": "1.0.0"
- }
- },
- "cross-spawn": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-4.0.2.tgz",
- "integrity": "sha1-e5JHYhwjrf3ThWAEqCPL45dCTUE=",
- "requires": {
- "lru-cache": "4.1.1",
- "which": "1.3.0"
- }
- },
- "cryptiles": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/cryptiles/-/cryptiles-3.1.2.tgz",
- "integrity": "sha1-qJ+7Ig9c4l7FboxKqKT9e1sNKf4=",
- "requires": {
- "boom": "5.2.0"
- },
- "dependencies": {
- "boom": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/boom/-/boom-5.2.0.tgz",
- "integrity": "sha512-Z5BTk6ZRe4tXXQlkqftmsAUANpXmuwlsF5Oov8ThoMbQRzdGTA1ngYRW160GexgOgjsFOKJz0LYhoNi+2AMBUw==",
- "requires": {
- "hoek": "4.2.0"
- }
- }
- }
- },
- "css-parse": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/css-parse/-/css-parse-1.7.0.tgz",
- "integrity": "sha1-Mh9s9zeCpv91ERE5D8BeLGV9jJs="
- },
- "css-select": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/css-select/-/css-select-1.2.0.tgz",
- "integrity": "sha1-KzoRBTnFNV8c2NMUYj6HCxIeyFg=",
- "requires": {
- "boolbase": "1.0.0",
- "css-what": "2.1.0",
- "domutils": "1.5.1",
- "nth-check": "1.0.1"
- }
- },
- "css-what": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/css-what/-/css-what-2.1.0.tgz",
- "integrity": "sha1-lGfQMsOM+u+58teVASUwYvh/ob0="
- },
- "cssom": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.3.2.tgz",
- "integrity": "sha1-uANhcMefB6kP8vFuIihAJ6JDhIs="
- },
- "cssstyle": {
- "version": "0.2.37",
- "resolved": "https://registry.npmjs.org/cssstyle/-/cssstyle-0.2.37.tgz",
- "integrity": "sha1-VBCXI0yyUTyDzu06zdwn/yeYfVQ=",
- "optional": true,
- "requires": {
- "cssom": "0.3.2"
- }
- },
- "cuid": {
- "version": "1.3.8",
- "resolved": "https://registry.npmjs.org/cuid/-/cuid-1.3.8.tgz",
- "integrity": "sha1-S4deCWm612T37AcGz0T1+wgx9rc=",
- "requires": {
- "browser-fingerprint": "0.0.1",
- "core-js": "1.2.7",
- "node-fingerprint": "0.0.2"
- }
- },
- "currently-unhandled": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz",
- "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=",
- "requires": {
- "array-find-index": "1.0.2"
- }
- },
- "dashdash": {
- "version": "1.14.1",
- "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz",
- "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=",
- "requires": {
- "assert-plus": "1.0.0"
- }
- },
- "debug": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/debug/-/debug-3.0.1.tgz",
- "integrity": "sha512-6nVc6S36qbt/mutyt+UGMnawAMrPDZUPQjRZI3FS9tCtDRhvxJbK79unYBLPi+z5SLXQ3ftoVBFCblQtNSls8w==",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "decamelize": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz",
- "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA="
- },
- "deep-assign": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/deep-assign/-/deep-assign-2.0.0.tgz",
- "integrity": "sha1-6+BrHwfwja5ZdiDj3RYi83GhxXI=",
- "requires": {
- "is-obj": "1.0.1"
- }
- },
- "deep-extend": {
- "version": "0.4.2",
- "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.4.2.tgz",
- "integrity": "sha1-SLaZwn4zS/ifEIkr5DL25MfTSn8="
- },
- "deep-is": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
- "integrity": "sha1-s2nW+128E+7PUk+RsHD+7cNXzzQ=",
- "optional": true
- },
- "delayed-stream": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
- "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
- },
- "depd": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.1.tgz",
- "integrity": "sha1-V4O04cRZ8G+lyif5kfPQbnoxA1k="
- },
- "destroy": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz",
- "integrity": "sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA="
- },
- "dom-serializer": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-0.1.0.tgz",
- "integrity": "sha1-BzxpdUbOB4DOI75KKOKT5AvDDII=",
- "requires": {
- "domelementtype": "1.1.3",
- "entities": "1.1.1"
- },
- "dependencies": {
- "domelementtype": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.1.3.tgz",
- "integrity": "sha1-vSh3PiZCiBrsUVRJJCmcXNgiGFs="
- }
- }
- },
- "dom-urls": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/dom-urls/-/dom-urls-1.1.0.tgz",
- "integrity": "sha1-AB3fgWKM0ecGElxxdvU8zsVdkY4=",
- "requires": {
- "urijs": "1.18.12"
- }
- },
- "domelementtype": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-1.3.0.tgz",
- "integrity": "sha1-sXrtguirWeUt2cGbF1bg/BhyBMI="
- },
- "domhandler": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-2.3.0.tgz",
- "integrity": "sha1-LeWaCCLVAn+r/28DLCsloqir5zg=",
- "requires": {
- "domelementtype": "1.3.0"
- }
- },
- "domutils": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/domutils/-/domutils-1.5.1.tgz",
- "integrity": "sha1-3NhIiib1Y9YQeeSMn3t+Mjc2gs8=",
- "requires": {
- "dom-serializer": "0.1.0",
- "domelementtype": "1.3.0"
- }
- },
- "dot-prop": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/dot-prop/-/dot-prop-3.0.0.tgz",
- "integrity": "sha1-G3CK8JSknJoOfbyteQq6U52sEXc=",
- "requires": {
- "is-obj": "1.0.1"
- }
- },
- "duplexer2": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz",
- "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=",
- "requires": {
- "readable-stream": "2.3.3"
- },
- "dependencies": {
- "isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
- },
- "readable-stream": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
- "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
- "requires": {
- "core-util-is": "1.0.2",
- "inherits": "2.0.3",
- "isarray": "1.0.0",
- "process-nextick-args": "1.0.7",
- "safe-buffer": "5.1.1",
- "string_decoder": "1.0.3",
- "util-deprecate": "1.0.2"
- }
- },
- "string_decoder": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
- "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
- "requires": {
- "safe-buffer": "5.1.1"
- }
- }
- }
- },
- "ecc-jsbn": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.1.tgz",
- "integrity": "sha1-D8c6ntXw1Tw4GTOYUj735UN3dQU=",
- "optional": true,
- "requires": {
- "jsbn": "0.1.1"
- }
- },
- "ee-first": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
- "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0="
- },
- "ejs": {
- "version": "2.5.7",
- "resolved": "https://registry.npmjs.org/ejs/-/ejs-2.5.7.tgz",
- "integrity": "sha1-zIcsFoiArjxxiXYv1f/ACJbJUYo="
- },
- "encodeurl": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.1.tgz",
- "integrity": "sha1-eePVhlU0aQn+bw9Fpd5oEDspTSA="
- },
- "entities": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/entities/-/entities-1.1.1.tgz",
- "integrity": "sha1-blwtClYhtdra7O+AuQ7ftc13cvA="
- },
- "error-ex": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.1.tgz",
- "integrity": "sha1-+FWobOYa3E6GIcPNoh56dhLDqNw=",
- "requires": {
- "is-arrayish": "0.2.1"
- }
- },
- "es6-promise": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.1.1.tgz",
- "integrity": "sha512-OaU1hHjgJf+b0NzsxCg7NdIYERD6Hy/PEmFLTjw+b65scuisG3Kt4QoTvJ66BBkPZ581gr0kpoVzKnxniM8nng=="
- },
- "escape-html": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
- "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg="
- },
- "escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ="
- },
- "escodegen": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-1.9.0.tgz",
- "integrity": "sha512-v0MYvNQ32bzwoG2OSFzWAkuahDQHK92JBN0pTAALJ4RIxEZe766QJPDR8Hqy7XNUy5K3fnVL76OqYAdc4TZEIw==",
- "optional": true,
- "requires": {
- "esprima": "3.1.3",
- "estraverse": "4.2.0",
- "esutils": "2.0.2",
- "optionator": "0.8.2",
- "source-map": "0.5.7"
- }
- },
- "esprima": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-3.1.3.tgz",
- "integrity": "sha1-/cpRzuYTOJXjyI1TXOSdv/YqRjM=",
- "optional": true
- },
- "estraverse": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.2.0.tgz",
- "integrity": "sha1-De4/7TH81GlhjOc0IJn8GvoL2xM=",
- "optional": true
- },
- "esutils": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.2.tgz",
- "integrity": "sha1-Cr9PHKpbyx96nYrMbepPqqBLrJs="
- },
- "etag": {
- "version": "1.8.0",
- "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.0.tgz",
- "integrity": "sha1-b2Ma7zNtbEY2K1F2QETOIWvjwFE="
- },
- "expand-brackets": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-0.1.5.tgz",
- "integrity": "sha1-3wcoTjQqgHzXM6xa9yQR5YHRF3s=",
- "requires": {
- "is-posix-bracket": "0.1.1"
- }
- },
- "expand-range": {
- "version": "1.8.2",
- "resolved": "https://registry.npmjs.org/expand-range/-/expand-range-1.8.2.tgz",
- "integrity": "sha1-opnv/TNf4nIeuujiV+x5ZE/IUzc=",
- "requires": {
- "fill-range": "2.2.3"
- }
- },
- "extend": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.1.tgz",
- "integrity": "sha1-p1Xqe8Gt/MWjHOfnYtuq3F5jZEQ="
- },
- "extglob": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/extglob/-/extglob-0.3.2.tgz",
- "integrity": "sha1-Lhj/PS9JqydlzskCPwEdqo2DSaE=",
- "requires": {
- "is-extglob": "1.0.0"
- }
- },
- "extsprintf": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz",
- "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU="
- },
- "fast-deep-equal": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-1.0.0.tgz",
- "integrity": "sha1-liVqO8l1WV6zbYLpkp0GDYk0Of8="
- },
- "fast-json-stable-stringify": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz",
- "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I="
- },
- "fast-levenshtein": {
- "version": "2.0.6",
- "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz",
- "integrity": "sha1-PYpcZog6FqMMqGQ+hR8Zuqd5eRc=",
- "optional": true
- },
- "filename-regex": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/filename-regex/-/filename-regex-2.0.1.tgz",
- "integrity": "sha1-wcS5vuPglyXdsQa3XB4wH+LxiyY="
- },
- "fill-range": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-2.2.3.tgz",
- "integrity": "sha1-ULd9/X5Gm8dJJHCWNpn+eoSFpyM=",
- "requires": {
- "is-number": "2.1.0",
- "isobject": "2.1.0",
- "randomatic": "1.1.7",
- "repeat-element": "1.1.2",
- "repeat-string": "1.6.1"
- }
- },
- "filled-array": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/filled-array/-/filled-array-1.1.0.tgz",
- "integrity": "sha1-w8T2xmO5I0WamqKZEtLQMfFQf4Q="
- },
- "finalhandler": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.0.4.tgz",
- "integrity": "sha512-16l/r8RgzlXKmFOhZpHBztvye+lAhC5SU7hXavnerC9UfZqZxxXl3BzL8MhffPT3kF61lj9Oav2LKEzh0ei7tg==",
- "requires": {
- "debug": "2.6.8",
- "encodeurl": "1.0.1",
- "escape-html": "1.0.3",
- "on-finished": "2.3.0",
- "parseurl": "1.3.1",
- "statuses": "1.3.1",
- "unpipe": "1.0.0"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.8",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
- "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
- "requires": {
- "ms": "2.0.0"
- }
- }
- }
- },
- "find-up": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz",
- "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=",
- "requires": {
- "path-exists": "2.1.0",
- "pinkie-promise": "2.0.1"
- }
- },
- "for-in": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
- "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA="
- },
- "for-own": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/for-own/-/for-own-0.1.5.tgz",
- "integrity": "sha1-UmXGgaTylNq78XyVCbZ2OqhFEM4=",
- "requires": {
- "for-in": "1.0.2"
- }
- },
- "forever-agent": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz",
- "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE="
- },
- "form-data": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.1.tgz",
- "integrity": "sha1-b7lPvXGIUwbXPRXMSX/kzE7NRL8=",
- "requires": {
- "asynckit": "0.4.0",
- "combined-stream": "1.0.5",
- "mime-types": "2.1.16"
- }
- },
- "fresh": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.0.tgz",
- "integrity": "sha1-9HTKXmqSRtb9jglTz6m5yAWvp44="
- },
- "fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
- },
- "fsevents": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.1.3.tgz",
- "integrity": "sha512-WIr7iDkdmdbxu/Gh6eKEZJL6KPE74/5MEsf2whTOFNxbIoIixogroLdKYqB6FDav4Wavh/lZdzzd3b2KxIXC5Q==",
- "optional": true,
- "requires": {
- "nan": "2.8.0",
- "node-pre-gyp": "0.6.39"
- },
- "dependencies": {
- "abbrev": {
- "version": "1.1.0",
- "bundled": true,
- "optional": true
- },
- "ajv": {
- "version": "4.11.8",
- "bundled": true,
- "optional": true,
- "requires": {
- "co": "4.6.0",
- "json-stable-stringify": "1.0.1"
- }
- },
- "ansi-regex": {
- "version": "2.1.1",
- "bundled": true
- },
- "aproba": {
- "version": "1.1.1",
- "bundled": true,
- "optional": true
- },
- "are-we-there-yet": {
- "version": "1.1.4",
- "bundled": true,
- "optional": true,
- "requires": {
- "delegates": "1.0.0",
- "readable-stream": "2.2.9"
- }
- },
- "asn1": {
- "version": "0.2.3",
- "bundled": true,
- "optional": true
- },
- "assert-plus": {
- "version": "0.2.0",
- "bundled": true,
- "optional": true
- },
- "asynckit": {
- "version": "0.4.0",
- "bundled": true,
- "optional": true
- },
- "aws-sign2": {
- "version": "0.6.0",
- "bundled": true,
- "optional": true
- },
- "aws4": {
- "version": "1.6.0",
- "bundled": true,
- "optional": true
- },
- "balanced-match": {
- "version": "0.4.2",
- "bundled": true
- },
- "bcrypt-pbkdf": {
- "version": "1.0.1",
- "bundled": true,
- "optional": true,
- "requires": {
- "tweetnacl": "0.14.5"
- }
- },
- "block-stream": {
- "version": "0.0.9",
- "bundled": true,
- "requires": {
- "inherits": "2.0.3"
- }
- },
- "boom": {
- "version": "2.10.1",
- "bundled": true,
- "requires": {
- "hoek": "2.16.3"
- }
- },
- "brace-expansion": {
- "version": "1.1.7",
- "bundled": true,
- "requires": {
- "balanced-match": "0.4.2",
- "concat-map": "0.0.1"
- }
- },
- "buffer-shims": {
- "version": "1.0.0",
- "bundled": true
- },
- "caseless": {
- "version": "0.12.0",
- "bundled": true,
- "optional": true
- },
- "co": {
- "version": "4.6.0",
- "bundled": true,
- "optional": true
- },
- "code-point-at": {
- "version": "1.1.0",
- "bundled": true
- },
- "combined-stream": {
- "version": "1.0.5",
- "bundled": true,
- "requires": {
- "delayed-stream": "1.0.0"
- }
- },
- "concat-map": {
- "version": "0.0.1",
- "bundled": true
- },
- "console-control-strings": {
- "version": "1.1.0",
- "bundled": true
- },
- "core-util-is": {
- "version": "1.0.2",
- "bundled": true
- },
- "cryptiles": {
- "version": "2.0.5",
- "bundled": true,
- "requires": {
- "boom": "2.10.1"
- }
- },
- "dashdash": {
- "version": "1.14.1",
- "bundled": true,
- "optional": true,
- "requires": {
- "assert-plus": "1.0.0"
- },
- "dependencies": {
- "assert-plus": {
- "version": "1.0.0",
- "bundled": true,
- "optional": true
- }
- }
- },
- "debug": {
- "version": "2.6.8",
- "bundled": true,
- "optional": true,
- "requires": {
- "ms": "2.0.0"
- }
- },
- "deep-extend": {
- "version": "0.4.2",
- "bundled": true,
- "optional": true
- },
- "delayed-stream": {
- "version": "1.0.0",
- "bundled": true
- },
- "delegates": {
- "version": "1.0.0",
- "bundled": true,
- "optional": true
- },
- "detect-libc": {
- "version": "1.0.2",
- "bundled": true,
- "optional": true
- },
- "ecc-jsbn": {
- "version": "0.1.1",
- "bundled": true,
- "optional": true,
- "requires": {
- "jsbn": "0.1.1"
- }
- },
- "extend": {
- "version": "3.0.1",
- "bundled": true,
- "optional": true
- },
- "extsprintf": {
- "version": "1.0.2",
- "bundled": true
- },
- "forever-agent": {
- "version": "0.6.1",
- "bundled": true,
- "optional": true
- },
- "form-data": {
- "version": "2.1.4",
- "bundled": true,
- "optional": true,
- "requires": {
- "asynckit": "0.4.0",
- "combined-stream": "1.0.5",
- "mime-types": "2.1.15"
- }
- },
- "fs.realpath": {
- "version": "1.0.0",
- "bundled": true
- },
- "fstream": {
- "version": "1.0.11",
- "bundled": true,
- "requires": {
- "graceful-fs": "4.1.11",
- "inherits": "2.0.3",
- "mkdirp": "0.5.1",
- "rimraf": "2.6.1"
- }
- },
- "fstream-ignore": {
- "version": "1.0.5",
- "bundled": true,
- "optional": true,
- "requires": {
- "fstream": "1.0.11",
- "inherits": "2.0.3",
- "minimatch": "3.0.4"
- }
- },
- "gauge": {
- "version": "2.7.4",
- "bundled": true,
- "optional": true,
- "requires": {
- "aproba": "1.1.1",
- "console-control-strings": "1.1.0",
- "has-unicode": "2.0.1",
- "object-assign": "4.1.1",
- "signal-exit": "3.0.2",
- "string-width": "1.0.2",
- "strip-ansi": "3.0.1",
- "wide-align": "1.1.2"
- }
- },
- "getpass": {
- "version": "0.1.7",
- "bundled": true,
- "optional": true,
- "requires": {
- "assert-plus": "1.0.0"
- },
- "dependencies": {
- "assert-plus": {
- "version": "1.0.0",
- "bundled": true,
- "optional": true
- }
- }
- },
- "glob": {
- "version": "7.1.2",
- "bundled": true,
- "requires": {
- "fs.realpath": "1.0.0",
- "inflight": "1.0.6",
- "inherits": "2.0.3",
- "minimatch": "3.0.4",
- "once": "1.4.0",
- "path-is-absolute": "1.0.1"
- }
- },
- "graceful-fs": {
- "version": "4.1.11",
- "bundled": true
- },
- "har-schema": {
- "version": "1.0.5",
- "bundled": true,
- "optional": true
- },
- "har-validator": {
- "version": "4.2.1",
- "bundled": true,
- "optional": true,
- "requires": {
- "ajv": "4.11.8",
- "har-schema": "1.0.5"
- }
- },
- "has-unicode": {
- "version": "2.0.1",
- "bundled": true,
- "optional": true
- },
- "hawk": {
- "version": "3.1.3",
- "bundled": true,
- "requires": {
- "boom": "2.10.1",
- "cryptiles": "2.0.5",
- "hoek": "2.16.3",
- "sntp": "1.0.9"
- }
- },
- "hoek": {
- "version": "2.16.3",
- "bundled": true
- },
- "http-signature": {
- "version": "1.1.1",
- "bundled": true,
- "optional": true,
- "requires": {
- "assert-plus": "0.2.0",
- "jsprim": "1.4.0",
- "sshpk": "1.13.0"
- }
- },
- "inflight": {
- "version": "1.0.6",
- "bundled": true,
- "requires": {
- "once": "1.4.0",
- "wrappy": "1.0.2"
- }
- },
- "inherits": {
- "version": "2.0.3",
- "bundled": true
- },
- "ini": {
- "version": "1.3.4",
- "bundled": true,
- "optional": true
- },
- "is-fullwidth-code-point": {
- "version": "1.0.0",
- "bundled": true,
- "requires": {
- "number-is-nan": "1.0.1"
- }
- },
- "is-typedarray": {
- "version": "1.0.0",
- "bundled": true,
- "optional": true
- },
- "isarray": {
- "version": "1.0.0",
- "bundled": true
- },
- "isstream": {
- "version": "0.1.2",
- "bundled": true,
- "optional": true
- },
- "jodid25519": {
- "version": "1.0.2",
- "bundled": true,
- "optional": true,
- "requires": {
- "jsbn": "0.1.1"
- }
- },
- "jsbn": {
- "version": "0.1.1",
- "bundled": true,
- "optional": true
- },
- "json-schema": {
- "version": "0.2.3",
- "bundled": true,
- "optional": true
- },
- "json-stable-stringify": {
- "version": "1.0.1",
- "bundled": true,
- "optional": true,
- "requires": {
- "jsonify": "0.0.0"
- }
- },
- "json-stringify-safe": {
- "version": "5.0.1",
- "bundled": true,
- "optional": true
- },
- "jsonify": {
- "version": "0.0.0",
- "bundled": true,
- "optional": true
- },
- "jsprim": {
- "version": "1.4.0",
- "bundled": true,
- "optional": true,
- "requires": {
- "assert-plus": "1.0.0",
- "extsprintf": "1.0.2",
- "json-schema": "0.2.3",
- "verror": "1.3.6"
- },
- "dependencies": {
- "assert-plus": {
- "version": "1.0.0",
- "bundled": true,
- "optional": true
- }
- }
- },
- "mime-db": {
- "version": "1.27.0",
- "bundled": true
- },
- "mime-types": {
- "version": "2.1.15",
- "bundled": true,
- "requires": {
- "mime-db": "1.27.0"
- }
- },
- "minimatch": {
- "version": "3.0.4",
- "bundled": true,
- "requires": {
- "brace-expansion": "1.1.7"
- }
- },
- "minimist": {
- "version": "0.0.8",
- "bundled": true
- },
- "mkdirp": {
- "version": "0.5.1",
- "bundled": true,
- "requires": {
- "minimist": "0.0.8"
- }
- },
- "ms": {
- "version": "2.0.0",
- "bundled": true,
- "optional": true
- },
- "node-pre-gyp": {
- "version": "0.6.39",
- "bundled": true,
- "optional": true,
- "requires": {
- "detect-libc": "1.0.2",
- "hawk": "3.1.3",
- "mkdirp": "0.5.1",
- "nopt": "4.0.1",
- "npmlog": "4.1.0",
- "rc": "1.2.1",
- "request": "2.81.0",
- "rimraf": "2.6.1",
- "semver": "5.3.0",
- "tar": "2.2.1",
- "tar-pack": "3.4.0"
- }
- },
- "nopt": {
- "version": "4.0.1",
- "bundled": true,
- "optional": true,
- "requires": {
- "abbrev": "1.1.0",
- "osenv": "0.1.4"
- }
- },
- "npmlog": {
- "version": "4.1.0",
- "bundled": true,
- "optional": true,
- "requires": {
- "are-we-there-yet": "1.1.4",
- "console-control-strings": "1.1.0",
- "gauge": "2.7.4",
- "set-blocking": "2.0.0"
- }
- },
- "number-is-nan": {
- "version": "1.0.1",
- "bundled": true
- },
- "oauth-sign": {
- "version": "0.8.2",
- "bundled": true,
- "optional": true
- },
- "object-assign": {
- "version": "4.1.1",
- "bundled": true,
- "optional": true
- },
- "once": {
- "version": "1.4.0",
- "bundled": true,
- "requires": {
- "wrappy": "1.0.2"
- }
- },
- "os-homedir": {
- "version": "1.0.2",
- "bundled": true,
- "optional": true
- },
- "os-tmpdir": {
- "version": "1.0.2",
- "bundled": true,
- "optional": true
- },
- "osenv": {
- "version": "0.1.4",
- "bundled": true,
- "optional": true,
- "requires": {
- "os-homedir": "1.0.2",
- "os-tmpdir": "1.0.2"
- }
- },
- "path-is-absolute": {
- "version": "1.0.1",
- "bundled": true
- },
- "performance-now": {
- "version": "0.2.0",
- "bundled": true,
- "optional": true
- },
- "process-nextick-args": {
- "version": "1.0.7",
- "bundled": true
- },
- "punycode": {
- "version": "1.4.1",
- "bundled": true,
- "optional": true
- },
- "qs": {
- "version": "6.4.0",
- "bundled": true,
- "optional": true
- },
- "rc": {
- "version": "1.2.1",
- "bundled": true,
- "optional": true,
- "requires": {
- "deep-extend": "0.4.2",
- "ini": "1.3.4",
- "minimist": "1.2.0",
- "strip-json-comments": "2.0.1"
- },
- "dependencies": {
- "minimist": {
- "version": "1.2.0",
- "bundled": true,
- "optional": true
- }
- }
- },
- "readable-stream": {
- "version": "2.2.9",
- "bundled": true,
- "requires": {
- "buffer-shims": "1.0.0",
- "core-util-is": "1.0.2",
- "inherits": "2.0.3",
- "isarray": "1.0.0",
- "process-nextick-args": "1.0.7",
- "string_decoder": "1.0.1",
- "util-deprecate": "1.0.2"
- }
- },
- "request": {
- "version": "2.81.0",
- "bundled": true,
- "optional": true,
- "requires": {
- "aws-sign2": "0.6.0",
- "aws4": "1.6.0",
- "caseless": "0.12.0",
- "combined-stream": "1.0.5",
- "extend": "3.0.1",
- "forever-agent": "0.6.1",
- "form-data": "2.1.4",
- "har-validator": "4.2.1",
- "hawk": "3.1.3",
- "http-signature": "1.1.1",
- "is-typedarray": "1.0.0",
- "isstream": "0.1.2",
- "json-stringify-safe": "5.0.1",
- "mime-types": "2.1.15",
- "oauth-sign": "0.8.2",
- "performance-now": "0.2.0",
- "qs": "6.4.0",
- "safe-buffer": "5.0.1",
- "stringstream": "0.0.5",
- "tough-cookie": "2.3.2",
- "tunnel-agent": "0.6.0",
- "uuid": "3.0.1"
- }
- },
- "rimraf": {
- "version": "2.6.1",
- "bundled": true,
- "requires": {
- "glob": "7.1.2"
- }
- },
- "safe-buffer": {
- "version": "5.0.1",
- "bundled": true
- },
- "semver": {
- "version": "5.3.0",
- "bundled": true,
- "optional": true
- },
- "set-blocking": {
- "version": "2.0.0",
- "bundled": true,
- "optional": true
- },
- "signal-exit": {
- "version": "3.0.2",
- "bundled": true,
- "optional": true
- },
- "sntp": {
- "version": "1.0.9",
- "bundled": true,
- "requires": {
- "hoek": "2.16.3"
- }
- },
- "sshpk": {
- "version": "1.13.0",
- "bundled": true,
- "optional": true,
- "requires": {
- "asn1": "0.2.3",
- "assert-plus": "1.0.0",
- "bcrypt-pbkdf": "1.0.1",
- "dashdash": "1.14.1",
- "ecc-jsbn": "0.1.1",
- "getpass": "0.1.7",
- "jodid25519": "1.0.2",
- "jsbn": "0.1.1",
- "tweetnacl": "0.14.5"
- },
- "dependencies": {
- "assert-plus": {
- "version": "1.0.0",
- "bundled": true,
- "optional": true
- }
- }
- },
- "string-width": {
- "version": "1.0.2",
- "bundled": true,
- "requires": {
- "code-point-at": "1.1.0",
- "is-fullwidth-code-point": "1.0.0",
- "strip-ansi": "3.0.1"
- }
- },
- "string_decoder": {
- "version": "1.0.1",
- "bundled": true,
- "requires": {
- "safe-buffer": "5.0.1"
- }
- },
- "stringstream": {
- "version": "0.0.5",
- "bundled": true,
- "optional": true
- },
- "strip-ansi": {
- "version": "3.0.1",
- "bundled": true,
- "requires": {
- "ansi-regex": "2.1.1"
- }
- },
- "strip-json-comments": {
- "version": "2.0.1",
- "bundled": true,
- "optional": true
- },
- "tar": {
- "version": "2.2.1",
- "bundled": true,
- "requires": {
- "block-stream": "0.0.9",
- "fstream": "1.0.11",
- "inherits": "2.0.3"
- }
- },
- "tar-pack": {
- "version": "3.4.0",
- "bundled": true,
- "optional": true,
- "requires": {
- "debug": "2.6.8",
- "fstream": "1.0.11",
- "fstream-ignore": "1.0.5",
- "once": "1.4.0",
- "readable-stream": "2.2.9",
- "rimraf": "2.6.1",
- "tar": "2.2.1",
- "uid-number": "0.0.6"
- }
- },
- "tough-cookie": {
- "version": "2.3.2",
- "bundled": true,
- "optional": true,
- "requires": {
- "punycode": "1.4.1"
- }
- },
- "tunnel-agent": {
- "version": "0.6.0",
- "bundled": true,
- "optional": true,
- "requires": {
- "safe-buffer": "5.0.1"
- }
- },
- "tweetnacl": {
- "version": "0.14.5",
- "bundled": true,
- "optional": true
- },
- "uid-number": {
- "version": "0.0.6",
- "bundled": true,
- "optional": true
- },
- "util-deprecate": {
- "version": "1.0.2",
- "bundled": true
- },
- "uuid": {
- "version": "3.0.1",
- "bundled": true,
- "optional": true
- },
- "verror": {
- "version": "1.3.6",
- "bundled": true,
- "optional": true,
- "requires": {
- "extsprintf": "1.0.2"
- }
- },
- "wide-align": {
- "version": "1.1.2",
- "bundled": true,
- "optional": true,
- "requires": {
- "string-width": "1.0.2"
- }
- },
- "wrappy": {
- "version": "1.0.2",
- "bundled": true
- }
- }
- },
- "get-stdin": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz",
- "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4="
- },
- "getpass": {
- "version": "0.1.7",
- "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz",
- "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=",
- "requires": {
- "assert-plus": "1.0.0"
- }
- },
- "glob": {
- "version": "6.0.4",
- "resolved": "https://registry.npmjs.org/glob/-/glob-6.0.4.tgz",
- "integrity": "sha1-DwiGD2oVUSey+t1PnOJLGqtuTSI=",
- "optional": true,
- "requires": {
- "inflight": "1.0.6",
- "inherits": "2.0.3",
- "minimatch": "3.0.4",
- "once": "1.4.0",
- "path-is-absolute": "1.0.1"
- }
- },
- "glob-base": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/glob-base/-/glob-base-0.3.0.tgz",
- "integrity": "sha1-27Fk9iIbHAscz4Kuoyi0l98Oo8Q=",
- "requires": {
- "glob-parent": "2.0.0",
- "is-glob": "2.0.1"
- }
- },
- "glob-parent": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-2.0.0.tgz",
- "integrity": "sha1-gTg9ctsFT8zPUzbaqQLxgvbtuyg=",
- "requires": {
- "is-glob": "2.0.1"
- }
- },
- "globals": {
- "version": "9.18.0",
- "resolved": "https://registry.npmjs.org/globals/-/globals-9.18.0.tgz",
- "integrity": "sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ=="
- },
- "got": {
- "version": "5.7.1",
- "resolved": "https://registry.npmjs.org/got/-/got-5.7.1.tgz",
- "integrity": "sha1-X4FjWmHkplifGAVp6k44FoClHzU=",
- "requires": {
- "create-error-class": "3.0.2",
- "duplexer2": "0.1.4",
- "is-redirect": "1.0.0",
- "is-retry-allowed": "1.1.0",
- "is-stream": "1.1.0",
- "lowercase-keys": "1.0.0",
- "node-status-codes": "1.0.0",
- "object-assign": "4.1.1",
- "parse-json": "2.2.0",
- "pinkie-promise": "2.0.1",
- "read-all-stream": "3.1.0",
- "readable-stream": "2.3.3",
- "timed-out": "3.1.3",
- "unzip-response": "1.0.2",
- "url-parse-lax": "1.0.0"
- },
- "dependencies": {
- "isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
- },
- "readable-stream": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
- "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
- "requires": {
- "core-util-is": "1.0.2",
- "inherits": "2.0.3",
- "isarray": "1.0.0",
- "process-nextick-args": "1.0.7",
- "safe-buffer": "5.1.1",
- "string_decoder": "1.0.3",
- "util-deprecate": "1.0.2"
- }
- },
- "string_decoder": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
- "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
- "requires": {
- "safe-buffer": "5.1.1"
- }
- }
- }
- },
- "graceful-fs": {
- "version": "4.1.11",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.11.tgz",
- "integrity": "sha1-Dovf5NHduIVNZOBOp8AOKgJuVlg="
- },
- "har-schema": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz",
- "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI="
- },
- "har-validator": {
- "version": "5.0.3",
- "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.0.3.tgz",
- "integrity": "sha1-ukAsJmGU8VlW7xXg/PJCmT9qff0=",
- "requires": {
- "ajv": "5.5.0",
- "har-schema": "2.0.0"
- }
- },
- "has-ansi": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
- "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=",
- "requires": {
- "ansi-regex": "2.1.1"
- }
- },
- "hawk": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/hawk/-/hawk-6.0.2.tgz",
- "integrity": "sha512-miowhl2+U7Qle4vdLqDdPt9m09K6yZhkLDTWGoUiUzrQCn+mHHSmfJgAyGaLRZbPmTqfFFjRV1QWCW0VWUJBbQ==",
- "requires": {
- "boom": "4.3.1",
- "cryptiles": "3.1.2",
- "hoek": "4.2.0",
- "sntp": "2.1.0"
- }
- },
- "hexo": {
- "version": "3.4.2",
- "resolved": "https://registry.npmjs.org/hexo/-/hexo-3.4.2.tgz",
- "integrity": "sha512-ElTdoBqf9n0OpJaTrmUJvZSMpeL8I/E65AZsQKPMBTbjZCt95yTx+edP3cbhlBMenRwZb83N658FVep/keDfuQ==",
- "requires": {
- "abbrev": "1.1.1",
- "archy": "1.0.0",
- "bluebird": "3.5.0",
- "chalk": "1.1.3",
- "cheerio": "0.20.0",
- "deep-assign": "2.0.0",
- "hexo-cli": "1.0.4",
- "hexo-front-matter": "0.2.3",
- "hexo-fs": "0.2.2",
- "hexo-i18n": "0.2.1",
- "hexo-log": "0.2.0",
- "hexo-util": "0.6.2",
- "js-yaml": "3.10.0",
- "lodash": "4.17.4",
- "minimatch": "3.0.4",
- "moment": "2.19.3",
- "moment-timezone": "0.5.14",
- "nunjucks": "2.5.2",
- "pretty-hrtime": "1.0.3",
- "strip-indent": "1.0.1",
- "swig": "1.4.2",
- "swig-extras": "0.0.1",
- "text-table": "0.2.0",
- "tildify": "1.2.0",
- "titlecase": "1.1.2",
- "warehouse": "2.2.0"
- },
- "dependencies": {
- "hexo-cli": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/hexo-cli/-/hexo-cli-1.0.4.tgz",
- "integrity": "sha512-X4YxBfuwRjCFF2fCAdmuLo/5IKruZCYc/kRaiVfPsTYFvvaBvsBTZBDhB8t4MOQv3QqoYMld9bGRLnd9NiEsFg==",
- "requires": {
- "abbrev": "1.1.1",
- "bluebird": "3.5.0",
- "chalk": "1.1.3",
- "command-exists": "1.2.2",
- "hexo-fs": "0.2.2",
- "hexo-log": "0.2.0",
- "hexo-util": "0.6.2",
- "minimist": "1.2.0",
- "object-assign": "4.1.1",
- "tildify": "1.2.0"
- }
- }
- }
- },
- "hexo-bunyan": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/hexo-bunyan/-/hexo-bunyan-1.0.0.tgz",
- "integrity": "sha512-RymT8Ck+K77mLt9BEYNb4uyfC7RIQnU5N3laXowMrS28jj2h89VHJCOnhV00mmta4fHRqNa07kP1Hrn17nvMkQ==",
- "requires": {
- "moment": "2.19.2",
- "mv": "2.1.1",
- "safe-json-stringify": "1.0.4"
- }
- },
- "hexo-deployer-git": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/hexo-deployer-git/-/hexo-deployer-git-0.3.1.tgz",
- "integrity": "sha512-JSwSmTSknGpaiooGXwmP7sAhoSNW3c+xmBiCc5yyrvRSfQ3zIYWjmcqNXSj8m2DmheqQNgt5D4M7quYjw+L6tA==",
- "requires": {
- "babel-eslint": "7.2.3",
- "bluebird": "3.5.0",
- "chalk": "1.1.3",
- "hexo-fs": "0.2.2",
- "hexo-util": "0.6.2",
- "moment": "2.19.2",
- "swig": "1.4.2"
- }
- },
- "hexo-front-matter": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/hexo-front-matter/-/hexo-front-matter-0.2.3.tgz",
- "integrity": "sha1-x8qO9CDqNr2F6ECKLoyb9J76YF4=",
- "requires": {
- "js-yaml": "3.10.0"
- }
- },
- "hexo-fs": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/hexo-fs/-/hexo-fs-0.2.2.tgz",
- "integrity": "sha512-boZoDQYieQJJ4drW40B5XI1Tol/ucEGXSV2qjVWI51NsGbFTNw0PBIZjwSs2rum6QnJIYw50K7uBTo8WXGp/aw==",
- "requires": {
- "bluebird": "3.5.0",
- "chokidar": "1.7.0",
- "escape-string-regexp": "1.0.5",
- "graceful-fs": "4.1.11"
- }
- },
- "hexo-generator-alias": {
- "version": "git+https://github.com/chrisvfritz/vuejs.org-hexo-generator-alias.git#67adb814a76750f3c841825f955bd5dd92cd1f20"
- },
- "hexo-generator-archive": {
- "version": "0.1.5",
- "resolved": "https://registry.npmjs.org/hexo-generator-archive/-/hexo-generator-archive-0.1.5.tgz",
- "integrity": "sha512-jPbMtibqkJnAX3hCwhYhK3r6cqy9OKQsVEScjk7LDok+iPmFmkKCNdU/OccxGe1CWAZpT+ta4+LknwNeHG2G4w==",
- "requires": {
- "hexo-pagination": "0.0.2",
- "object-assign": "2.1.1"
- },
- "dependencies": {
- "object-assign": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz",
- "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo="
- }
- }
- },
- "hexo-generator-category": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/hexo-generator-category/-/hexo-generator-category-0.1.3.tgz",
- "integrity": "sha1-uealhiUwqDvdfaTIGcG58+TMtLI=",
- "requires": {
- "hexo-pagination": "0.0.2",
- "object-assign": "2.1.1"
- },
- "dependencies": {
- "object-assign": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-2.1.1.tgz",
- "integrity": "sha1-Q8NuXVaf+OSBbE76i+AtJpZ8GKo="
- }
- }
- },
- "hexo-generator-feed": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/hexo-generator-feed/-/hexo-generator-feed-1.2.2.tgz",
- "integrity": "sha512-4jcvVhFgpEFRJ7A+KhBSfWoQaewRBjcVWEO4OmBgnvaZOm6XwK+b5ZXx/8BpujCLHbjXWzglXhiT7qFFS/nvzw==",
- "requires": {
- "nunjucks": "3.0.1",
- "object-assign": "4.1.1"
- },
- "dependencies": {
- "nunjucks": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-3.0.1.tgz",
- "integrity": "sha1-TedKPlULr2+jNwMj89HHwqhr3E0=",
- "requires": {
- "a-sync-waterfall": "1.0.0",
- "asap": "2.0.6",
- "chokidar": "1.7.0",
- "yargs": "3.32.0"
- }
- }
- }
- },
- "hexo-generator-index": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/hexo-generator-index/-/hexo-generator-index-0.2.1.tgz",
- "integrity": "sha1-kEIin8rHmq9wBXXaGTMr8/fuXF0=",
- "requires": {
- "hexo-pagination": "0.0.2",
- "object-assign": "4.1.1"
- }
- },
- "hexo-generator-tag": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/hexo-generator-tag/-/hexo-generator-tag-0.2.0.tgz",
- "integrity": "sha1-xXFYRrtB5X2cIMHWbX2yGhq/emI=",
- "requires": {
- "hexo-pagination": "0.0.2",
- "object-assign": "4.1.1"
- }
- },
- "hexo-i18n": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/hexo-i18n/-/hexo-i18n-0.2.1.tgz",
- "integrity": "sha1-hPFBQyvwnYtVjth4xygWS20c1t4=",
- "requires": {
- "sprintf-js": "1.0.3"
- }
- },
- "hexo-log": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/hexo-log/-/hexo-log-0.2.0.tgz",
- "integrity": "sha512-fzoc+GQexxPPILTjoOQILnA3ZG2MFgqMBVel4xvJ11pXptw9+f97ynTgDAExXafyp9Nz2ChXRuqlCYgPtZSlxQ==",
- "requires": {
- "chalk": "1.1.3",
- "hexo-bunyan": "1.0.0"
- }
- },
- "hexo-offline": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/hexo-offline/-/hexo-offline-0.2.2.tgz",
- "integrity": "sha1-ErrFHgRyCPWCr5GVRlROCyDKpGc=",
- "requires": {
- "sw-precache": "5.2.0"
- }
- },
- "hexo-pagination": {
- "version": "0.0.2",
- "resolved": "https://registry.npmjs.org/hexo-pagination/-/hexo-pagination-0.0.2.tgz",
- "integrity": "sha1-jPRwx9sN5bGKOSanbesZQBXffys=",
- "requires": {
- "utils-merge": "1.0.0"
- }
- },
- "hexo-renderer-ejs": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/hexo-renderer-ejs/-/hexo-renderer-ejs-0.3.1.tgz",
- "integrity": "sha512-XN8pYJU+Wr3dT8ipqEPRlOBySJpd1C5NUBBzgZpVSVBC/6L36O0YZI/Qd5NxQqwfGfSuKQ8N5iMyjmRXSR1MdA==",
- "requires": {
- "ejs": "2.5.7",
- "object-assign": "4.1.1"
- }
- },
- "hexo-renderer-marked": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/hexo-renderer-marked/-/hexo-renderer-marked-0.3.0.tgz",
- "integrity": "sha1-X6J6NhB10Ui47P8plSo+FeI67YE=",
- "requires": {
- "hexo-util": "0.6.2",
- "marked": "0.3.6",
- "object-assign": "4.1.1",
- "strip-indent": "1.0.1"
- }
- },
- "hexo-renderer-stylus": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/hexo-renderer-stylus/-/hexo-renderer-stylus-0.3.3.tgz",
- "integrity": "sha1-xU6ifh/Y48ipp6hM+6itNUEiyn8=",
- "requires": {
- "nib": "1.1.2",
- "stylus": "0.54.5"
- }
- },
- "hexo-server": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/hexo-server/-/hexo-server-0.2.2.tgz",
- "integrity": "sha512-/KkOYMIGylNoMtnlgas84Kw18A60WU3BVfo8ZnTHy8omCsAz2Z+aK6ddR4PpSmTdLeKDsiZj4ZSg86ZQ+FZzrA==",
- "requires": {
- "bluebird": "3.5.0",
- "chalk": "1.1.3",
- "compression": "1.7.0",
- "connect": "3.6.3",
- "mime": "1.4.0",
- "morgan": "1.8.2",
- "object-assign": "4.1.1",
- "opn": "4.0.2",
- "serve-static": "1.12.4"
- }
- },
- "hexo-util": {
- "version": "0.6.2",
- "resolved": "https://registry.npmjs.org/hexo-util/-/hexo-util-0.6.2.tgz",
- "integrity": "sha512-hmWS97r06UJnNTIIk2P4eTp5S/v+ZWliGzPHD8lJw5vo+q4JBOJ+bCL9KkuQBx6UQzxgFbe11QeVSklYWCiS6Q==",
- "requires": {
- "bluebird": "3.5.1",
- "camel-case": "3.0.0",
- "cross-spawn": "4.0.2",
- "highlight.js": "9.12.0",
- "html-entities": "1.2.1",
- "striptags": "2.2.1"
- },
- "dependencies": {
- "bluebird": {
- "version": "3.5.1",
- "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.5.1.tgz",
- "integrity": "sha512-MKiLiV+I1AA596t9w1sQJ8jkiSr5+ZKi0WKrYGUn6d1Fx+Ij4tIj+m2WMQSGczs5jZVxV339chE8iwk6F64wjA=="
- }
- }
- },
- "highlight.js": {
- "version": "9.12.0",
- "resolved": "https://registry.npmjs.org/highlight.js/-/highlight.js-9.12.0.tgz",
- "integrity": "sha1-5tnb5Xy+/mB1HwKvM2GVhwyQwB4="
- },
- "hoek": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/hoek/-/hoek-4.2.0.tgz",
- "integrity": "sha512-v0XCLxICi9nPfYrS9RL8HbYnXi9obYAeLbSP00BmnZwCK9+Ih9WOjoZ8YoHCoav2csqn4FOz4Orldsy2dmDwmQ=="
- },
- "hosted-git-info": {
- "version": "2.5.0",
- "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.5.0.tgz",
- "integrity": "sha512-pNgbURSuab90KbTqvRPsseaTxOJCZBD0a7t+haSN33piP9cCM4l0CqdzAif2hUqm716UovKB2ROmiabGAKVXyg=="
- },
- "html-entities": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-1.2.1.tgz",
- "integrity": "sha1-DfKTUfByEWNRXfueVUPl9u7VFi8="
- },
- "htmlparser2": {
- "version": "3.8.3",
- "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-3.8.3.tgz",
- "integrity": "sha1-mWwosZFRaovoZQGn15dX5ccMEGg=",
- "requires": {
- "domelementtype": "1.3.0",
- "domhandler": "2.3.0",
- "domutils": "1.5.1",
- "entities": "1.0.0",
- "readable-stream": "1.1.14"
- },
- "dependencies": {
- "entities": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/entities/-/entities-1.0.0.tgz",
- "integrity": "sha1-sph6o4ITR/zeZCsk/fyeT7cSvyY="
- }
- }
- },
- "http-errors": {
- "version": "1.6.2",
- "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.2.tgz",
- "integrity": "sha1-CgAsyFcHGSp+eUbO7cERVfYOxzY=",
- "requires": {
- "depd": "1.1.1",
- "inherits": "2.0.3",
- "setprototypeof": "1.0.3",
- "statuses": "1.3.1"
- }
- },
- "http-signature": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz",
- "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=",
- "requires": {
- "assert-plus": "1.0.0",
- "jsprim": "1.4.1",
- "sshpk": "1.13.1"
- }
- },
- "imurmurhash": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz",
- "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o="
- },
- "indent-string": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz",
- "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=",
- "requires": {
- "repeating": "2.0.1"
- }
- },
- "inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
- "requires": {
- "once": "1.4.0",
- "wrappy": "1.0.2"
- }
- },
- "inherits": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz",
- "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4="
- },
- "ini": {
- "version": "1.3.4",
- "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.4.tgz",
- "integrity": "sha1-BTfLedr1m1mhpRff9wbIbsA5Fi4="
- },
- "invariant": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/invariant/-/invariant-2.2.2.tgz",
- "integrity": "sha1-nh9WrArNtr8wMwbzOL47IErmA2A=",
- "requires": {
- "loose-envify": "1.3.1"
- }
- },
- "invert-kv": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz",
- "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY="
- },
- "is-arrayish": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz",
- "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0="
- },
- "is-binary-path": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz",
- "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=",
- "requires": {
- "binary-extensions": "1.11.0"
- }
- },
- "is-buffer": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz",
- "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w=="
- },
- "is-builtin-module": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz",
- "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=",
- "requires": {
- "builtin-modules": "1.1.1"
- }
- },
- "is-dotfile": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/is-dotfile/-/is-dotfile-1.0.3.tgz",
- "integrity": "sha1-pqLzL/0t+wT1yiXs0Pa4PPeYoeE="
- },
- "is-equal-shallow": {
- "version": "0.1.3",
- "resolved": "https://registry.npmjs.org/is-equal-shallow/-/is-equal-shallow-0.1.3.tgz",
- "integrity": "sha1-IjgJj8Ih3gvPpdnqxMRdY4qhxTQ=",
- "requires": {
- "is-primitive": "2.0.0"
- }
- },
- "is-extendable": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz",
- "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik="
- },
- "is-extglob": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-1.0.0.tgz",
- "integrity": "sha1-rEaBd8SUNAWgkvyPKXYMb/xiBsA="
- },
- "is-finite": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.0.2.tgz",
- "integrity": "sha1-zGZ3aVYCvlUO8R6LSqYwU0K20Ko=",
- "requires": {
- "number-is-nan": "1.0.1"
- }
- },
- "is-fullwidth-code-point": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
- "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
- "requires": {
- "number-is-nan": "1.0.1"
- }
- },
- "is-glob": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-2.0.1.tgz",
- "integrity": "sha1-0Jb5JqPe1WAPP9/ZEZjLCIjC2GM=",
- "requires": {
- "is-extglob": "1.0.0"
- }
- },
- "is-npm": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-npm/-/is-npm-1.0.0.tgz",
- "integrity": "sha1-8vtjpl5JBbQGyGBydloaTceTufQ="
- },
- "is-number": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-2.1.0.tgz",
- "integrity": "sha1-Afy7s5NGOlSPL0ZszhbezknbkI8=",
- "requires": {
- "kind-of": "3.2.2"
- }
- },
- "is-obj": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-1.0.1.tgz",
- "integrity": "sha1-PkcprB9f3gJc19g6iW2rn09n2w8="
- },
- "is-plain-object": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
- "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
- "requires": {
- "isobject": "3.0.1"
- },
- "dependencies": {
- "isobject": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
- "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8="
- }
- }
- },
- "is-posix-bracket": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/is-posix-bracket/-/is-posix-bracket-0.1.1.tgz",
- "integrity": "sha1-MzTceXdDaOkvAW5vvAqI9c1ua8Q="
- },
- "is-primitive": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/is-primitive/-/is-primitive-2.0.0.tgz",
- "integrity": "sha1-IHurkWOEmcB7Kt8kCkGochADRXU="
- },
- "is-redirect": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-redirect/-/is-redirect-1.0.0.tgz",
- "integrity": "sha1-HQPd7VO9jbDzDCbk+V02/HyH3CQ="
- },
- "is-retry-allowed": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-retry-allowed/-/is-retry-allowed-1.1.0.tgz",
- "integrity": "sha1-EaBgVotnM5REAz0BJaYaINVk+zQ="
- },
- "is-stream": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-1.1.0.tgz",
- "integrity": "sha1-EtSj3U5o4Lec6428hBc66A2RykQ="
- },
- "is-typedarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz",
- "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo="
- },
- "is-utf8": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
- "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI="
- },
- "isarray": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
- "integrity": "sha1-ihis/Kmo9Bd+Cav8YDiTmwXR7t8="
- },
- "isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA="
- },
- "isobject": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz",
- "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=",
- "requires": {
- "isarray": "1.0.0"
- },
- "dependencies": {
- "isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
- }
- }
- },
- "isstream": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz",
- "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo="
- },
- "js-tokens": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-3.0.2.tgz",
- "integrity": "sha1-mGbfOVECEw449/mWvOtlRDIJwls="
- },
- "js-yaml": {
- "version": "3.10.0",
- "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.10.0.tgz",
- "integrity": "sha512-O2v52ffjLa9VeM43J4XocZE//WT9N0IiwDa3KSHH7Tu8CtH+1qM8SIZvnsTh6v+4yFy5KUY3BHUVwjpfAWsjIA==",
- "requires": {
- "argparse": "1.0.9",
- "esprima": "4.0.0"
- },
- "dependencies": {
- "esprima": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.0.tgz",
- "integrity": "sha512-oftTcaMu/EGrEIu904mWteKIv8vMuOgGYo7EhVJJN00R/EED9DCua/xxHRdYnKtcECzVg7xOWhflvJMnqcFZjw=="
- }
- }
- },
- "jsbn": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz",
- "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=",
- "optional": true
- },
- "jsdom": {
- "version": "7.2.2",
- "resolved": "https://registry.npmjs.org/jsdom/-/jsdom-7.2.2.tgz",
- "integrity": "sha1-QLQCdwwr2iNGkJa+6Rq2deOx/G4=",
- "optional": true,
- "requires": {
- "abab": "1.0.4",
- "acorn": "2.7.0",
- "acorn-globals": "1.0.9",
- "cssom": "0.3.2",
- "cssstyle": "0.2.37",
- "escodegen": "1.9.0",
- "nwmatcher": "1.4.3",
- "parse5": "1.5.1",
- "request": "2.83.0",
- "sax": "1.2.4",
- "symbol-tree": "3.2.2",
- "tough-cookie": "2.3.3",
- "webidl-conversions": "2.0.1",
- "whatwg-url-compat": "0.6.5",
- "xml-name-validator": "2.0.1"
- }
- },
- "json-schema": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz",
- "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM="
- },
- "json-schema-traverse": {
- "version": "0.3.1",
- "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.3.1.tgz",
- "integrity": "sha1-NJptRMU6Ud6JtAgFxdXlm0F9M0A="
- },
- "json-stringify-safe": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz",
- "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus="
- },
- "jsonparse": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz",
- "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA="
- },
- "jsprim": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",
- "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=",
- "requires": {
- "assert-plus": "1.0.0",
- "extsprintf": "1.3.0",
- "json-schema": "0.2.3",
- "verror": "1.10.0"
- }
- },
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "requires": {
- "is-buffer": "1.1.6"
- }
- },
- "latest-version": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/latest-version/-/latest-version-2.0.0.tgz",
- "integrity": "sha1-VvjWE5YghHuAF/jx9NeOIRMkFos=",
- "requires": {
- "package-json": "2.4.0"
- }
- },
- "lazy-req": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/lazy-req/-/lazy-req-1.1.0.tgz",
- "integrity": "sha1-va6+rTD42CQDnODOFJ1Nqge6H6w="
- },
- "lcid": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz",
- "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=",
- "requires": {
- "invert-kv": "1.0.0"
- }
- },
- "levn": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/levn/-/levn-0.3.0.tgz",
- "integrity": "sha1-OwmSTt+fCDwEkP3UwLxEIeBHZO4=",
- "optional": true,
- "requires": {
- "prelude-ls": "1.1.2",
- "type-check": "0.3.2"
- }
- },
- "load-json-file": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz",
- "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=",
- "requires": {
- "graceful-fs": "4.1.11",
- "parse-json": "2.2.0",
- "pify": "2.3.0",
- "pinkie-promise": "2.0.1",
- "strip-bom": "2.0.0"
- }
- },
- "lodash": {
- "version": "4.17.4",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.4.tgz",
- "integrity": "sha1-eCA6TRwyiuHYbcpkYONptX9AVa4="
- },
- "lodash._reinterpolate": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
- "integrity": "sha1-DM8tiRZq8Ds2Y8eWU4t1rG4RTZ0="
- },
- "lodash.defaults": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
- "integrity": "sha1-0JF4cW/+pN3p5ft7N/bwgCJ0WAw="
- },
- "lodash.template": {
- "version": "4.4.0",
- "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.4.0.tgz",
- "integrity": "sha1-5zoDhcg1VZF0bgILmWecaQ5o+6A=",
- "requires": {
- "lodash._reinterpolate": "3.0.0",
- "lodash.templatesettings": "4.1.0"
- }
- },
- "lodash.templatesettings": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.1.0.tgz",
- "integrity": "sha1-K01OlbpEDZFf8IvImeRVNmZxMxY=",
- "requires": {
- "lodash._reinterpolate": "3.0.0"
- }
- },
- "loose-envify": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.3.1.tgz",
- "integrity": "sha1-0aitM/qc4OcT1l/dCsi3SNR4yEg=",
- "requires": {
- "js-tokens": "3.0.2"
- }
- },
- "loud-rejection": {
- "version": "1.6.0",
- "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz",
- "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=",
- "requires": {
- "currently-unhandled": "0.4.1",
- "signal-exit": "3.0.2"
- }
- },
- "lower-case": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/lower-case/-/lower-case-1.1.4.tgz",
- "integrity": "sha1-miyr0bno4K6ZOkv31YdcOcQujqw="
- },
- "lowercase-keys": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.0.tgz",
- "integrity": "sha1-TjNms55/VFfjXxMkvfb4jQv8cwY="
- },
- "lru-cache": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.1.tgz",
- "integrity": "sha512-q4spe4KTfsAS1SUHLO0wz8Qiyf1+vMIAgpRYioFYDMNqKfHQbg+AVDH3i4fvpl71/P1L0dBl+fQi+P37UYf0ew==",
- "requires": {
- "pseudomap": "1.0.2",
- "yallist": "2.1.2"
- }
- },
- "map-obj": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz",
- "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0="
- },
- "markdown": {
- "version": "0.5.0",
- "resolved": "https://registry.npmjs.org/markdown/-/markdown-0.5.0.tgz",
- "integrity": "sha1-KCBbVlqK51kt4gdGPWY33BgnIrI=",
- "requires": {
- "nopt": "2.1.2"
- }
- },
- "marked": {
- "version": "0.3.6",
- "resolved": "https://registry.npmjs.org/marked/-/marked-0.3.6.tgz",
- "integrity": "sha1-ssbGGPzOzk74bE/Gy4p8v1rtqNc="
- },
- "meow": {
- "version": "3.7.0",
- "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz",
- "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=",
- "requires": {
- "camelcase-keys": "2.1.0",
- "decamelize": "1.2.0",
- "loud-rejection": "1.6.0",
- "map-obj": "1.0.1",
- "minimist": "1.2.0",
- "normalize-package-data": "2.4.0",
- "object-assign": "4.1.1",
- "read-pkg-up": "1.0.1",
- "redent": "1.0.0",
- "trim-newlines": "1.0.0"
- }
- },
- "micromatch": {
- "version": "2.3.11",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-2.3.11.tgz",
- "integrity": "sha1-hmd8l9FyCzY0MdBNDRUpO9OMFWU=",
- "requires": {
- "arr-diff": "2.0.0",
- "array-unique": "0.2.1",
- "braces": "1.8.5",
- "expand-brackets": "0.1.5",
- "extglob": "0.3.2",
- "filename-regex": "2.0.1",
- "is-extglob": "1.0.0",
- "is-glob": "2.0.1",
- "kind-of": "3.2.2",
- "normalize-path": "2.1.1",
- "object.omit": "2.0.1",
- "parse-glob": "3.0.4",
- "regex-cache": "0.4.4"
- }
- },
- "mime": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.0.tgz",
- "integrity": "sha512-n9ChLv77+QQEapYz8lV+rIZAW3HhAPW2CXnzb1GN5uMkuczshwvkW7XPsbzU0ZQN3sP47Er2KVkp2p3KyqZKSQ=="
- },
- "mime-db": {
- "version": "1.29.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.29.0.tgz",
- "integrity": "sha1-SNJtI1WJZRcErFkWygYAGRQmaHg="
- },
- "mime-types": {
- "version": "2.1.16",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.16.tgz",
- "integrity": "sha1-K4WKUuXs1RbbiXrCvodIeDBpjiM=",
- "requires": {
- "mime-db": "1.29.0"
- }
- },
- "minimatch": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
- "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
- "requires": {
- "brace-expansion": "1.1.8"
- }
- },
- "minimist": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz",
- "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ="
- },
- "mkdirp": {
- "version": "0.5.1",
- "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz",
- "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=",
- "requires": {
- "minimist": "0.0.8"
- },
- "dependencies": {
- "minimist": {
- "version": "0.0.8",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz",
- "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0="
- }
- }
- },
- "moment": {
- "version": "2.19.2",
- "resolved": "https://registry.npmjs.org/moment/-/moment-2.19.2.tgz",
- "integrity": "sha512-Rf6jiHPEfxp9+dlzxPTmRHbvoFXsh2L/U8hOupUMpnuecHQmI6cF6lUbJl3QqKPko1u6ujO+FxtcajLVfLpAtA=="
- },
- "moment-timezone": {
- "version": "0.5.14",
- "resolved": "https://registry.npmjs.org/moment-timezone/-/moment-timezone-0.5.14.tgz",
- "integrity": "sha1-TrOP+VOLgBCLpGekWPPtQmjM/LE=",
- "requires": {
- "moment": "2.19.2"
- }
- },
- "morgan": {
- "version": "1.8.2",
- "resolved": "https://registry.npmjs.org/morgan/-/morgan-1.8.2.tgz",
- "integrity": "sha1-eErHc05KRTqcbm6GgKkyknXItoc=",
- "requires": {
- "basic-auth": "1.1.0",
- "debug": "2.6.8",
- "depd": "1.1.1",
- "on-finished": "2.3.0",
- "on-headers": "1.0.1"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.8",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
- "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
- "requires": {
- "ms": "2.0.0"
- }
- }
- }
- },
- "ms": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
- "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
- },
- "mv": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/mv/-/mv-2.1.1.tgz",
- "integrity": "sha1-rmzg1vbV4KT32JN5jQPB6pVZtqI=",
- "optional": true,
- "requires": {
- "mkdirp": "0.5.1",
- "ncp": "2.0.0",
- "rimraf": "2.4.5"
- }
- },
- "nan": {
- "version": "2.8.0",
- "resolved": "https://registry.npmjs.org/nan/-/nan-2.8.0.tgz",
- "integrity": "sha1-7XFfP+neArV6XmJS2QqWZ14fCFo=",
- "optional": true
- },
- "ncp": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/ncp/-/ncp-2.0.0.tgz",
- "integrity": "sha1-GVoh1sRuNh0vsSgbo4uR6d9727M=",
- "optional": true
- },
- "negotiator": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.1.tgz",
- "integrity": "sha1-KzJxhOiZIQEXeyhWP7XnECrNDKk="
- },
- "nib": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/nib/-/nib-1.1.2.tgz",
- "integrity": "sha1-amnt5AgblcDe+L4CSkyK4MLLtsc=",
- "requires": {
- "stylus": "0.54.5"
- }
- },
- "no-case": {
- "version": "2.3.2",
- "resolved": "https://registry.npmjs.org/no-case/-/no-case-2.3.2.tgz",
- "integrity": "sha512-rmTZ9kz+f3rCvK2TD1Ue/oZlns7OGoIWP4fc3llxxRXlOkHKoWPPWJOfFYpITabSow43QJbRIoHQXtt10VldyQ==",
- "requires": {
- "lower-case": "1.1.4"
- }
- },
- "node-fingerprint": {
- "version": "0.0.2",
- "resolved": "https://registry.npmjs.org/node-fingerprint/-/node-fingerprint-0.0.2.tgz",
- "integrity": "sha1-Mcur63GmeufdWn3AQuUcPHWGhQE="
- },
- "node-status-codes": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/node-status-codes/-/node-status-codes-1.0.0.tgz",
- "integrity": "sha1-WuVUHQJGRdMqWPzdyc7s6nrjrC8="
- },
- "nopt": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/nopt/-/nopt-2.1.2.tgz",
- "integrity": "sha1-bMzZd7gBMqB3MdbozljCyDA8+a8=",
- "requires": {
- "abbrev": "1.1.1"
- }
- },
- "normalize-package-data": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.0.tgz",
- "integrity": "sha512-9jjUFbTPfEy3R/ad/2oNbKtW9Hgovl5O1FvFWKkKblNXoN/Oou6+9+KKohPK13Yc3/TyunyWhJp6gvRNR/PPAw==",
- "requires": {
- "hosted-git-info": "2.5.0",
- "is-builtin-module": "1.0.0",
- "semver": "5.4.1",
- "validate-npm-package-license": "3.0.1"
- }
- },
- "normalize-path": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz",
- "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=",
- "requires": {
- "remove-trailing-separator": "1.1.0"
- }
- },
- "nth-check": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-1.0.1.tgz",
- "integrity": "sha1-mSms32KPwsQQmN6rgqxYDPFJquQ=",
- "requires": {
- "boolbase": "1.0.0"
- }
- },
- "number-is-nan": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
- "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
- },
- "nunjucks": {
- "version": "2.5.2",
- "resolved": "https://registry.npmjs.org/nunjucks/-/nunjucks-2.5.2.tgz",
- "integrity": "sha1-6n00bnhbikh0Zmw8yp4YxXf7oiw=",
- "requires": {
- "asap": "2.0.6",
- "chokidar": "1.7.0",
- "yargs": "3.32.0"
- }
- },
- "nwmatcher": {
- "version": "1.4.3",
- "resolved": "https://registry.npmjs.org/nwmatcher/-/nwmatcher-1.4.3.tgz",
- "integrity": "sha512-IKdSTiDWCarf2JTS5e9e2+5tPZGdkRJ79XjYV0pzK8Q9BpsFyBq1RGKxzs7Q8UBushGw7m6TzVKz6fcY99iSWw==",
- "optional": true
- },
- "oauth-sign": {
- "version": "0.8.2",
- "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.8.2.tgz",
- "integrity": "sha1-Rqarfwrq2N6unsBWV4C31O/rnUM="
- },
- "object-assign": {
- "version": "4.1.1",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
- "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
- },
- "object.omit": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/object.omit/-/object.omit-2.0.1.tgz",
- "integrity": "sha1-Gpx0SCnznbuFjHbKNXmuKlTr0fo=",
- "requires": {
- "for-own": "0.1.5",
- "is-extendable": "0.1.1"
- }
- },
- "on-finished": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz",
- "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=",
- "requires": {
- "ee-first": "1.1.1"
- }
- },
- "on-headers": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.1.tgz",
- "integrity": "sha1-ko9dD0cNSTQmUepnlLCFfBAGk/c="
- },
- "once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
- "requires": {
- "wrappy": "1.0.2"
- }
- },
- "opn": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/opn/-/opn-4.0.2.tgz",
- "integrity": "sha1-erwi5kTf9jsKltWrfyeQwPAavJU=",
- "requires": {
- "object-assign": "4.1.1",
- "pinkie-promise": "2.0.1"
- }
- },
- "optimist": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/optimist/-/optimist-0.6.1.tgz",
- "integrity": "sha1-2j6nRob6IaGaERwybpDrFaAZZoY=",
- "requires": {
- "minimist": "0.0.10",
- "wordwrap": "0.0.3"
- },
- "dependencies": {
- "minimist": {
- "version": "0.0.10",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.10.tgz",
- "integrity": "sha1-3j+YVD2/lggr5IrRoMfNqDYwHc8="
- },
- "wordwrap": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.3.tgz",
- "integrity": "sha1-o9XabNXAvAAI03I0u68b7WMFkQc="
- }
- }
- },
- "optionator": {
- "version": "0.8.2",
- "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.8.2.tgz",
- "integrity": "sha1-NkxeQJ0/TWMB1sC0wFu6UBgK62Q=",
- "optional": true,
- "requires": {
- "deep-is": "0.1.3",
- "fast-levenshtein": "2.0.6",
- "levn": "0.3.0",
- "prelude-ls": "1.1.2",
- "type-check": "0.3.2",
- "wordwrap": "1.0.0"
- }
- },
- "os-homedir": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
- "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
- },
- "os-locale": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz",
- "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=",
- "requires": {
- "lcid": "1.0.0"
- }
- },
- "os-tmpdir": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
- "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
- },
- "osenv": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.4.tgz",
- "integrity": "sha1-Qv5tWVPfBsgGS+bxdsPQWqqjRkQ=",
- "requires": {
- "os-homedir": "1.0.2",
- "os-tmpdir": "1.0.2"
- }
- },
- "package-json": {
- "version": "2.4.0",
- "resolved": "https://registry.npmjs.org/package-json/-/package-json-2.4.0.tgz",
- "integrity": "sha1-DRW9Z9HLvduyyiIv8u24a8sxqLs=",
- "requires": {
- "got": "5.7.1",
- "registry-auth-token": "3.3.1",
- "registry-url": "3.1.0",
- "semver": "5.4.1"
- }
- },
- "parse-glob": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/parse-glob/-/parse-glob-3.0.4.tgz",
- "integrity": "sha1-ssN2z7EfNVE7rdFz7wu246OIORw=",
- "requires": {
- "glob-base": "0.3.0",
- "is-dotfile": "1.0.3",
- "is-extglob": "1.0.0",
- "is-glob": "2.0.1"
- }
- },
- "parse-json": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz",
- "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=",
- "requires": {
- "error-ex": "1.3.1"
- }
- },
- "parse5": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/parse5/-/parse5-1.5.1.tgz",
- "integrity": "sha1-m387DeMr543CQBsXVzzK8Pb1nZQ=",
- "optional": true
- },
- "parseurl": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.1.tgz",
- "integrity": "sha1-yKuMkiO6NIiKpkopeyiFO+wY2lY="
- },
- "path-exists": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz",
- "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=",
- "requires": {
- "pinkie-promise": "2.0.1"
- }
- },
- "path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
- },
- "path-to-regexp": {
- "version": "1.7.0",
- "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.7.0.tgz",
- "integrity": "sha1-Wf3g9DW62suhA6hOnTvGTpa5k30=",
- "requires": {
- "isarray": "0.0.1"
- }
- },
- "path-type": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz",
- "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=",
- "requires": {
- "graceful-fs": "4.1.11",
- "pify": "2.3.0",
- "pinkie-promise": "2.0.1"
- }
- },
- "performance-now": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
- "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns="
- },
- "pify": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz",
- "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw="
- },
- "pinkie": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz",
- "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA="
- },
- "pinkie-promise": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz",
- "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=",
- "requires": {
- "pinkie": "2.0.4"
- }
- },
- "prelude-ls": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.1.2.tgz",
- "integrity": "sha1-IZMqVJ9eUv/ZqCf1cOBL5iqX2lQ="
- },
- "prepend-http": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/prepend-http/-/prepend-http-1.0.4.tgz",
- "integrity": "sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw="
- },
- "preserve": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/preserve/-/preserve-0.2.0.tgz",
- "integrity": "sha1-gV7R9uvGWSb4ZbMQwHE7yzMVzks="
- },
- "pretty-bytes": {
- "version": "4.0.2",
- "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-4.0.2.tgz",
- "integrity": "sha1-sr+C5zUNZcbDOqlaqlpPYyf2HNk="
- },
- "pretty-hrtime": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz",
- "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE="
- },
- "process-nextick-args": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz",
- "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M="
- },
- "pseudomap": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz",
- "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM="
- },
- "punycode": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz",
- "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4="
- },
- "qs": {
- "version": "6.5.1",
- "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.1.tgz",
- "integrity": "sha512-eRzhrN1WSINYCDCbrz796z37LOe3m5tmW7RQf6oBntukAG1nmovJvhnwHHRMAfeoItc1m2Hk02WER2aQ/iqs+A=="
- },
- "randomatic": {
- "version": "1.1.7",
- "resolved": "https://registry.npmjs.org/randomatic/-/randomatic-1.1.7.tgz",
- "integrity": "sha512-D5JUjPyJbaJDkuAazpVnSfVkLlpeO3wDlPROTMLGKG1zMFNFRgrciKo1ltz/AzNTkqE0HzDx655QOL51N06how==",
- "requires": {
- "is-number": "3.0.0",
- "kind-of": "4.0.0"
- },
- "dependencies": {
- "is-number": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz",
- "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=",
- "requires": {
- "kind-of": "3.2.2"
- },
- "dependencies": {
- "kind-of": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz",
- "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=",
- "requires": {
- "is-buffer": "1.1.6"
- }
- }
- }
- },
- "kind-of": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz",
- "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=",
- "requires": {
- "is-buffer": "1.1.6"
- }
- }
- }
- },
- "range-parser": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.0.tgz",
- "integrity": "sha1-9JvmtIeJTdxA3MlKMi9hEJLgDV4="
- },
- "rc": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.1.tgz",
- "integrity": "sha1-LgPo5C7kULjLPc5lvhv4l04d/ZU=",
- "requires": {
- "deep-extend": "0.4.2",
- "ini": "1.3.4",
- "minimist": "1.2.0",
- "strip-json-comments": "2.0.1"
- }
- },
- "read-all-stream": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/read-all-stream/-/read-all-stream-3.1.0.tgz",
- "integrity": "sha1-NcPhd/IHjveJ7kv6+kNzB06u9Po=",
- "requires": {
- "pinkie-promise": "2.0.1",
- "readable-stream": "2.3.3"
- },
- "dependencies": {
- "isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
- },
- "readable-stream": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
- "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
- "requires": {
- "core-util-is": "1.0.2",
- "inherits": "2.0.3",
- "isarray": "1.0.0",
- "process-nextick-args": "1.0.7",
- "safe-buffer": "5.1.1",
- "string_decoder": "1.0.3",
- "util-deprecate": "1.0.2"
- }
- },
- "string_decoder": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
- "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
- "requires": {
- "safe-buffer": "5.1.1"
- }
- }
- }
- },
- "read-pkg": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz",
- "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=",
- "requires": {
- "load-json-file": "1.1.0",
- "normalize-package-data": "2.4.0",
- "path-type": "1.1.0"
- }
- },
- "read-pkg-up": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz",
- "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=",
- "requires": {
- "find-up": "1.1.2",
- "read-pkg": "1.1.0"
- }
- },
- "readable-stream": {
- "version": "1.1.14",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
- "integrity": "sha1-fPTFTvZI44EwhMY23SB54WbAgdk=",
- "requires": {
- "core-util-is": "1.0.2",
- "inherits": "2.0.3",
- "isarray": "0.0.1",
- "string_decoder": "0.10.31"
- }
- },
- "readdirp": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.1.0.tgz",
- "integrity": "sha1-TtCtBg3zBzMAxIRANz9y0cxkLXg=",
- "requires": {
- "graceful-fs": "4.1.11",
- "minimatch": "3.0.4",
- "readable-stream": "2.3.3",
- "set-immediate-shim": "1.0.1"
- },
- "dependencies": {
- "isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
- },
- "readable-stream": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.3.tgz",
- "integrity": "sha512-m+qzzcn7KUxEmd1gMbchF+Y2eIUbieUaxkWtptyHywrX0rE8QEYqPC07Vuy4Wm32/xE16NcdBctb8S0Xe/5IeQ==",
- "requires": {
- "core-util-is": "1.0.2",
- "inherits": "2.0.3",
- "isarray": "1.0.0",
- "process-nextick-args": "1.0.7",
- "safe-buffer": "5.1.1",
- "string_decoder": "1.0.3",
- "util-deprecate": "1.0.2"
- }
- },
- "string_decoder": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.0.3.tgz",
- "integrity": "sha512-4AH6Z5fzNNBcH+6XDMfA/BTt87skxqJlO0lAh3Dker5zThcAxG6mKz+iGu308UKoPPQ8Dcqx/4JhujzltRa+hQ==",
- "requires": {
- "safe-buffer": "5.1.1"
- }
- }
- }
- },
- "redent": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz",
- "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=",
- "requires": {
- "indent-string": "2.1.0",
- "strip-indent": "1.0.1"
- }
- },
- "regenerator-runtime": {
- "version": "0.11.0",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.11.0.tgz",
- "integrity": "sha512-/aA0kLeRb5N9K0d4fw7ooEbI+xDe+DKD499EQqygGqeS8N3xto15p09uY2xj7ixP81sNPXvRLnAQIqdVStgb1A=="
- },
- "regex-cache": {
- "version": "0.4.4",
- "resolved": "https://registry.npmjs.org/regex-cache/-/regex-cache-0.4.4.tgz",
- "integrity": "sha512-nVIZwtCjkC9YgvWkpM55B5rBhBYRZhAaJbgcFYXXsHnbZ9UZI9nnVWYZpBlCqv9ho2eZryPnWrZGsOdPwVWXWQ==",
- "requires": {
- "is-equal-shallow": "0.1.3"
- }
- },
- "registry-auth-token": {
- "version": "3.3.1",
- "resolved": "https://registry.npmjs.org/registry-auth-token/-/registry-auth-token-3.3.1.tgz",
- "integrity": "sha1-+w0yie4Nmtosu1KvXf5mywcNMAY=",
- "requires": {
- "rc": "1.2.1",
- "safe-buffer": "5.1.1"
- }
- },
- "registry-url": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/registry-url/-/registry-url-3.1.0.tgz",
- "integrity": "sha1-PU74cPc93h138M+aOBQyRE4XSUI=",
- "requires": {
- "rc": "1.2.1"
- }
- },
- "remove-trailing-separator": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
- "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8="
- },
- "repeat-element": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.2.tgz",
- "integrity": "sha1-7wiaF40Ug7quTZPrmLT55OEdmQo="
- },
- "repeat-string": {
- "version": "1.6.1",
- "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz",
- "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc="
- },
- "repeating": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz",
- "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=",
- "requires": {
- "is-finite": "1.0.2"
- }
- },
- "request": {
- "version": "2.83.0",
- "resolved": "https://registry.npmjs.org/request/-/request-2.83.0.tgz",
- "integrity": "sha512-lR3gD69osqm6EYLk9wB/G1W/laGWjzH90t1vEa2xuxHD5KUrSzp9pUSfTm+YC5Nxt2T8nMPEvKlhbQayU7bgFw==",
- "requires": {
- "aws-sign2": "0.7.0",
- "aws4": "1.6.0",
- "caseless": "0.12.0",
- "combined-stream": "1.0.5",
- "extend": "3.0.1",
- "forever-agent": "0.6.1",
- "form-data": "2.3.1",
- "har-validator": "5.0.3",
- "hawk": "6.0.2",
- "http-signature": "1.2.0",
- "is-typedarray": "1.0.0",
- "isstream": "0.1.2",
- "json-stringify-safe": "5.0.1",
- "mime-types": "2.1.17",
- "oauth-sign": "0.8.2",
- "performance-now": "2.1.0",
- "qs": "6.5.1",
- "safe-buffer": "5.1.1",
- "stringstream": "0.0.5",
- "tough-cookie": "2.3.3",
- "tunnel-agent": "0.6.0",
- "uuid": "3.1.0"
- },
- "dependencies": {
- "mime-db": {
- "version": "1.30.0",
- "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.30.0.tgz",
- "integrity": "sha1-dMZD2i3Z1qRTmZY0ZbJtXKfXHwE="
- },
- "mime-types": {
- "version": "2.1.17",
- "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.17.tgz",
- "integrity": "sha1-Cdejk/A+mVp5+K+Fe3Cp4KsWVXo=",
- "requires": {
- "mime-db": "1.30.0"
- }
- }
- }
- },
- "rimraf": {
- "version": "2.4.5",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.4.5.tgz",
- "integrity": "sha1-7nEM5dk6j9uFb7Xqj/Di11k0sto=",
- "optional": true,
- "requires": {
- "glob": "6.0.4"
- }
- },
- "safe-buffer": {
- "version": "5.1.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.1.tgz",
- "integrity": "sha512-kKvNJn6Mm93gAczWVJg7wH+wGYWNrDHdWvpUmHyEsgCtIwwo3bqPtV4tR5tuPaUhTOo/kvhVwd8XwwOllGYkbg=="
- },
- "safe-json-stringify": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/safe-json-stringify/-/safe-json-stringify-1.0.4.tgz",
- "integrity": "sha1-gaCY9Efku8P/MxKiQ1IbwGDvWRE=",
- "optional": true
- },
- "sax": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
- "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==",
- "optional": true
- },
- "semver": {
- "version": "5.4.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-5.4.1.tgz",
- "integrity": "sha512-WfG/X9+oATh81XtllIo/I8gOiY9EXRdv1cQdyykeXK17YcUW3EXUAi2To4pcH6nZtJPr7ZOpM5OMyWJZm+8Rsg=="
- },
- "semver-diff": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/semver-diff/-/semver-diff-2.1.0.tgz",
- "integrity": "sha1-S7uEN8jTfksM8aaP1ybsbWRdbTY=",
- "requires": {
- "semver": "5.4.1"
- }
- },
- "send": {
- "version": "0.15.4",
- "resolved": "https://registry.npmjs.org/send/-/send-0.15.4.tgz",
- "integrity": "sha1-mF+qPihLAnPHkzZKNcZze9k5Bbk=",
- "requires": {
- "debug": "2.6.8",
- "depd": "1.1.1",
- "destroy": "1.0.4",
- "encodeurl": "1.0.1",
- "escape-html": "1.0.3",
- "etag": "1.8.0",
- "fresh": "0.5.0",
- "http-errors": "1.6.2",
- "mime": "1.3.4",
- "ms": "2.0.0",
- "on-finished": "2.3.0",
- "range-parser": "1.2.0",
- "statuses": "1.3.1"
- },
- "dependencies": {
- "debug": {
- "version": "2.6.8",
- "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.8.tgz",
- "integrity": "sha1-5zFTHKLt4n0YgiJCfaF4IdaP9Pw=",
- "requires": {
- "ms": "2.0.0"
- }
- },
- "mime": {
- "version": "1.3.4",
- "resolved": "https://registry.npmjs.org/mime/-/mime-1.3.4.tgz",
- "integrity": "sha1-EV+eO2s9rylZmDyzjxSaLUDrXVM="
- }
- }
- },
- "serve-static": {
- "version": "1.12.4",
- "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.12.4.tgz",
- "integrity": "sha1-m2qpjutyU8Tu3Ewfb9vKYJkBqWE=",
- "requires": {
- "encodeurl": "1.0.1",
- "escape-html": "1.0.3",
- "parseurl": "1.3.1",
- "send": "0.15.4"
- }
- },
- "serviceworker-cache-polyfill": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/serviceworker-cache-polyfill/-/serviceworker-cache-polyfill-4.0.0.tgz",
- "integrity": "sha1-3hnuc77yGrPAdAo3sz22JGS6ves="
- },
- "set-immediate-shim": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/set-immediate-shim/-/set-immediate-shim-1.0.1.tgz",
- "integrity": "sha1-SysbJ+uAip+NzEgaWOXlb1mfP2E="
- },
- "setprototypeof": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.0.3.tgz",
- "integrity": "sha1-ZlZ+NwQ+608E2RvWWMDL77VbjgQ="
- },
- "signal-exit": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz",
- "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0="
- },
- "slide": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/slide/-/slide-1.1.6.tgz",
- "integrity": "sha1-VusCfWW00tzmyy4tMsTUr8nh1wc="
- },
- "sntp": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/sntp/-/sntp-2.1.0.tgz",
- "integrity": "sha512-FL1b58BDrqS3A11lJ0zEdnJ3UOKqVxawAkF3k7F0CVN7VQ34aZrV+G8BZ1WC9ZL7NyrwsW0oviwsWDgRuVYtJg==",
- "requires": {
- "hoek": "4.2.0"
- }
- },
- "source-map": {
- "version": "0.5.7",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz",
- "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=",
- "optional": true
- },
- "spdx-correct": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-1.0.2.tgz",
- "integrity": "sha1-SzBz2TP/UfORLwOsVRlJikFQ20A=",
- "requires": {
- "spdx-license-ids": "1.2.2"
- }
- },
- "spdx-expression-parse": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-1.0.4.tgz",
- "integrity": "sha1-m98vIOH0DtRH++JzJmGR/O1RYmw="
- },
- "spdx-license-ids": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-1.2.2.tgz",
- "integrity": "sha1-yd96NCRZSt5r0RkA1ZZpbcBrrFc="
- },
- "sprintf-js": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz",
- "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw="
- },
- "sshpk": {
- "version": "1.13.1",
- "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.13.1.tgz",
- "integrity": "sha1-US322mKHFEMW3EwY/hzx2UBzm+M=",
- "requires": {
- "asn1": "0.2.3",
- "assert-plus": "1.0.0",
- "bcrypt-pbkdf": "1.0.1",
- "dashdash": "1.14.1",
- "ecc-jsbn": "0.1.1",
- "getpass": "0.1.7",
- "jsbn": "0.1.1",
- "tweetnacl": "0.14.5"
- }
- },
- "statuses": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz",
- "integrity": "sha1-+vUbnrdKrvOzrPStX2Gr8ky3uT4="
- },
- "string-width": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
- "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
- "requires": {
- "code-point-at": "1.1.0",
- "is-fullwidth-code-point": "1.0.0",
- "strip-ansi": "3.0.1"
- }
- },
- "string_decoder": {
- "version": "0.10.31",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
- "integrity": "sha1-YuIDvEF2bGwoyfyEMB2rHFMQ+pQ="
- },
- "stringstream": {
- "version": "0.0.5",
- "resolved": "https://registry.npmjs.org/stringstream/-/stringstream-0.0.5.tgz",
- "integrity": "sha1-TkhM1N5aC7vuGORjB3EKioFiGHg="
- },
- "strip-ansi": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
- "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
- "requires": {
- "ansi-regex": "2.1.1"
- }
- },
- "strip-bom": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz",
- "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=",
- "requires": {
- "is-utf8": "0.2.1"
- }
- },
- "strip-indent": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz",
- "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=",
- "requires": {
- "get-stdin": "4.0.1"
- }
- },
- "strip-json-comments": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
- "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
- },
- "striptags": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/striptags/-/striptags-2.2.1.tgz",
- "integrity": "sha1-TEULcI1BuL85zyTEn/I0/Gqr/TI="
- },
- "stylus": {
- "version": "0.54.5",
- "resolved": "https://registry.npmjs.org/stylus/-/stylus-0.54.5.tgz",
- "integrity": "sha1-QrlWCTHKcJDOhRWnmLqeaqPW3Hk=",
- "requires": {
- "css-parse": "1.7.0",
- "debug": "3.0.1",
- "glob": "7.0.6",
- "mkdirp": "0.5.1",
- "sax": "0.5.8",
- "source-map": "0.1.43"
- },
- "dependencies": {
- "glob": {
- "version": "7.0.6",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.0.6.tgz",
- "integrity": "sha1-IRuvr0nlJbjNkyYNFKsTYVKz9Xo=",
- "requires": {
- "fs.realpath": "1.0.0",
- "inflight": "1.0.6",
- "inherits": "2.0.3",
- "minimatch": "3.0.4",
- "once": "1.4.0",
- "path-is-absolute": "1.0.1"
- }
- },
- "sax": {
- "version": "0.5.8",
- "resolved": "https://registry.npmjs.org/sax/-/sax-0.5.8.tgz",
- "integrity": "sha1-1HLbIo6zMcJQaw6MFVJK25OdEsE="
- },
- "source-map": {
- "version": "0.1.43",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz",
- "integrity": "sha1-wkvBRspRfBRx9drL4lcbK3+eM0Y=",
- "requires": {
- "amdefine": "1.0.1"
- }
- }
- }
- },
- "supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc="
- },
- "sw-precache": {
- "version": "5.2.0",
- "resolved": "https://registry.npmjs.org/sw-precache/-/sw-precache-5.2.0.tgz",
- "integrity": "sha512-sKctdX+5hUxkqJ/1DM88ubQ+QRvyw7CnxWdk909N2DgvxMqc1gcQFrwL7zpVc87wFmCA/OvRQd0iMC2XdFopYg==",
- "requires": {
- "dom-urls": "1.1.0",
- "es6-promise": "4.1.1",
- "glob": "7.1.2",
- "lodash.defaults": "4.2.0",
- "lodash.template": "4.4.0",
- "meow": "3.7.0",
- "mkdirp": "0.5.1",
- "pretty-bytes": "4.0.2",
- "sw-toolbox": "3.6.0",
- "update-notifier": "1.0.3"
- },
- "dependencies": {
- "glob": {
- "version": "7.1.2",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.2.tgz",
- "integrity": "sha512-MJTUg1kjuLeQCJ+ccE4Vpa6kKVXkPYJ2mOCQyUuKLcLQsdrMCpBPUi8qVE6+YuaJkozeA9NusTAw3hLr8Xe5EQ==",
- "requires": {
- "fs.realpath": "1.0.0",
- "inflight": "1.0.6",
- "inherits": "2.0.3",
- "minimatch": "3.0.4",
- "once": "1.4.0",
- "path-is-absolute": "1.0.1"
- }
- }
- }
- },
- "sw-toolbox": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/sw-toolbox/-/sw-toolbox-3.6.0.tgz",
- "integrity": "sha1-Jt8dHHA0hljk3qKIQxkUm3sxg7U=",
- "requires": {
- "path-to-regexp": "1.7.0",
- "serviceworker-cache-polyfill": "4.0.0"
- }
- },
- "swig": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/swig/-/swig-1.4.2.tgz",
- "integrity": "sha1-QIXKBFM2kQS11IPihBs5t64aq6U=",
- "requires": {
- "optimist": "0.6.1",
- "uglify-js": "2.4.24"
- }
- },
- "swig-extras": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/swig-extras/-/swig-extras-0.0.1.tgz",
- "integrity": "sha1-tQP+3jcqucJMasaMr2VrzvGHIyg=",
- "requires": {
- "markdown": "0.5.0"
- }
- },
- "symbol-tree": {
- "version": "3.2.2",
- "resolved": "https://registry.npmjs.org/symbol-tree/-/symbol-tree-3.2.2.tgz",
- "integrity": "sha1-rifbOPZgp64uHDt9G8KQgZuFGeY=",
- "optional": true
- },
- "text-table": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
- "integrity": "sha1-f17oI66AUgfACvLfSoTsP8+lcLQ="
- },
- "through": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
- "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU="
- },
- "tildify": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/tildify/-/tildify-1.2.0.tgz",
- "integrity": "sha1-3OwD9V3Km3qj5bBPIYF+tW5jWIo=",
- "requires": {
- "os-homedir": "1.0.2"
- }
- },
- "timed-out": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/timed-out/-/timed-out-3.1.3.tgz",
- "integrity": "sha1-lYYL/MXHbCd/j4Mm/Q9bLiDrohc="
- },
- "titlecase": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/titlecase/-/titlecase-1.1.2.tgz",
- "integrity": "sha1-eBE9EQgIa4MmMxoyR96o9aSeqFM="
- },
- "to-fast-properties": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-1.0.3.tgz",
- "integrity": "sha1-uDVx+k2MJbguIxsG46MFXeTKGkc="
- },
- "tough-cookie": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.3.3.tgz",
- "integrity": "sha1-C2GKVWW23qkL80JdBNVe3EdadWE=",
- "requires": {
- "punycode": "1.4.1"
- }
- },
- "tr46": {
- "version": "0.0.3",
- "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
- "integrity": "sha1-gYT9NH2snNwYWZLzpmIuFLnZq2o=",
- "optional": true
- },
- "trim-newlines": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz",
- "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM="
- },
- "tunnel-agent": {
- "version": "0.6.0",
- "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz",
- "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=",
- "requires": {
- "safe-buffer": "5.1.1"
- }
- },
- "tweetnacl": {
- "version": "0.14.5",
- "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz",
- "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=",
- "optional": true
- },
- "type-check": {
- "version": "0.3.2",
- "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.3.2.tgz",
- "integrity": "sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=",
- "requires": {
- "prelude-ls": "1.1.2"
- }
- },
- "uglify-js": {
- "version": "2.4.24",
- "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-2.4.24.tgz",
- "integrity": "sha1-+tV1XB4Vd2WLsG/5q25UjJW+vW4=",
- "requires": {
- "async": "0.2.10",
- "source-map": "0.1.34",
- "uglify-to-browserify": "1.0.2",
- "yargs": "3.5.4"
- },
- "dependencies": {
- "camelcase": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-1.2.1.tgz",
- "integrity": "sha1-m7UwTS4LVmmLLHWLCKPqqdqlijk="
- },
- "source-map": {
- "version": "0.1.34",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.34.tgz",
- "integrity": "sha1-p8/omux7FoLDsZjQrPtH19CQVms=",
- "requires": {
- "amdefine": "1.0.1"
- }
- },
- "window-size": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.0.tgz",
- "integrity": "sha1-VDjNLqk7IC76Ohn+iIeu58lPnJ0="
- },
- "wordwrap": {
- "version": "0.0.2",
- "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-0.0.2.tgz",
- "integrity": "sha1-t5Zpu0LstAn4PVg8rVLKF+qhZD8="
- },
- "yargs": {
- "version": "3.5.4",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.5.4.tgz",
- "integrity": "sha1-2K/49mXpTDS9JZvevRv68N3TU2E=",
- "requires": {
- "camelcase": "1.2.1",
- "decamelize": "1.2.0",
- "window-size": "0.1.0",
- "wordwrap": "0.0.2"
- }
- }
- }
- },
- "uglify-to-browserify": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/uglify-to-browserify/-/uglify-to-browserify-1.0.2.tgz",
- "integrity": "sha1-bgkk1r2mta/jSeOabWMoUKD4grc="
- },
- "unpipe": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz",
- "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw="
- },
- "unzip-response": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/unzip-response/-/unzip-response-1.0.2.tgz",
- "integrity": "sha1-uYTwh3/AqJwsdzzB73tbIytbBv4="
- },
- "update-notifier": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/update-notifier/-/update-notifier-1.0.3.tgz",
- "integrity": "sha1-j5LFFUgr1oMbfJMBPnD4dVLHz1o=",
- "requires": {
- "boxen": "0.6.0",
- "chalk": "1.1.3",
- "configstore": "2.1.0",
- "is-npm": "1.0.0",
- "latest-version": "2.0.0",
- "lazy-req": "1.1.0",
- "semver-diff": "2.1.0",
- "xdg-basedir": "2.0.0"
- }
- },
- "upper-case": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/upper-case/-/upper-case-1.1.3.tgz",
- "integrity": "sha1-9rRQHC7EzdJrp4vnIilh3ndiFZg="
- },
- "urijs": {
- "version": "1.18.12",
- "resolved": "https://registry.npmjs.org/urijs/-/urijs-1.18.12.tgz",
- "integrity": "sha512-WlvUkocbQ+GYhi8zkcbecbGYq7YLSd2I3InxAfqeh6mWvWalBE7bISDHcAL3J7STrWFfizuJ709srHD+RuABPQ=="
- },
- "url-parse-lax": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/url-parse-lax/-/url-parse-lax-1.0.0.tgz",
- "integrity": "sha1-evjzA2Rem9eaJy56FKxovAYJ2nM=",
- "requires": {
- "prepend-http": "1.0.4"
- }
- },
- "util-deprecate": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
- },
- "utils-merge": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.0.tgz",
- "integrity": "sha1-ApT7kiu5N1FTVBxPcJYjHyh8ivg="
- },
- "uuid": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.1.0.tgz",
- "integrity": "sha512-DIWtzUkw04M4k3bf1IcpS2tngXEL26YUD2M0tMDUpnUrz2hgzUBlD55a4FjdLGPvfHxS6uluGWvaVEqgBcVa+g=="
- },
- "validate-npm-package-license": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz",
- "integrity": "sha1-KAS6vnEq0zeUWaz74kdGqywwP7w=",
- "requires": {
- "spdx-correct": "1.0.2",
- "spdx-expression-parse": "1.0.4"
- }
- },
- "vary": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.1.tgz",
- "integrity": "sha1-Z1Neu2lMHVIldFeYRmUyP1h+jTc="
- },
- "verror": {
- "version": "1.10.0",
- "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz",
- "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=",
- "requires": {
- "assert-plus": "1.0.0",
- "core-util-is": "1.0.2",
- "extsprintf": "1.3.0"
- }
- },
- "warehouse": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/warehouse/-/warehouse-2.2.0.tgz",
- "integrity": "sha1-XQnWSUKZK+Zn2PfIagnCuK6gQGI=",
- "requires": {
- "JSONStream": "1.3.1",
- "bluebird": "3.5.0",
- "cuid": "1.3.8",
- "graceful-fs": "4.1.11",
- "is-plain-object": "2.0.4",
- "lodash": "4.17.4"
- }
- },
- "webidl-conversions": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-2.0.1.tgz",
- "integrity": "sha1-O/glj30xjHRDw28uFpQCoaZwNQY=",
- "optional": true
- },
- "whatwg-url-compat": {
- "version": "0.6.5",
- "resolved": "https://registry.npmjs.org/whatwg-url-compat/-/whatwg-url-compat-0.6.5.tgz",
- "integrity": "sha1-AImBEa9om7CXVBzVpFymyHmERb8=",
- "optional": true,
- "requires": {
- "tr46": "0.0.3"
- }
- },
- "which": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/which/-/which-1.3.0.tgz",
- "integrity": "sha512-xcJpopdamTuY5duC/KnTTNBraPK54YwpenP4lzxU8H91GudWpFv38u0CKjclE1Wi2EH2EDz5LRcHcKbCIzqGyg==",
- "requires": {
- "isexe": "2.0.0"
- }
- },
- "widest-line": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/widest-line/-/widest-line-1.0.0.tgz",
- "integrity": "sha1-DAnIXCqUaD0Nfq+O4JfVZL8OEFw=",
- "requires": {
- "string-width": "1.0.2"
- }
- },
- "window-size": {
- "version": "0.1.4",
- "resolved": "https://registry.npmjs.org/window-size/-/window-size-0.1.4.tgz",
- "integrity": "sha1-+OGqHuWlPsW/FR/6CXQqatdpeHY="
- },
- "wordwrap": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/wordwrap/-/wordwrap-1.0.0.tgz",
- "integrity": "sha1-J1hIEIkUVqQXHI0CJkQa3pDLyus=",
- "optional": true
- },
- "wrap-ansi": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz",
- "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=",
- "requires": {
- "string-width": "1.0.2",
- "strip-ansi": "3.0.1"
- }
- },
- "wrappy": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
- "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
- },
- "write-file-atomic": {
- "version": "1.3.4",
- "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-1.3.4.tgz",
- "integrity": "sha1-+Aek8LHZ6ROuekgRLmzDrxmRtF8=",
- "requires": {
- "graceful-fs": "4.1.11",
- "imurmurhash": "0.1.4",
- "slide": "1.1.6"
- }
- },
- "xdg-basedir": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/xdg-basedir/-/xdg-basedir-2.0.0.tgz",
- "integrity": "sha1-7byQPMOF/ARSPZZqM1UEtVBNG9I=",
- "requires": {
- "os-homedir": "1.0.2"
- }
- },
- "xml-name-validator": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/xml-name-validator/-/xml-name-validator-2.0.1.tgz",
- "integrity": "sha1-TYuPHszTQZqjYgYb7O9RXh5VljU=",
- "optional": true
- },
- "y18n": {
- "version": "3.2.1",
- "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz",
- "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE="
- },
- "yallist": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz",
- "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI="
- },
- "yargs": {
- "version": "3.32.0",
- "resolved": "https://registry.npmjs.org/yargs/-/yargs-3.32.0.tgz",
- "integrity": "sha1-AwiOnr+edWtpdRYR0qXvWRSCyZU=",
- "requires": {
- "camelcase": "2.1.1",
- "cliui": "3.2.0",
- "decamelize": "1.2.0",
- "os-locale": "1.4.0",
- "string-width": "1.0.2",
- "window-size": "0.1.4",
- "y18n": "3.2.1"
- }
- }
- }
-}
diff --git a/package.json b/package.json
index 287873960d..b88a44c727 100644
--- a/package.json
+++ b/package.json
@@ -1,28 +1,31 @@
{
- "name": "vuejs.org",
+ "name": "v2.vuejs.org",
"private": true,
"hexo": {
- "version": "3.4.2"
+ "version": "6.2.0"
},
"scripts": {
- "start": "hexo server",
- "build": "node pre-deploy.js && hexo clean && hexo generate",
+ "dev": "node _scripts/sync-sponsors.js && hexo server",
+ "build": "node _scripts/pre-deploy.js && hexo clean && hexo generate",
"deploy": "npm run build && hexo deploy"
},
+ "engines": {
+ "node": ">=14.0.0"
+ },
"dependencies": {
- "hexo": "^3.4.2",
- "hexo-deployer-git": "0.3.1",
+ "axios": "^0.27.2",
+ "hexo": "^6.2.0",
"hexo-generator-alias": "git+https://github.com/chrisvfritz/vuejs.org-hexo-generator-alias.git",
- "hexo-generator-archive": "^0.1.5",
- "hexo-generator-category": "^0.1.3",
- "hexo-generator-feed": "^1.2.2",
- "hexo-generator-index": "^0.2.1",
- "hexo-generator-tag": "^0.2.0",
- "hexo-offline": "^0.2.2",
- "hexo-renderer-ejs": "^0.3.1",
- "hexo-renderer-marked": "^0.3.0",
- "hexo-renderer-stylus": "^0.3.3",
- "hexo-server": "^0.2.2",
- "request": "^2.83.0"
+ "hexo-generator-archive": "^1.0.0",
+ "hexo-generator-category": "^1.0.0",
+ "hexo-generator-feed": "^3.0.0",
+ "hexo-generator-index": "^2.0.0",
+ "hexo-generator-tag": "^1.0.0",
+ "hexo-renderer-ejs": "^2.0.0",
+ "hexo-renderer-marked": "^0.3.2",
+ "hexo-renderer-stylus": "^2.1.0",
+ "hexo-server": "^3.0.0",
+ "hoek": "^6.1.2",
+ "js-yaml": "^4.1.0"
}
-}
\ No newline at end of file
+}
diff --git a/pre-deploy.js b/pre-deploy.js
deleted file mode 100644
index 1abac6b4fa..0000000000
--- a/pre-deploy.js
+++ /dev/null
@@ -1,74 +0,0 @@
-// udpate to latest built files of Vue
-
-const fs = require('fs')
-const zlib = require('zlib')
-const request = require('request')
-const execSync = require('child_process').execSync
-
-const themeconfPath = 'themes/vue/_config.yml'
-const installPath = 'src/v2/guide/installation.md'
-const themeconfig = fs.readFileSync(themeconfPath, 'utf-8')
-const installation = fs.readFileSync(installPath, 'utf-8')
-
-// get latest Vue version
-console.log(`Checking latest Vue version...`)
-const localVersion = themeconfig.match(/vue_version: (.*)/)[1]
-const version = execSync('npm view vue version').toString().trim()
-
-if (localVersion === version) {
- console.log(`Version is up-to-date.`)
- process.exit(0)
-}
-
-console.log(`Latest version: ${version}. Downloading dist files...`)
-
-// replace version in theme config
-fs.writeFileSync(
- themeconfPath,
- themeconfig.replace(/vue_version: .*/, 'vue_version: ' + version)
-)
-
-// grab it from unpkg
-Promise.all([
- download(`vue.js`),
- download(`vue.min.js`)
-]).then(([ devSize, prodSize ]) => {
- // replace installation page version and size
- fs.writeFileSync(
- installPath,
- installation
- .replace(/vue_version: .*/, 'vue_version: ' + version)
- .replace(/gz_size:.*/g, `gz_size: "${prodSize}"`)
- .replace(/\/vue@[\d\.]+\//g, `/vue@${version}/`)
- )
- console.log(`\nSuccessfully updated Vue version and gzip file size.\n`)
-}).catch(err => {
- console.error(err)
- process.exit(1)
-})
-
-function download (file) {
- return new Promise((resolve, reject) => {
- request({
- url: `http://unpkg.com/vue@${version}/dist/${file}`,
- encoding: null
- }, (err, res, body) => {
- if (err) {
- return reject(err)
- }
- if (res.statusCode != 200) {
- return reject(
- `unexpected response code when downloading from unpkg: ${res.statusCode}` +
- `\n${body.toString()}`
- )
- }
- fs.writeFile(`themes/vue/source/js/${file}`, body, err => {
- if (err) return reject(err)
- zlib.gzip(body, (err, zipped) => {
- if (err) return reject(err)
- resolve((zipped.length / 1024).toFixed(2))
- })
- })
- })
- })
-}
diff --git a/src/_posts/common-gotchas.md b/src/_posts/common-gotchas.md
index a8abf2314e..c4ed741291 100644
--- a/src/_posts/common-gotchas.md
+++ b/src/_posts/common-gotchas.md
@@ -15,7 +15,7 @@ Most of the time, when you change a Vue instance's data, the view updates. But t
2. When you modify an Array by directly setting an index (e.g. `arr[0] = val`) or modifying its `length` property. Similarly, Vue.js cannot pickup these changes. Always modify arrays by using an Array instance method, or replacing it entirely. Vue provides a convenience method `arr.$set(index, value)` which is syntax sugar for `arr.splice(index, 1, value)`.
-Further reading: [Reactivity in Depth](/guide/reactivity.html) and [Array Change Detection](http://vuejs.org/guide/list.html#Array-Change-Detection).
+Further reading: [Reactivity in Depth](/guide/reactivity.html) and [Array Change Detection](/guide/list.html#Array-Change-Detection).
### When is the DOM updated?
@@ -33,6 +33,6 @@ Further reading: [Component Option Caveats](/guide/components.html#Component-Opt
All Vue.js templates are valid, parsable HTML markup, and Vue.js relies on spec-compliant parsers to process its templates. However, as specified in the standard, HTML is case-insensitive when matching tag and attribute names. This means camelCase attributes like `:myProp="123"` will be matched as `:myprop="123"`. As a rule of thumb, you should use camelCase in JavaScript and kebab-case in templates. For example a prop defined in JavaScript as `myProp` should be bound in templates as `:my-prop`.
-Further reading: [camelCase vs. kebab-case](http://vuejs.org/guide/components.html#camelCase-vs-kebab-case).
+Further reading: [camelCase vs. kebab-case](/guide/components.html#camelCase-vs-kebab-case).
We are also discussing the possibility of eliminating this inconsistency by resolving props and components in a case-insensitive manner. Join the conversation [here](https://github.com/vuejs/vue/issues/2308).
diff --git a/src/_posts/why-no-template-url.md b/src/_posts/why-no-template-url.md
index f6fbabe2dd..8ffacabbbb 100644
--- a/src/_posts/why-no-template-url.md
+++ b/src/_posts/why-no-template-url.md
@@ -13,8 +13,8 @@ First, it allows us to write our template in a separate HTML file. This gives us
Second, because `templateURL` loads the template via Ajax at runtime, you don't need a build step in order to split up your files. This is convenient during development, but comes at a serious cost when you want to deploy it to production. Before HTTP/2 is universally supported, the number of HTTP requests is still probably the most critical factor in your app's initial load performance. Now imagine you use `templateURL` for every component in your app - the browser needs to perform dozens of HTTP requests before even being able to display anything! In case you don't know, most browsers limit the number of parallel requests it can perform to a single server. When you exceed that limit, your app's initial rendering will suffer for every extra round trip the browser has to wait for. Sure, there are build tools that can help you pre-register all those templates in `$templateCache` - but that shows us a build step is, in fact, inevitable for any serious frontend development.
-So, without `templateURL`, how do we deal with the development experience problem? Writing templates as inline JavaScript strings is terrible, faking templates with `
+
+
+{% endraw %}
diff --git a/src/support-vuejs/index.md b/src/support-vuejs/index.md
index e010c9081d..679571bc4c 100644
--- a/src/support-vuejs/index.md
+++ b/src/support-vuejs/index.md
@@ -1,3 +1,4 @@
---
sponsors: true
+type: sponsors
---
diff --git a/src/v2/api/index.md b/src/v2/api/index.md
index 74bb867e9c..2e073bbcb6 100644
--- a/src/v2/api/index.md
+++ b/src/v2/api/index.md
@@ -82,7 +82,9 @@ type: api
> In 2.2.0+, this hook also captures errors in component lifecycle hooks. Also, when this hook is `undefined`, captured errors will be logged with `console.error` instead of crashing the app.
- > In 2.4.0+ this hook also captures errors thrown inside Vue custom event handlers.
+ > In 2.4.0+, this hook also captures errors thrown inside Vue custom event handlers.
+
+ > In 2.6.0+, this hook also captures errors thrown inside `v-on` DOM listeners. In addition, if any of the covered hooks or handlers returns a Promise chain (e.g. async functions), the error from that Promise chain will also be handled.
> Error tracking services [Sentry](https://sentry.io/for/vue/) and [Bugsnag](https://docs.bugsnag.com/platforms/browsers/vue/) provide official integrations using this option.
@@ -244,28 +246,28 @@ type: api
- **See also:** [Async Update Queue](../guide/reactivity.html#Async-Update-Queue)
-### Vue.set( target, key, value )
+### Vue.set( target, propertyName/index, value )
- **Arguments:**
- `{Object | Array} target`
- - `{string | number} key`
+ - `{string | number} propertyName/index`
- `{any} value`
- **Returns:** the set value.
- **Usage:**
- Set a property on an object. If the object is reactive, ensure the property is created as a reactive property and trigger view updates. This is primarily used to get around the limitation that Vue cannot detect property additions.
+ Adds a property to a reactive object, ensuring the new property is also reactive, so triggers view updates. This must be used to add new properties to reactive objects, as Vue cannot detect normal property additions (e.g. `this.myObject.newProperty = 'hi'`).
The target object cannot be a Vue instance, or the root data object of a Vue instance.
- **See also:** [Reactivity in Depth](../guide/reactivity.html)
-### Vue.delete( target, key )
+### Vue.delete( target, propertyName/index )
- **Arguments:**
- `{Object | Array} target`
- - `{string | number} key/index`
+ - `{string | number} propertyName/index`
> Only in 2.2.0+: Also works with Array + index.
@@ -362,6 +364,8 @@ type: api
Install a Vue.js plugin. If the plugin is an Object, it must expose an `install` method. If it is a function itself, it will be treated as the install method. The install method will be called with Vue as the argument.
+ This method has to be called before calling `new Vue()`
+
When this method is called on the same plugin multiple times, the plugin will be installed only once.
- **See also:** [Plugins](../guide/plugins.html)
@@ -400,6 +404,35 @@ type: api
- **See also:** [Render Functions](../guide/render-function.html)
+### Vue.observable( object )
+
+> New in 2.6.0+
+
+- **Arguments:**
+ - `{Object} object`
+
+- **Usage:**
+
+ Make an object reactive. Internally, Vue uses this on the object returned by the `data` function.
+
+ The returned object can be used directly inside [render functions](../guide/render-function.html) and [computed properties](../guide/computed.html), and will trigger appropriate updates when mutated. It can also be used as a minimal, cross-component state store for simple scenarios:
+
+ ``` js
+ const state = Vue.observable({ count: 0 })
+
+ const Demo = {
+ render(h) {
+ return h('button', {
+ on: { click: () => { state.count++ }}
+ }, `count is: ${state.count}`)
+ }
+ }
+ ```
+
+ In Vue 2.x, `Vue.observable` directly mutates the object passed to it, so that it is equivalent to the object returned, as [demonstrated here](../guide/instance.html#Data-and-Methods). In Vue 3.x, a reactive proxy will be returned instead, leaving the original object non-reactive if mutated directly. Therefore, for future compatibility, we recommend always working with the object returned by `Vue.observable`, rather than the object originally passed to it.
+
+- **See also:** [Reactivity in Depth](../guide/reactivity.html)
+
### Vue.version
- **Details**: Provides the installed version of Vue as a string. This is especially useful for community plugins and components, where you might use different strategies for different versions.
@@ -460,7 +493,11 @@ type: api
})
```
- Note that __you should not use an arrow function with the `data` property__ (e.g. `data: () => { return { a: this.myProp }}`). The reason is arrow functions bind the parent context, so `this` will not be the Vue instance as you expect and `this.myProp` will be undefined.
+ Note that if you use an arrow function with the `data` property, `this` won't be the component's instance, but you can still access the instance as the function's first argument:
+
+ ```js
+ data: vm => ({ a: vm.myProp })
+ ```
- **See also:** [Reactivity in Depth](../guide/reactivity.html)
@@ -472,6 +509,15 @@ type: api
A list/hash of attributes that are exposed to accept data from the parent component. It has an Array-based simple syntax and an alternative Object-based syntax that allows advanced configurations such as type checking, custom validation and default values.
+ With Object-based syntax, you can use following options:
+ - `type`: can be one of the following native constructors: `String`, `Number`, `Boolean`, `Array`, `Object`, `Date`, `Function`, `Symbol`, any custom constructor function or an array of those. Will check if a prop has a given type, and will throw a warning if it doesn't. [More information](../guide/components-props.html#Prop-Types) on prop types.
+ - `default`: `any`
+ Specifies a default value for the prop. If the prop is not passed, this value will be used instead. Object or array defaults must be returned from a factory function.
+ - `required`: `Boolean`
+ Defines if the prop is required. In a non-production environment, a console warning will be thrown if this value is truthy and the prop is not passed.
+ - `validator`: `Function`
+ Custom validator function that takes the prop value as the sole argument. In a non-production environment, a console warning will be thrown if this function returns a falsy value (i.e. the validation fails). You can read more about prop validation [here](../guide/components-props.html#Prop-Validation).
+
- **Example:**
``` js
@@ -498,7 +544,7 @@ type: api
})
```
-- **See also:** [Props](../guide/components.html#Props)
+- **See also:** [Props](../guide/components-props.html)
### propsData
@@ -533,7 +579,13 @@ type: api
Computed properties to be mixed into the Vue instance. All getters and setters have their `this` context automatically bound to the Vue instance.
- Note that __you should not use an arrow function to define a computed property__ (e.g. `aDouble: () => this.a * 2`). The reason is arrow functions bind the parent context, so `this` will not be the Vue instance as you expect and `this.a` will be undefined.
+ Note that if you use an arrow function with a computed property, `this` won't be the component's instance, but you can still access the instance as the function's first argument:
+
+ ```js
+ computed: {
+ aDouble: vm => vm.a * 2
+ }
+ ```
Computed properties are cached, and only re-computed on reactive dependency changes. Note that if a certain dependency is out of the instance's scope (i.e. not reactive), the computed property will __not__ be updated.
@@ -622,19 +674,24 @@ type: api
},
// string method name
b: 'someMethod',
- // deep watcher
+ // the callback will be called whenever any of the watched object properties change regardless of their nested depth
c: {
handler: function (val, oldVal) { /* ... */ },
deep: true
},
// the callback will be called immediately after the start of the observation
d: {
- handler: function (val, oldVal) { /* ... */ },
+ handler: 'someMethod',
immediate: true
},
+ // you can pass array of callbacks, they will be called one-by-one
e: [
- function handle1 (val, oldVal) { /* ... */ },
- function handle2 (val, oldVal) { /* ... */ }
+ 'handle1',
+ function handle2 (val, oldVal) { /* ... */ },
+ {
+ handler: function handle3 (val, oldVal) { /* ... */ },
+ /* ... */
+ }
],
// watch vm.e.f's value: {g: 5}
'e.f': function (val, oldVal) { /* ... */ }
@@ -651,7 +708,7 @@ type: api
### el
-- **Type:** `string | HTMLElement`
+- **Type:** `string | Element`
- **Restriction:** only respected in instance creation via `new`.
@@ -886,7 +943,7 @@ type: api
- **Details:**
- Called when an error from any descendent component is captured. The hook receives three arguments: the error, the component instance that triggered the error, and a string containing information on where the error was captured. The hook can return `false` to stop the error from propagating further.
+ Called when an error from any descendant component is captured. The hook receives three arguments: the error, the component instance that triggered the error, and a string containing information on where the error was captured. The hook can return `false` to stop the error from propagating further.
You can modify component state in this hook. However, it is important to have conditionals in your template or render function that short circuits other content when an error has been captured; otherwise the component will be thrown into an infinite render loop.
@@ -1002,9 +1059,7 @@ type: api
- **Details:**
- `provide` and `inject` are primarily provided for advanced plugin / component library use cases. It is NOT recommended to use them in generic application code.
-
- This pair of options are used together to allow an ancestor component to serve as a dependency injector for its all descendants, regardless of how deep the component hierarchy is, as long as they are in the same parent chain. If you are familiar with React, this is very similar to React's context feature.
+ This pair of options are used together to allow an ancestor component to serve as a dependency injector for all its descendants, regardless of how deep the component hierarchy is, as long as they are in the same parent chain. If you are familiar with React, this is very similar to React's context feature.
The `provide` option should be an object or a function that returns an object. This object contains the properties that are available for injection into its descendants. You can use ES2015 Symbols as keys in this object, but only in environments that natively support `Symbol` and `Reflect.ownKeys`.
@@ -1013,7 +1068,7 @@ type: api
- an object where the keys are the local binding name and the value is either:
- the key (string or Symbol) to search for in available injections, or
- an object where:
- - the `name` property is the key (string or Symbol) to search for in available injections, and
+ - the `from` property is the key (string or Symbol) to search for in available injections, and
- the `default` property is used as fallback value
> Note: the `provide` and `inject` bindings are NOT reactive. This is intentional. However, if you pass down an observed object, properties on that object do remain reactive.
@@ -1021,6 +1076,7 @@ type: api
- **Example:**
``` js
+ // parent component providing 'foo'
var Provider = {
provide: {
foo: 'bar'
@@ -1028,6 +1084,7 @@ type: api
// ...
}
+ // child component injecting 'foo'
var Child = {
inject: ['foo'],
created () {
@@ -1262,7 +1319,7 @@ type: api
### vm.$el
-- **Type:** `HTMLElement`
+- **Type:** `Element`
- **Read only**
@@ -1325,9 +1382,15 @@ type: api
- **Read only**
+- **Reactive?** No
+
- **Details:**
- Used to programmatically access content [distributed by slots](../guide/components.html#Content-Distribution-with-Slots). Each [named slot](../guide/components.html#Named-Slots) has its own corresponding property (e.g. the contents of `slot="foo"` will be found at `vm.$slots.foo`). The `default` property contains any nodes not included in a named slot.
+ Used to programmatically access content [distributed by slots](../guide/components.html#Content-Distribution-with-Slots). Each [named slot](../guide/components.html#Named-Slots) has its own corresponding property (e.g. the contents of `v-slot:foo` will be found at `vm.$slots.foo`). The `default` property contains either nodes not included in a named slot or contents of `v-slot:default`.
+
+ Please note that slots are **not** reactive. If you need a component to re-render based on changes to data passed to a slot, we suggest considering a different strategy that relies on a reactive instance option, such as `props` or `data`.
+
+ **Note:** `v-slot:foo` is supported in v2.6+. For older versions, you can use the [deprecated syntax](../guide/components-slots.html#Deprecated-Syntax).
Accessing `vm.$slots` is most useful when writing a component with a [render function](../guide/render-function.html).
@@ -1335,15 +1398,15 @@ type: api
```html
-
- About Me
-
+
+ About Me
+
Here's some page content, which will be included in vm.$slots.default, because it's not inside a named slot.
-
- Copyright 2016 Evan You
-
+
+ Copyright 2016 Evan You
+
If I have some content down here, it will also be included in vm.$slots.default.
.
@@ -1365,7 +1428,7 @@ type: api
```
- **See also:**
- - [`` Component](#slot-1)
+ - [`` Component](#slot)
- [Content Distribution with Slots](../guide/components.html#Content-Distribution-with-Slots)
- [Render Functions - Slots](../guide/render-function.html#Slots)
@@ -1373,7 +1436,7 @@ type: api
> New in 2.1.0+
-- **Type:** `{ [name: string]: props => VNode | Array }`
+- **Type:** `{ [name: string]: props => Array | undefined }`
- **Read only**
@@ -1383,8 +1446,14 @@ type: api
Accessing `vm.$scopedSlots` is most useful when writing a component with a [render function](../guide/render-function.html).
+ **Note:** since 2.6.0+, there are two notable changes to this property:
+
+ 1. Scoped slot functions are now guaranteed to return an array of VNodes, unless the return value is invalid, in which case the function will return `undefined`.
+
+ 2. All `$slots` are now also exposed on `$scopedSlots` as functions. If you work with render functions, it is now recommended to always access slots via `$scopedSlots`, whether they currently use a scope or not. This will not only make future refactors to add a scope simpler, but also ease your eventual migration to Vue 3, where all slots will be functions.
+
- **See also:**
- - [`` Component](#slot-1)
+ - [`` Component](#slot)
- [Scoped Slots](../guide/components.html#Scoped-Slots)
- [Render Functions - Slots](../guide/render-function.html#Slots)
@@ -1396,7 +1465,7 @@ type: api
- **Details:**
- An object that holds child components that have `ref` registered.
+ An object of DOM elements and component instances, registered with [`ref` attributes](#ref).
- **See also:**
- [Child Component Refs](../guide/components.html#Child-Component-Refs)
@@ -1416,6 +1485,8 @@ type: api
### vm.$attrs
+> New in 2.4.0+
+
- **Type:** `{ [key: string]: string }`
- **Read only**
@@ -1426,13 +1497,15 @@ type: api
### vm.$listeners
+> New in 2.4.0+
+
- **Type:** `{ [key: string]: Function | Array }`
- **Read only**
- **Details:**
- Contains parent-scope `v-on` event listeners (without `.native` modifiers). This can be passed down to an inner component via `v-on="$listeners"` - useful when creating higher-order components.
+ Contains parent-scope `v-on` event listeners (without `.native` modifiers). This can be passed down to an inner component via `v-on="$listeners"` - useful when creating transparent wrapper components.
## Instance Methods / Data
@@ -1464,6 +1537,9 @@ type: api
// function
vm.$watch(
function () {
+ // every time the expression `this.a + this.b` yields a different result,
+ // the handler will be called. It's as if we were watching a computed
+ // property without defining the computed property itself
return this.a + this.b
},
function (newVal, oldVal) {
@@ -1503,11 +1579,40 @@ type: api
// `callback` is fired immediately with current value of `a`
```
-### vm.$set( target, key, value )
+ Note that with `immediate` option you won't be able to unwatch the given property on the first callback call.
+
+ ``` js
+ // This will cause an error
+ var unwatch = vm.$watch(
+ 'value',
+ function () {
+ doSomething()
+ unwatch()
+ },
+ { immediate: true }
+ )
+ ```
+
+ If you still want to call an unwatch function inside the callback, you should check its availability first:
+
+ ``` js
+ var unwatch = vm.$watch(
+ 'value',
+ function () {
+ doSomething()
+ if (unwatch) {
+ unwatch()
+ }
+ },
+ { immediate: true }
+ )
+ ```
+
+### vm.$set( target, propertyName/index, value )
- **Arguments:**
- `{Object | Array} target`
- - `{string | number} key`
+ - `{string | number} propertyName/index`
- `{any} value`
- **Returns:** the set value.
@@ -1518,11 +1623,11 @@ type: api
- **See also:** [Vue.set](#Vue-set)
-### vm.$delete( target, key )
+### vm.$delete( target, propertyName/index )
- **Arguments:**
- `{Object | Array} target`
- - `{string | number} key`
+ - `{string | number} propertyName/index`
- **Usage:**
@@ -1578,14 +1683,139 @@ type: api
- If both event and callback are given, remove the listener for that specific callback only.
-### vm.$emit( event, [...args] )
+### vm.$emit( eventName, [...args] )
- **Arguments:**
- - `{string} event`
+ - `{string} eventName`
- `[...args]`
Trigger an event on the current instance. Any additional arguments will be passed into the listener's callback function.
+- **Examples:**
+
+ Using `$emit` with only an event name:
+
+ ```js
+ Vue.component('welcome-button', {
+ template: `
+
+ Click me to be welcomed
+
+ `
+ })
+ ```
+ ```html
+
+
+
+ ```
+ ```js
+ new Vue({
+ el: '#emit-example-simple',
+ methods: {
+ sayHi: function () {
+ alert('Hi!')
+ }
+ }
+ })
+ ```
+ {% raw %}
+
+
+
+
+ {% endraw %}
+
+ Using `$emit` with additional arguments:
+
+ ```js
+ Vue.component('magic-eight-ball', {
+ data: function () {
+ return {
+ possibleAdvice: ['Yes', 'No', 'Maybe']
+ }
+ },
+ methods: {
+ giveAdvice: function () {
+ var randomAdviceIndex = Math.floor(Math.random() * this.possibleAdvice.length)
+ this.$emit('give-advice', this.possibleAdvice[randomAdviceIndex])
+ }
+ },
+ template: `
+
+ Click me for advice
+
+ `
+ })
+ ```
+
+ ```html
+
+
+
+ ```
+
+ ```js
+ new Vue({
+ el: '#emit-example-argument',
+ methods: {
+ showAdvice: function (advice) {
+ alert(advice)
+ }
+ }
+ })
+ ```
+
+ {% raw %}
+
+
+
+
+ {% endraw %}
+
## Instance Methods / Lifecycle
### vm.$mount( [elementOrSelector] )
@@ -1798,7 +2028,7 @@ type: api
### v-for
-- **Expects:** `Array | Object | number | string`
+- **Expects:** `Array | Object | number | string | Iterable (since 2.6)`
- **Usage:**
@@ -1815,7 +2045,7 @@ type: api
``` html
-
+
```
The default behavior of `v-for` will try to patch the elements in-place without moving them. To force it to reorder elements, you need to provide an ordering hint with the `key` special attribute:
@@ -1826,6 +2056,8 @@ type: api
```
+ In 2.6+, `v-for` can also work on values that implement the [Iterable Protocol](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#The_iterable_protocol), including native `Map` and `Set`. However, it should be noted that Vue 2.x currently does not support reactivity on `Map` and `Set` values, so cannot automatically detect changes.
+
When used together with v-if, v-for has a higher priority than v-if. See the list rendering guide for details.
The detailed usage for `v-for` is explained in the guide section linked below.
@@ -1859,20 +2091,20 @@ type: api
Attaches an event listener to the element. The event type is denoted by the argument. The expression can be a method name, an inline statement, or omitted if there are modifiers present.
- Starting in 2.4.0+, `v-on` also supports binding to an object of event/listener pairs without an argument. Note when using the object syntax, it does not support any modifiers.
-
When used on a normal element, it listens to [**native DOM events**](https://developer.mozilla.org/en-US/docs/Web/Events) only. When used on a custom element component, it listens to **custom events** emitted on that child component.
When listening to native DOM events, the method receives the native event as the only argument. If using inline statement, the statement has access to the special `$event` property: `v-on:click="handle('ok', $event)"`.
+ Starting in 2.4.0+, `v-on` also supports binding to an object of event/listener pairs without an argument. Note when using the object syntax, it does not support any modifiers.
+
- **Example:**
```html
-
-
+
+
@@ -1880,6 +2112,9 @@ type: api
+
+
+
@@ -1900,6 +2135,9 @@ type: api
+
+
+
```
Listening to custom events on a child component (the handler is called when "my-event" is emitted on the child):
@@ -1947,16 +2185,22 @@ type: api
+
+
+
+
+
+
-
+
@@ -2003,7 +2247,7 @@ type: api
- **Modifiers:**
- [`.lazy`](../guide/forms.html#lazy) - listen to `change` events instead of `input`
- - [`.number`](../guide/forms.html#number) - cast input string to numbers
+ - [`.number`](../guide/forms.html#number) - cast valid input string to numbers
- [`.trim`](../guide/forms.html#trim) - trim input
- **Usage:**
@@ -2014,6 +2258,59 @@ type: api
- [Form Input Bindings](../guide/forms.html)
- [Components - Form Input Components using Custom Events](../guide/components.html#Form-Input-Components-using-Custom-Events)
+### v-slot
+
+- **Shorthand:** `#`
+
+- **Expects:** JavaScript expression that is valid in a function argument position (supports destructuring in [supported environments](../guide/components-slots.html#Slot-Props-Destructuring)). Optional - only needed if expecting props to be passed to the slot.
+
+- **Argument:** slot name (optional, defaults to `default`)
+
+- **Limited to:**
+ - `
`
+ - [components](../guide/components-slots.html#Abbreviated-Syntax-for-Lone-Default-Slots) (for a lone default slot with props)
+
+- **Usage:**
+
+ Denote named slots or slots that expect to receive props.
+
+- **Example:**
+
+ ```html
+
+
+
+ Header content
+
+
+ Default slot content
+
+
+ Footer content
+
+
+
+
+
+
+
+ {{ slotProps.item.text }}
+
+
+
+
+
+
+ Mouse position: {{ x }}, {{ y }}
+
+ ```
+
+ For more details, see the links below.
+
+- **See also:**
+ - [Components - Slots](../guide/components-slots.html)
+ - [RFC-0001](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0001-new-slot-syntax.md)
+
### v-pre
- **Does not expect expression**
@@ -2084,7 +2381,7 @@ type: api
### key
-- **Expects:** `number | string`
+- **Expects:** `number | string | boolean (since 2.4.2) | symbol (since 2.5.12)`
The `key` special attribute is primarily used as a hint for Vue's virtual DOM algorithm to identify VNodes when diffing the new list of nodes against the old list. Without keys, Vue uses an algorithm that minimizes element movement and tries to patch/reuse elements of the same type in-place as much as possible. With keys, it will reorder elements based on the order change of keys, and elements with keys that are no longer present will always be removed/destroyed.
@@ -2123,8 +2420,8 @@ type: api
hello
-
-
+
+
```
When used on elements/components with `v-for`, the registered reference will be an Array containing DOM nodes or component instances.
@@ -2133,41 +2430,9 @@ type: api
- **See also:** [Child Component Refs](../guide/components.html#Child-Component-Refs)
-### slot
-
-- **Expects:** `string`
-
- Used on content inserted into child components to indicate which named slot the content belongs to.
-
- For detailed usage, see the guide section linked below.
-
-- **See also:** [Named Slots](../guide/components.html#Named-Slots)
-
-### slot-scope
-
-> New in 2.5.0+
-
-- **Expects:** `function argument expression`
-
-- **Usage:**
-
- Used to denote an element or component as a scoped slot. The attribute's value should be a valid JavaScript expression that can appear in the argument position of a function signature. This means in supported environments you can also use ES2015 destructuring in the expression. Serves as a replacement for [`scope`](#scope-replaced) in 2.5.0+.
-
- This attribute does not support dynamic binding.
-
-- **See also:** [Scoped Slots](../guide/components.html#Scoped-Slots)
-
-### scope replaced
-
-Used to denote a `` element as a scoped slot, which is replaced by [`slot-scope`](#slot-scope) in 2.5.0+.
-
-- **Usage:**
-
- Same as [`slot-scope`](#slot-scope) except that `scope` can only be used on `` elements.
-
### is
-- **Expects:** `string`
+- **Expects:** `string | Object (component’s options object)`
Used for [dynamic components](../guide/components.html#Dynamic-Components) and to work around [limitations of in-DOM templates](../guide/components.html#DOM-Template-Parsing-Caveats).
@@ -2190,6 +2455,40 @@ Used to denote a `` element as a scoped slot, which is replaced by [`s
- [Dynamic Components](../guide/components.html#Dynamic-Components)
- [DOM Template Parsing Caveats](../guide/components.html#DOM-Template-Parsing-Caveats)
+### slot deprecated
+
+**Prefer [v-slot](#v-slot) in 2.6.0+.**
+
+- **Expects:** `string`
+
+ Used on content inserted into child components to indicate which named slot the content belongs to.
+
+- **See also:** [Named Slots with `slot`](../guide/components.html#Named-Slots-with-slot)
+
+### slot-scope deprecated
+
+**Prefer [v-slot](#v-slot) in 2.6.0+.**
+
+- **Expects:** `function argument expression`
+
+- **Usage:**
+
+ Used to denote an element or component as a scoped slot. The attribute's value should be a valid JavaScript expression that can appear in the argument position of a function signature. This means in supported environments you can also use ES2015 destructuring in the expression. Serves as a replacement for [`scope`](#scope-replaced) in 2.5.0+.
+
+ This attribute does not support dynamic binding.
+
+- **See also:** [Scoped Slots with `slot-scope`](../guide/components.html#Scoped-Slots-with-slot-scope)
+
+### scope removed
+
+**Replaced by [slot-scope](#slot-scope) in 2.5.0+. Prefer [v-slot](#v-slot) in 2.6.0+.**
+
+Used to denote a `` element as a scoped slot.
+
+- **Usage:**
+
+ Same as [`slot-scope`](#slot-scope) except that `scope` can only be used on `` elements.
+
## Built-In Components
### component
@@ -2219,8 +2518,9 @@ Used to denote a `` element as a scoped slot, which is replaced by [`s
- `name` - string, Used to automatically generate transition CSS class names. e.g. `name: 'fade'` will auto expand to `.fade-enter`, `.fade-enter-active`, etc. Defaults to `"v"`.
- `appear` - boolean, Whether to apply transition on initial render. Defaults to `false`.
- `css` - boolean, Whether to apply CSS transition classes. Defaults to `true`. If set to `false`, will only trigger JavaScript hooks registered via component events.
- - `type` - string, Specify the type of transition events to wait for to determine transition end timing. Available values are `"transition"` and `"animation"`. By default, it will automatically detect the type that has a longer duration.
+ - `type` - string, Specifies the type of transition events to wait for to determine transition end timing. Available values are `"transition"` and `"animation"`. By default, it will automatically detect the type that has a longer duration.
- `mode` - string, Controls the timing sequence of leaving/entering transitions. Available modes are `"out-in"` and `"in-out"`; defaults to simultaneous.
+ - `duration` - number | { `enter`: number, `leave`: number }, Specifies the duration of transition. By default, Vue waits for the first `transitionend` or `animationend` event on the root transition element.
- `enter-class` - string
- `leave-class` - string
- `appear-class` - string
@@ -2294,11 +2594,11 @@ Used to denote a `` element as a scoped slot, which is replaced by [`s
- **Usage:**
- `` serve as transition effects for **multiple** elements/components. The `` renders a real DOM element. By default it renders a ``, and you can configure what element is should render via the `tag` attribute.
+ `` serve as transition effects for **multiple** elements/components. The `` renders a real DOM element. By default it renders a ``, and you can configure what element it should render via the `tag` attribute.
- Note every child in a `` must be **uniquely keyed** for the animations to work properly.
+ Note that every child in a `` must be **uniquely keyed** for the animations to work properly.
- `` supports moving transitions via CSS transform. When a child's position on screen has changed after an updated, it will get applied a moving CSS class (auto generated from the `name` attribute or configured with the `move-class` attribute). If the CSS `transform` property is "transition-able" when the moving class is applied, the element will be smoothly animated to its destination using the [FLIP technique](https://aerotwist.com/blog/flip-your-animations/).
+ `` supports moving transitions via CSS transform. When a child's position on screen has changed after an update, it will get applied a moving CSS class (auto generated from the `name` attribute or configured with the `move-class` attribute). If the CSS `transform` property is "transition-able" when the moving class is applied, the element will be smoothly animated to its destination using the [FLIP technique](https://aerotwist.com/blog/flip-your-animations/).
```html
@@ -2313,8 +2613,9 @@ Used to denote a `` element as a scoped slot, which is replaced by [`s
### keep-alive
- **Props:**
- - `include` - string or RegExp or Array. Only components matched by this will be cached.
- - `exclude` - string or RegExp or Array. Any component matched by this will not be cached.
+ - `include` - string or RegExp or Array. Only components with matching names will be cached.
+ - `exclude` - string or RegExp or Array. Any component with a matching name will not be cached.
+ - `max` - number. The maximum number of component instances to cache.
- **Usage:**
@@ -2324,7 +2625,7 @@ Used to denote a `` element as a scoped slot, which is replaced by [`s
> In 2.2.0+ and above, `activated` and `deactivated` will fire for all nested components inside a `` tree.
- Primarily used with preserve component state or avoid re-rendering.
+ Primarily used to preserve component state or avoid re-rendering.
```html
@@ -2373,6 +2674,18 @@ Used to denote a `` element as a scoped slot, which is replaced by [`s
The match is first checked on the component's own `name` option, then its local registration name (the key in the parent's `components` option) if the `name` option is not available. Anonymous components cannot be matched against.
+- **`max`**
+
+ > New in 2.5.0+
+
+ The maximum number of component instances to cache. Once this number is reached, the cached component instance that was least recently accessed will be destroyed before creating a new instance.
+
+ ``` html
+
+
+
+ ```
+
`` does not work with functional components because they do not have instances to be cached.
- **See also:** [Dynamic Components - keep-alive](../guide/components.html#keep-alive)
diff --git a/src/v2/cookbook/adding-instance-properties.md b/src/v2/cookbook/adding-instance-properties.md
index 4737c8cb34..8df1c7eab0 100644
--- a/src/v2/cookbook/adding-instance-properties.md
+++ b/src/v2/cookbook/adding-instance-properties.md
@@ -6,7 +6,7 @@ order: 2
## Base Example
-There may be data/utilities you'd like to use in many components, but you don't want to [pollute the global scope](https://github.com/getify/You-Dont-Know-JS/blob/master/scope%20%26%20closures/ch3.md). In these cases, you can make them available to each Vue instance by defining them on the prototype:
+There may be data/utilities you'd like to use in many components, but you don't want to [pollute the global scope](https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/scope-closures/ch3.md). In these cases, you can make them available to each Vue instance by defining them on the prototype:
```js
Vue.prototype.$appName = 'My App'
@@ -58,7 +58,7 @@ new Vue({
})
```
-It would be `"My App"`, then `"The name of some other app"`, because `this.appName` is overwritten ([sort of](https://github.com/getify/You-Dont-Know-JS/blob/master/this%20%26%20object%20prototypes/ch5.md)) by `data` when the instance is created. We scope instance properties with `$` to avoid this. You can even use your own convention if you'd like, such as `$_appName` or `ΩappName`, to prevent even conflicts with plugins or future features.
+It would be `"My App"`, then `"The name of some other app"`, because `this.appName` is overwritten ([sort of](https://github.com/getify/You-Dont-Know-JS/blob/1st-ed/this%20%26%20object%20prototypes/ch5.md)) by `data` when the instance is created. We scope instance properties with `$` to avoid this. You can even use your own convention if you'd like, such as `$_appName` or `ΩappName`, to prevent even conflicts with plugins or future features.
## Real-World Example: Replacing Vue Resource with Axios
@@ -165,7 +165,7 @@ If what you want to add has nothing to do with Vue specifically, this may be a g
```js
var App = Object.freeze({
name: 'My App',
- description: '2.1.4',
+ version: '2.1.4',
helpers: {
// This is a purely functional version of
// the $reverseText method we saw earlier
diff --git a/src/v2/cookbook/avoiding-memory-leaks.md b/src/v2/cookbook/avoiding-memory-leaks.md
new file mode 100644
index 0000000000..f4b0f071ed
--- /dev/null
+++ b/src/v2/cookbook/avoiding-memory-leaks.md
@@ -0,0 +1,178 @@
+---
+title: Avoiding Memory Leaks
+type: cookbook
+order: 10
+---
+
+## Introduction
+
+If you are developing applications with Vue, then you need to watch out for memory leaks. This issue is especially important in Single Page Applications (SPAs) because by design, users should not have to refresh their browser when using an SPA, so it is up to the JavaScript application to clean up components and make sure that garbage collection takes place as expected.
+
+Memory leaks in Vue applications do not typically come from Vue itself, rather they can happen when incorporating other libraries into an application.
+
+## Simple Example
+
+The following example shows a memory leak caused by using the [Choices.js](https://github.com/jshjohnson/Choices) library in a Vue component and not properly cleaning it up. Later, we will show how to remove the Choices.js footprint and avoid the memory leak.
+
+In the example below, we load up a select with a lot of options and then we use a show/hide button with a [v-if](/v2/guide/conditional.html) directive to add it and remove it from the virtual DOM. The problem with this example is that the `v-if` directive removes the parent element from the DOM, but we did not clean up the additional DOM pieces created by Choices.js, causing a memory leak.
+
+```html
+
+
+
+
+```
+
+```js
+new Vue({
+ el: "#app",
+ data: function () {
+ return {
+ showChoices: true
+ }
+ },
+ mounted: function () {
+ this.initializeChoices()
+ },
+ methods: {
+ initializeChoices: function () {
+ let list = []
+ // lets load up our select with many choices
+ // so it will use a lot of memory
+ for (let i = 0; i < 1000; i++) {
+ list.push({
+ label: "Item " + i,
+ value: i
+ })
+ }
+ new Choices("#choices-single-default", {
+ searchEnabled: true,
+ removeItemButton: true,
+ choices: list
+ })
+ },
+ show: function () {
+ this.showChoices = true
+ this.$nextTick(() => {
+ this.initializeChoices()
+ })
+ },
+ hide: function () {
+ this.showChoices = false
+ }
+ }
+})
+```
+
+To see this memory leak in action, open this [CodePen example](https://codepen.io/freeman-g/pen/qobpxo) using Chrome and then open the Chrome Task Manager. To open the Chrome Task Manager on Mac, choose Chrome Top Navigation > Window > Task Manager or on Windows, use the Shift+Esc shortcut. Now, click the show/hide button 50 or so times. You should see the memory usage in the Chrome Task Manager increase and never be reclaimed.
+
+
+
+## Resolving the Memory Leak
+
+In the above example, we can use our `hide()` method to do some clean up and solve the memory leak prior to removing the select from the DOM. To accomplish this, we will keep a property in our Vue instance’s data object and we will use the [Choices API’s](https://github.com/jshjohnson/Choices) `destroy()` method to perform the clean up.
+
+Check the memory usage again with this [updated CodePen example](https://codepen.io/freeman-g/pen/mxWMor).
+
+```js
+new Vue({
+ el: "#app",
+ data: function () {
+ return {
+ showChoices: true,
+ choicesSelect: null
+ }
+ },
+ mounted: function () {
+ this.initializeChoices()
+ },
+ methods: {
+ initializeChoices: function () {
+ let list = []
+ for (let i = 0; i < 1000; i++) {
+ list.push({
+ label: "Item " + i,
+ value: i
+ })
+ }
+ // Set a reference to our choicesSelect in our Vue instance's data object
+ this.choicesSelect = new Choices("#choices-single-default", {
+ searchEnabled: true,
+ removeItemButton: true,
+ choices: list
+ })
+ },
+ show: function () {
+ this.showChoices = true
+ this.$nextTick(() => {
+ this.initializeChoices()
+ })
+ },
+ hide: function () {
+ // now we can use the reference to Choices to perform clean up here
+ // prior to removing the elements from the DOM
+ this.choicesSelect.destroy()
+ this.showChoices = false
+ }
+ }
+})
+```
+
+## Details about the Value
+
+Memory management and performance testing can easily be neglected in the excitement of shipping quickly, however, keeping a small memory footprint is still important to your overall user experience.
+
+Consider the types of devices your users may be using and what their normal flow will be. Could they use memory constrained laptops or mobile devices? Do your users typically do lots of in-application navigation? If either of these are true, then good memory management practices can help you avoid the worst case scenario of crashing a user’s browser. Even if neither of these are true, you can still potentially have degradation of performance over extended usage of your app if you are not careful.
+
+## Real-World Example
+
+In the above example, we used a `v-if` directive to illustrate the memory leak, but a more common real-world scenario happens when using [vue-router](https://router.vuejs.org/en/) to route to components in a Single Page Application.
+
+Just like the `v-if` directive, `vue-router` removes elements from the virtual DOM and replaces those with new elements when a user navigates around your application. The Vue `beforeDestroy()` [lifecycle hook](/v2/guide/instance.html#Lifecycle-Diagram) is a good place to solve the same sort of issue in a `vue-router` based application.
+
+We could move our clean up into the `beforeDestroy()` hook like this:
+
+```js
+beforeDestroy: function () {
+ this.choicesSelect.destroy()
+}
+```
+
+## Alternative Patterns
+
+We have discussed managing memory when removing elements, but what if you intentionally want to preserve state and keep elements in memory? In this case, you can use the built-in component [keep-alive](/v2/api/#keep-alive).
+
+When you wrap a component with `keep-alive`, its state will be preserved and therefore kept in memory.
+
+```html
+Hide
+
+
+
+
+```
+This technique can be useful to improve user experience. For example, imagine a user starts entering comments into a text input and then decides to navigate away. If the user then navigated back, their comments would still be preserved.
+
+Once you use keep-alive, then you have access to two more lifecycle hooks: `activated` and `deactivated`. If you do want to clean up or change data when a keep-alive component is removed, you can do so in the `deactivated` hook.
+
+```js
+deactivated: function () {
+ // remove any data you do not want to keep alive
+}
+```
+
+## Wrapping Up
+
+Vue makes it very easy to develop amazing, reactive JavaScript applications, but you still need to be careful about memory leaks. These leaks will often occur when using additional 3rd Party libraries that manipulate the DOM outside of Vue. Make sure to test your application for memory leaks and take appropriate steps to clean up components where necessary.
\ No newline at end of file
diff --git a/src/v2/cookbook/client-side-storage.md b/src/v2/cookbook/client-side-storage.md
new file mode 100644
index 0000000000..915ff798bf
--- /dev/null
+++ b/src/v2/cookbook/client-side-storage.md
@@ -0,0 +1,188 @@
+---
+title: Client-Side Storage
+type: cookbook
+order: 11
+---
+
+## Base Example
+
+Client-side storage is an excellent way to quickly add performance gains to an application. By storing data on the browser itself, you can skip fetching information from the server every time the user needs it. While especially useful when offline, even online users will benefit from using data locally versus a remote server. Client-side storage can be done with [cookies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Cookies), [Local Storage](https://developer.mozilla.org/en-US/docs/Web/API/Web_Storage_API) (technically "Web Storage"), [IndexedDB](https://developer.mozilla.org/en-US/docs/Web/API/IndexedDB_API), and [WebSQL](https://www.w3.org/TR/webdatabase/) (a deprecated method that should not be used in new projects).
+
+In this cookbook entry we'll focus on Local Storage, the simplest of the storage mechanisms. Local Storage uses a key/value system for storing data. It is limited to storing only simple values but complex data can be stored if you are willing to encode and decode the values with JSON. In general, Local Storage is appropriate for smaller sets of data you would want to persist, things like user preferences or form data. Larger data with more complex storage needs would be better stored typically in IndexedDB.
+
+Let's begin with a simple form based example:
+
+``` html
+
+ My name is
+
+```
+
+This example has one form field bound to a Vue value called `name`. Here's the JavaScript:
+
+``` js
+const app = new Vue({
+ el: '#app',
+ data: {
+ name: ''
+ },
+ mounted() {
+ if (localStorage.name) {
+ this.name = localStorage.name;
+ }
+ },
+ watch: {
+ name(newName) {
+ localStorage.name = newName;
+ }
+ }
+});
+```
+
+Focus on the `mounted` and `watch` parts. We use `mounted` to handle loading the value from localStorage. To handle writing the data base, we watch the `name` value and on change, immediately write it.
+
+You can run this yourself here:
+
+See the Pen testing localstorage by Raymond Camden (@cfjedimaster ) on CodePen .
+
+
+Type something in the form and then reload this page. You'll note that the value you typed previously will show up automatically. Don't forget that your browser provides excellent developer tools for inspecting client-side storage. Here's an example in Firefox:
+
+
+
+And here it is in Chrome:
+
+
+
+And then finally, an example in Microsoft Edge. Note that you can find application storage values under the Debugger tab.
+
+
+
+As a quick aside, these dev tools also offer you a way to remove storage values. This can be very useful when testing.
+
+Immediately writing the value may not be advisable. Let's consider a slightly more advanced example. First, the updated form.
+
+``` html
+
+```
+
+Now we've got two fields (again, bound to a Vue instance) but now there is the addition of a button that runs a `persist` method. Let's look at the JavaScript.
+
+``` js
+const app = new Vue({
+ el: '#app',
+ data: {
+ name: '',
+ age: 0
+ },
+ mounted() {
+ if (localStorage.name) {
+ this.name = localStorage.name;
+ }
+ if (localStorage.age) {
+ this.age = localStorage.age;
+ }
+ },
+ methods: {
+ persist() {
+ localStorage.name = this.name;
+ localStorage.age = this.age;
+ console.log('now pretend I did more stuff...');
+ }
+ }
+})
+```
+
+As before, `mounted` is used to load persisted data, if it exists. This time, though, data is only persisted when the button is clicked. We could also do any validations or transformations here before storing the value. You could also store a date representing when the values were stored. With that metadata, the `mounted` method could make a logical call on whether or not to store the values again. You can try this version below.
+
+See the Pen testing localstorage 2 by Raymond Camden (@cfjedimaster ) on CodePen .
+
+
+## Working with Complex Values
+
+As mentioned above, Local Storage only works with simple values. To store more complex values, like objects or arrays, you must serialize and deserialize the values with JSON. Here is a more advanced example that persists an array of cats (the best kind of array possible).
+
+``` html
+
+
Cats
+
+
+ {{ cat }}
+ Remove
+
+
+
+
+
+ Add Cat
+
+
+```
+
+This "app" consists of a simple list on top (with a button to remove a cat) and a small form at the bottom to add a new cat. Now let's look at the JavaScript.
+
+``` js
+const app = new Vue({
+ el: '#app',
+ data: {
+ cats: [],
+ newCat: null
+ },
+ mounted() {
+ if (localStorage.getItem('cats')) {
+ try {
+ this.cats = JSON.parse(localStorage.getItem('cats'));
+ } catch(e) {
+ localStorage.removeItem('cats');
+ }
+ }
+ },
+ methods: {
+ addCat() {
+ // ensure they actually typed something
+ if (!this.newCat) {
+ return;
+ }
+
+ this.cats.push(this.newCat);
+ this.newCat = '';
+ this.saveCats();
+ },
+ removeCat(x) {
+ this.cats.splice(x, 1);
+ this.saveCats();
+ },
+ saveCats() {
+ const parsed = JSON.stringify(this.cats);
+ localStorage.setItem('cats', parsed);
+ }
+ }
+})
+```
+
+In this application, we've switched to use the Local Storage APIs versus "direct" access. Both work but the API method is generally preferred. `mounted` now has to grab the value and parse the JSON value. If anything goes wrong here we assume the data is corrupt and delete it. (Remember, any time your web application uses client-side storage, the user has access to it and can modify it at will.)
+
+We have three methods now to handle working with cats. Both `addCat` and `removeCat` handle updating the "live" Vue data stored in `this.cats`. They then run `saveCats` which handles serializing and persisting the data. You can play with this version below:
+
+See the Pen localstorage, complex by Raymond Camden (@cfjedimaster ) on CodePen .
+
+
+## Alternative Patterns
+
+While the Local Storage API is relatively simple, it is missing some basic features that would be useful in many applications. The following plugins wrap Local Storage access and make it easier to use, while also adding functionality like default values.
+
+* [vue-local-storage](https://github.com/pinguinjkeke/vue-local-storage)
+* [vue-reactive-storage](https://github.com/ropbla9/vue-reactive-storage)
+* [vue2-storage](https://github.com/yarkovaleksei/vue2-storage)
+
+## Wrapping Up
+
+While the browser will never replace a server persistence system, having multiple ways to cache data locally can be a huge performance boost for your application, and working with it in Vue.js makes it even more powerful.
diff --git a/src/v2/cookbook/creating-custom-scroll-directives.md b/src/v2/cookbook/creating-custom-scroll-directives.md
index 927179a314..645ba3eb5c 100644
--- a/src/v2/cookbook/creating-custom-scroll-directives.md
+++ b/src/v2/cookbook/creating-custom-scroll-directives.md
@@ -6,7 +6,7 @@ order: 7
## Base Example
-There are many times that we might want to add a bit of behavior, especially animation, to a scroll event on a site. There are many ways to do so, but the path with the least amount of code and dependencies is perhaps to use a [custom directive](https://vuejs.org/v2/guide/custom-directive.html) to create a hook for anything that fires off a particular scroll event.
+There are many times that we might want to add a bit of behavior, especially animation, to a scroll event on a site. There are many ways to do so, but the path with the least amount of code and dependencies is perhaps to use a [custom directive](/v2/guide/custom-directive.html) to create a hook for anything that fires off a particular scroll event.
```js
Vue.directive('scroll', {
@@ -40,7 +40,10 @@ new Vue({
```html
Scroll me
-
+
Lorem ipsum dolor sit amet, consectetur adipisicing elit. A atque amet harum aut ab veritatis earum porro praesentium ut corporis. Quasi provident dolorem officia iure fugiat, eius mollitia sequi quisquam.
@@ -50,7 +53,7 @@ new Vue({
We'd also need a style property that will transition the intermediary values here, in this case:
-```
+```css
.box {
transition: 1.5s all cubic-bezier(0.39, 0.575, 0.565, 1);
}
diff --git a/src/v2/cookbook/debugging-in-vscode.md b/src/v2/cookbook/debugging-in-vscode.md
index fd2f0eb5af..5c79d7b6dd 100644
--- a/src/v2/cookbook/debugging-in-vscode.md
+++ b/src/v2/cookbook/debugging-in-vscode.md
@@ -1,32 +1,49 @@
---
-title: Debugging in VS Code and Chrome
+title: Debugging in VS Code
type: cookbook
order: 8
---
-Every application reaches a point where it's necessary to understand failures, small to large. In this recipe, we explore a few workflows for VS Code users, who are using Chrome to test.
+Every application reaches a point where it's necessary to understand failures, small to large. In this recipe, we explore a few workflows for VS Code users who would like to debug their application in the browser.
-This recipe shows how to use the [Debugger for Chrome](https://github.com/Microsoft/VSCode-chrome-debug) extension with VS Code to debug Vue.js applications generated by the [Vue CLI](https://github.com/vuejs/vue-cli).
+This recipe shows how to debug [Vue CLI](https://github.com/vuejs/vue-cli) applications in VS Code as they run in the browser.
+
+
Note: This recipe covers Chrome and Firefox. If you know how to setup VS Code debugging with other browsers, please consider sharing your insights (see bottom of the page).
## Prerequisites
-You must have Chrome and VS Code installed. Make sure to get the latest version of [Debugger for Chrome](https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome) extension installed in VS Code.
+Make sure you have VS Code and the browser of your choice installed, and the latest version of the corresponding Debugger extension installed and enabled:
+
+* [Debugger for Chrome](https://marketplace.visualstudio.com/items?itemName=msjsdiag.debugger-for-chrome)
+* [Debugger for Firefox](https://marketplace.visualstudio.com/items?itemName=hbenl.vscode-firefox-debug)
-Install and create a project with the [vue-cli](https://github.com/vuejs/vue-cli), with the instructions for installation documented in the readme of the project. Change into the newly created application directory and open VS Code.
+Install and create a project with the [vue-cli](https://github.com/vuejs/vue-cli), following the instructions in the [Vue CLI Guide](https://cli.vuejs.org/). Change into the newly created application directory and open VS Code.
-### Showing Source Code in the Chrome Devtools
+### Displaying Source Code in the Browser
-Before you can debug your Vue components from VS Code you need to update the generated Webpack config to build sourcemaps. We do this so that our debugger has a way to map the code within a compressed file back to its position in the original file. This ensures that you can debug an application even after your assets have been optimized by Webpack.
+Before you can debug your Vue components from VS Code, you need to update the generated Webpack config to build sourcemaps. We do this so that our debugger has a way to map the code within a compressed file back to its position in the original file. This ensures that you can debug an application even after your assets have been optimized by Webpack.
-Go to `config/index.js` and find the `devtool` property. Update it to:
+If you use Vue CLI 2, set or update the `devtool` property inside `config/index.js`:
```json
devtool: 'source-map',
```
+If you use Vue CLI 3, set or update the `devtool` property inside `vue.config.js`:
+
+```js
+module.exports = {
+ configureWebpack: {
+ devtool: 'source-map'
+ }
+}
+```
+
### Launching the Application from VS Code
-Click on the Debugging icon in the Activity Bar to bring up the Debug view, then click on the gear icon to configure a launch.json file, selecting **Chrome** for the environment. Replace content of the generated launch.json with the following two configurations:
+
We're assuming the port to be `8080` here. If it's not the case (for instance, if `8080` has been taken and Vue CLI automatically picks another port for you), just modify the configuration accordingly.
+
+Click on the Debugging icon in the Activity Bar to bring up the Debug view, then click on the gear icon to configure a launch.json file, selecting **Chrome/Firefox: Launch** as the environment. Replace content of the generated launch.json with the corresponding configuration:

@@ -44,6 +61,14 @@ Click on the Debugging icon in the Activity Bar to bring up the Debug view, then
"sourceMapPathOverrides": {
"webpack:///src/*": "${webRoot}/*"
}
+ },
+ {
+ "type": "firefox",
+ "request": "launch",
+ "name": "vuejs: firefox",
+ "url": "http://localhost:8080/",
+ "webRoot": "${workspaceFolder}/src",
+ "pathMappings": [{ "url": "webpack:///src/", "path": "${webRoot}/" }]
}
]
}
@@ -53,40 +78,30 @@ Click on the Debugging icon in the Activity Bar to bring up the Debug view, then
1. Set a breakpoint in **src/components/HelloWorld.vue** on `line 90` where the `data` function returns a string.
-
+ 
2. Open your favorite terminal at the root folder and serve the app using Vue CLI:
-```
-npm start
-```
+ ```
+ npm run serve
+ ```
-3. Go to the Debug view, select the **'vuejs: chrome'** configuration, then press F5 or click the green play button.
+3. Go to the Debug view, select the **'vuejs: chrome/firefox'** configuration, then press F5 or click the green play button.
-4. Your breakpoint should now be hit as the new instance of Chrome opens `http://localhost:8080`.
+4. Your breakpoint should now be hit as a new browser instance opens `http://localhost:8080`.
-
+ 
## Alternative Patterns
### Vue Devtools
-There are other methods of debugging, varying in complexity. The most popular and simple of which is to use the excellent [vue-devtools](https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd). Some of the benefits of working with the devtools are that they enable you to live-edit data properties and see the changes reflected immediately. The other major benefit is the ability to do time travel debugging for Vuex.
+There are other methods of debugging, varying in complexity. The most popular and simple of which is to use the excellent Vue.js devtools [for Chrome](https://chrome.google.com/webstore/detail/vuejs-devtools/nhdogjmejiglipccpnnnanhbledajbpd) and [for Firefox](https://addons.mozilla.org/en-US/firefox/addon/vue-js-devtools/). Some of the benefits of working with the devtools are that they enable you to live-edit data properties and see the changes reflected immediately. The other major benefit is the ability to do time travel debugging for Vuex.

Please note that if the page uses a production/minified build of Vue.js (such as the standard link from a CDN), devtools inspection is disabled by default so the Vue pane won't show up. If you switch to an unminified version, you may have to give the page a hard refresh to see them.
-### Vuetron
-
-[Vuetron](http://vuetron.io/) is a really nice project that extends some of the work that vue-devtools has done. In addition to the normal devtools workflow, you are able to:
-
-* Quickly view API Request/Response: if you're using the fetch API for requests, this event is displayed for any request sent. The expanded card displays the request data as well as the response data.
-* Subscribe to specific parts of your application’s state for faster debugging
-* Visualize component hierarchy, and an animation allows you to collapse or expand the tree for specific hierarchy views.
-
-
-
### Simple Debugger Statement
The example above has a great workflow. However, there is an alternative option where you can use the [native debugger statement](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/debugger) directly in your code. If you choose to work this way, it's important that you remember to remove the statements when you're done.
diff --git a/src/v2/cookbook/dockerize-vuejs-app.md b/src/v2/cookbook/dockerize-vuejs-app.md
new file mode 100644
index 0000000000..1fc4ed6299
--- /dev/null
+++ b/src/v2/cookbook/dockerize-vuejs-app.md
@@ -0,0 +1,134 @@
+---
+title: Dockerize Vue.js App
+type: cookbook
+order: 13
+---
+
+## Simple Example
+
+So you built your first Vue.js app using the amazing [Vue.js webpack template](https://github.com/vuejs-templates/webpack) and now you really want to show off with your colleagues by demonstrating that you can also run it in a Docker container.
+
+Let's start by creating a `Dockerfile` in the root folder of our project:
+
+```docker
+FROM node:lts-alpine
+
+# install simple http server for serving static content
+RUN npm install -g http-server
+
+# make the 'app' folder the current working directory
+WORKDIR /app
+
+# copy both 'package.json' and 'package-lock.json' (if available)
+COPY package*.json ./
+
+# install project dependencies
+RUN npm install
+
+# copy project files and folders to the current working directory (i.e. 'app' folder)
+COPY . .
+
+# build app for production with minification
+RUN npm run build
+
+EXPOSE 8080
+CMD [ "http-server", "dist" ]
+```
+
+It may seem redundant to first copy `package.json` and `package-lock.json` and then all project files and folders in two separate steps but there is actually [a very good reason for that](http://bitjudo.com/blog/2014/03/13/building-efficient-dockerfiles-node-dot-js/) (spoiler: it allows us to take advantage of cached Docker layers).
+
+Now let's build the Docker image of our Vue.js app:
+
+```bash
+docker build -t vuejs-cookbook/dockerize-vuejs-app .
+```
+
+Finally, let's run our Vue.js app in a Docker container:
+
+```bash
+docker run -it -p 8080:8080 --rm --name dockerize-vuejs-app-1 vuejs-cookbook/dockerize-vuejs-app
+```
+
+We should be able to access our Vue.js app on `localhost:8080`.
+
+## Real-World Example
+
+In the previous example, we used a simple, zero-configuration command-line [http server](https://github.com/indexzero/http-server) to serve our Vue.js app which is perfectly ok for quick prototyping and _may_ even be ok for simple production scenarios. After all, the documentation says:
+
+> It is powerful enough for production usage, but it's simple and hackable enough to be used for testing, local development, and learning.
+
+Nevertheless, for realistically complex production use cases, it may be wiser to stand on the shoulders of some giant like [NGINX](https://www.nginx.com/) or [Apache](https://httpd.apache.org/) and that is exactly what we are going to do next: we are about to leverage NGINX to serve our Vue.js app because it is considered to be one of the most performant and battle-tested solutions out there.
+
+Let's refactor our `Dockerfile` to use NGINX:
+
+ ```docker
+# build stage
+FROM node:lts-alpine as build-stage
+WORKDIR /app
+COPY package*.json ./
+RUN npm install
+COPY . .
+RUN npm run build
+
+# production stage
+FROM nginx:stable-alpine as production-stage
+COPY --from=build-stage /app/dist /usr/share/nginx/html
+EXPOSE 80
+CMD ["nginx", "-g", "daemon off;"]
+```
+
+Ok, let's see what's going on here:
+* we have split our original `Dockerfile` in multiple stages by leveraging the Docker [multi-stage builds](https://docs.docker.com/develop/develop-images/multistage-build/) feature;
+* the first stage is responsible for building a production-ready artifact of our Vue.js app;
+* the second stage is responsible for serving such artifact using NGINX.
+
+Now let's build the Docker image of our Vue.js app:
+
+```bash
+docker build -t vuejs-cookbook/dockerize-vuejs-app .
+```
+
+Finally, let's run our Vue.js app in a Docker container:
+
+```bash
+docker run -it -p 8080:80 --rm --name dockerize-vuejs-app-1 vuejs-cookbook/dockerize-vuejs-app
+```
+
+We should be able to access our Vue.js app on `localhost:8080`.
+
+## Additional Context
+
+If you are reading this cookbook, chances are you already know why you decided to dockerize your Vue.js app. But if you simply landed on this page after hitting the Google's `I'm feeling lucky` button, let me share with you a couple of good reasons for doing that.
+
+Today's modern trend is to build applications using the [Cloud-Native](https://pivotal.io/cloud-native) approach which revolves mainly around the following buzzwords:
+* Microservices
+* DevOps
+* Continuous Delivery
+
+Let's see how these concepts actually affect our decision of dockerizing our Vue.js app.
+
+### Effects of Microservices
+
+By adopting the [microservices architectural style](https://martinfowler.com/microservices/), we end up building a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms. These services are built around business capabilities and independently deployable by fully automated deployment machinery.
+
+So, committing to this architectural approach most of the time implies developing and delivering our front-end as an independent service.
+
+### Effects of DevOps
+
+The adoption of [DevOps](https://martinfowler.com/bliki/DevOpsCulture.html) culture, tools and agile engineering practices has, among other things, the nice effect of increasing the collaboration between the roles of development and operations. One of the main problem of the past (but also today in some realities) is that the dev team tended to be uninterested in the operation and maintenance of a system once it was handed over to the ops team, while the latter tended to be not really aware of the system's business goals and, therefore, reluctant in satisfying the operational needs of the system (also referred to as "whims of developers").
+
+So, delivering our Vue.js app as a Docker image helps reducing, if not removing entirely, the difference between running the service on a developer's laptop, the production environment or any environment we may think of.
+
+### Effects of Continuous Delivery
+
+By leveraging the [Continuous Delivery](https://martinfowler.com/bliki/ContinuousDelivery.html) discipline we build our software in a way that it can potentially be released to production at any time. Such engineering practice is enabled by means of what is normally called [continuous delivery pipeline](https://martinfowler.com/bliki/DeploymentPipeline.html). The purpose of a continuous delivery pipeline is to split our build into stages (e.g. compilation, unit tests, integration tests, performance tests, etc.) and let each stage verify our build artifact whenever our software changes. Ultimately, each stage increases our confidence in the production readiness of our build artifact and, therefore, reduces the risk of breaking things in production (or any other environment for that matter).
+
+So, creating a Docker image for our Vue.js app is a good choice here because that would represent our final build artifact, the same artifact that would be verified against our continuous delivery pipeline and that could potentially be released to production with confidence.
+
+## Alternative Patterns
+
+If your company is not into Docker and Kubernetes just yet or you simply want to get your MVP out the door, maybe dockerizing your Vue.js app is not what you need.
+
+Common alternatives are:
+* leveraging an all-in-one platform like [Netlify](https://www.netlify.com/);
+* hosting your SPA on [Amazon S3](https://aws.amazon.com/s3/) and serving it with [Amazon CloudFront](https://aws.amazon.com/cloudfront/) (see [this](https://serverless-stack.com/chapters/deploy-the-frontend.html) link for a detailed guide).
diff --git a/src/v2/cookbook/editable-svg-icons.md b/src/v2/cookbook/editable-svg-icons.md
index 033a7230ce..a1903f5533 100644
--- a/src/v2/cookbook/editable-svg-icons.md
+++ b/src/v2/cookbook/editable-svg-icons.md
@@ -35,7 +35,10 @@ We'll create a base icon (`IconBase.vue`) component that uses a slot.
:aria-labelledby="iconName"
role="presentation"
>
-
{{iconName}} icon
+
{{ iconName }} icon
@@ -83,11 +86,19 @@ Now, if we'd like to make many sizes for the icon, we can do so very easily:
```html
-
+
-
+
```
@@ -99,16 +110,23 @@ Keeping icons in components comes in very handy when you'd like to animate them,
```html
-
- Scissors Animated Icon
-
+ >
+ Scissors Animated Icon
+
...
@@ -157,7 +175,7 @@ Designers may change their minds. Product requirements change. Keeping the logic
## When To Avoid This Pattern
-This type of SVG icon system is really useful when you have a number of icons that are used in different ways throughout your site. If you're repeating the same icon many times on one page (e.g. a giant table a delete icon in each row), it might make more sense to have all of the sprites compiled into a sprite sheet and use `` tags to load them.
+This type of SVG icon system is really useful when you have a number of icons that are used in different ways throughout your site. If you're repeating the same icon many times on one page (e.g. a giant table with a delete icon in each row), it might make more sense to have all of the sprites compiled into a sprite sheet and use `` tags to load them.
## Alternative Patterns
diff --git a/src/v2/cookbook/form-validation.md b/src/v2/cookbook/form-validation.md
index 87caae8c8b..0325ce601d 100644
--- a/src/v2/cookbook/form-validation.md
+++ b/src/v2/cookbook/form-validation.md
@@ -1,322 +1,440 @@
----
-title: Form Validation
-type: cookbook
-order: 3
----
-
-## Base Example
-
-Form validation is natively supported by the browser, but sometimes different browsers will handle things in a manner which makes relying on it a bit tricky. Even when validation is supported perfectly, there may be times when custom validations are needed and a more manual, Vue-based solution may be more appropriate. Let's begin with a simple example.
-
-Given a form of three fields, make two required. Let's look at the HTML first:
-
-``` html
-
-```
-
-Let's cover it from the top. The `
-```
-
-While the change here is small, note the `novalidate="true"` on top. This is important because the browser will attempt to validate the email address in the field when `type="email"`. Frankly it may make more sense to trust the browser in this case, but as we wanted an example with custom validation, we're disabling it. Here's the updated JavaScript.
-
-``` js
-const app = new Vue({
- el:'#app',
- data:{
- errors:[],
- name:null,
- email:null,
- movie:null
- },
- methods:{
- checkForm:function(e) {
- this.errors = [];
- if(!this.name) this.errors.push("Name required.");
- if(!this.email) {
- this.errors.push("Email required.");
- } else if(!this.validEmail(this.email)) {
- this.errors.push("Valid email required.");
- }
- if(!this.errors.length) return true;
- e.preventDefault();
- },
- validEmail:function(email) {
- var re = /^(([^<>()\[\]\\.,;:\s@"]+(\.[^<>()\[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
- return re.test(email);
- }
- }
-})
-```
-
-As you can see, we've added `validEmail` as a new method and it is simply called from `checkForm`. You can play with this example here:
-
-See the Pen form validation 2 by Raymond Camden (@cfjedimaster ) on CodePen .
-
-
-## Another Example of Custom Validation
-
-For the third example, we've built something you've probably seen in survey apps. The user is asked to spend a "budget" for a set of features for a new Star Destroyer model. The total must equal 100. First, the HTML.
-
-``` html
-
-```
-
-Note the set of inputs covering the five different features. Note the addition of `.number` to the `v-model` attribute. This tells Vue to cast the value to a number when you use it. However, there is a bug with this feature such that when the value is blank, it turns back into a string. You'll see the workaround below. To make it a bit easier for the user, we also added a current total right below so they can see, in real time, what their total is. Now let's look at the JavaScript.
-
-``` js
-const app = new Vue({
- el:'#app',
- data:{
- errors:[],
- weapons:0,
- shields:0,
- coffee:0,
- ac:0,
- mousedroids:0
- },
- computed:{
- total:function() {
- // must parse cuz Vue turns empty value to string
- return Number(this.weapons)+
- Number(this.shields)+
- Number(this.coffee)+
- Number(this.ac+this.mousedroids);
- }
- },
- methods:{
- checkForm:function(e) {
- this.errors = [];
- if(this.total != 100) this.errors.push("Total must be 100!");
- if(!this.errors.length) return true;
- e.preventDefault();
- }
- }
-})
-```
-
-We set up the total value as a computed value, and outside of that bug I ran into, it was simple enough to setup. My checkForm method now just needs to see if the total is 100 and that's it. You can play with this here:
-
-See the Pen form validation 3 by Raymond Camden (@cfjedimaster ) on CodePen .
-
-
-## Server-side Validation
-
-In my final example, we built something that makes use of Ajax to validate at the server. The form will ask you to name a new product and will then check to ensure that the name is unique. We wrote a quick [OpenWhisk](http://openwhisk.apache.org/) serverless action to do the validation. While it isn't terribly important, here is the logic:
-
-``` js
-function main(args) {
-
- return new Promise((resolve, reject) => {
-
- // bad product names: vista, empire, mbp
- let badNames = ['vista','empire','mbp'];
- if(badNames.includes(args.name)) reject({error:'Existing product'});
- resolve({status:'ok'});
-
- });
-
-}
-```
-
-Basically any name but "vista", "empire", and "mbp" are acceptable. Ok, so let's look at the form.
-
-``` html
-
-```
-
-There isn't anything special here. So let's go on to the JavaScript.
-
-``` js
-const apiUrl = 'https://openwhisk.ng.bluemix.net/api/v1/web/rcamden%40us.ibm.com_My%20Space/safeToDelete/productName.json?name=';
-
-const app = new Vue({
- el:'#app',
- data:{
- errors:[],
- name:''
- },
- methods:{
- checkForm:function(e) {
- e.preventDefault();
- this.errors = [];
- if(this.name === '') {
- this.errors.push("Product name is required.");
- } else {
- fetch(apiUrl+encodeURIComponent(this.name))
- .then(res => res.json())
- .then(res => {
- if(res.error) {
- this.errors.push(res.error);
- } else {
- // redirect to a new URL, or do something on success
- alert('ok!');
- }
- });
- }
- }
- }
-})
-```
-
-We start off with a variable representing the URL of the API that is running on OpenWhisk. Now look at `checkForm`. In this version, we always prevent the form from submitting (which, by the way, could be done in the HTML with Vue as well). You can see a basic check on `this.name` being empty, and then we hit the API. If it's bad, we add an error as before. If it's good, right now we do nothing (just an alert), but you could navigate the user to a new page with the product name in the URL, or do other actions as well. You can run this demo below:
-
-See the Pen form validation 4 by Raymond Camden (@cfjedimaster ) on CodePen .
-
-
-## Alternative Patterns
-
-While this cookbook entry focused on doing form validation "by hand", there are, of course, some great Vue libraries that will handle a lot of this for you. Switching to a prepackage library may impact the final size of your application, but the benefits could be tremendous. You have code that is (most likely) heavily tested and also updated on a regular basis. Some examples of form validation libraries for Vue include:
-
-* [vuelidate](https://github.com/monterail/vuelidate)
-* [VeeValidate](http://vee-validate.logaretm.com/)
-
+---
+title: Form Validation
+type: cookbook
+order: 3
+---
+
+## Base Example
+
+
+
+Form validation is natively supported by the browser, but sometimes different browsers will handle things in a manner which makes relying on it a bit tricky. Even when validation is supported perfectly, there may be times when custom validations are needed and a more manual, Vue-based solution may be more appropriate. Let's begin with a simple example.
+
+Given a form of three fields, make two required. Let's look at the HTML first:
+
+``` html
+
+```
+
+Let's cover it from the top. The `
+```
+
+While the change here is small, note the `novalidate="true"` on top. This is important because the browser will attempt to validate the email address in the field when `type="email"`. Frankly it may make more sense to trust the browser in this case, but as we wanted an example with custom validation, we're disabling it. Here's the updated JavaScript.
+
+``` js
+const app = new Vue({
+ el: '#app',
+ data: {
+ errors: [],
+ name: null,
+ email: null,
+ movie: null
+ },
+ methods: {
+ checkForm: function (e) {
+ this.errors = [];
+
+ if (!this.name) {
+ this.errors.push("Name required.");
+ }
+ if (!this.email) {
+ this.errors.push('Email required.');
+ } else if (!this.validEmail(this.email)) {
+ this.errors.push('Valid email required.');
+ }
+
+ if (!this.errors.length) {
+ return true;
+ }
+
+ e.preventDefault();
+ },
+ validEmail: function (email) {
+ var re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
+ return re.test(email);
+ }
+ }
+})
+```
+
+As you can see, we've added `validEmail` as a new method and it is simply called from `checkForm`. You can play with this example here:
+
+See the Pen form validation 2 by Raymond Camden (@cfjedimaster ) on CodePen .
+
+
+## Another Example of Custom Validation
+
+For the third example, we've built something you've probably seen in survey apps. The user is asked to spend a "budget" for a set of features for a new Star Destroyer model. The total must equal 100. First, the HTML.
+
+``` html
+
+```
+
+Note the set of inputs covering the five different features. Note the addition of `.number` to the `v-model` attribute. This tells Vue to cast the value to a number when you use it. However, there is a bug with this feature such that when the value is blank, it turns back into a string. You'll see the workaround below. To make it a bit easier for the user, we also added a current total right below so they can see, in real time, what their total is. Now let's look at the JavaScript.
+
+``` js
+const app = new Vue({
+ el: '#app',
+ data:{
+ errors: [],
+ weapons: 0,
+ shields: 0,
+ coffee: 0,
+ ac: 0,
+ mousedroids: 0
+ },
+ computed: {
+ total: function () {
+ // must parse because Vue turns empty value to string
+ return Number(this.weapons) +
+ Number(this.shields) +
+ Number(this.coffee) +
+ Number(this.ac+this.mousedroids);
+ }
+ },
+ methods:{
+ checkForm: function (e) {
+ this.errors = [];
+
+ if (this.total != 100) {
+ this.errors.push('Total must be 100!');
+ }
+
+ if (!this.errors.length) {
+ return true;
+ }
+
+ e.preventDefault();
+ }
+ }
+})
+```
+
+We set up the total value as a computed value, and outside of that bug I ran into, it was simple enough to setup. My checkForm method now just needs to see if the total is 100 and that's it. You can play with this here:
+
+See the Pen form validation 3 by Raymond Camden (@cfjedimaster ) on CodePen .
+
+
+## Server-side Validation
+
+In my final example, we built something that makes use of Ajax to validate at the server. The form will ask you to name a new product and will then check to ensure that the name is unique. We wrote a quick [Netlify](https://netlify.com/) serverless action to do the validation. While it isn't terribly important, here is the logic:
+
+``` js
+exports.handler = async (event, context) => {
+
+ const badNames = ['vista', 'empire', 'mbp'];
+ const name = event.queryStringParameters.name;
+
+ if (badNames.includes(name)) {
+ return {
+ statusCode: 400,
+ body: JSON.stringify({error: 'Invalid name passed.'})
+ }
+ }
+
+ return {
+ statusCode: 204
+ }
+
+}
+
+```
+
+Basically any name but "vista", "empire", and "mbp" are acceptable. Ok, so let's look at the form.
+
+``` html
+
+```
+
+There isn't anything special here. So let's go on to the JavaScript.
+
+``` js
+const apiUrl = 'https://vuecookbook.netlify.app/.netlify/functions/product-name?name=';
+
+const app = new Vue({
+ el: '#app',
+ data: {
+ errors: [],
+ name: ''
+ },
+ methods:{
+ checkForm: function (e) {
+ e.preventDefault();
+
+ this.errors = [];
+
+ if (this.name === '') {
+ this.errors.push('Product name is required.');
+ } else {
+ fetch(apiUrl + encodeURIComponent(this.name))
+ .then(async res => {
+ if (res.status === 204) {
+ alert('OK');
+ } else if (res.status === 400) {
+ let errorResponse = await res.json();
+ this.errors.push(errorResponse.error);
+ }
+ });
+ }
+ }
+ }
+})
+```
+
+We start off with a variable representing the URL of the API that is running on OpenWhisk. Now look at `checkForm`. In this version, we always prevent the form from submitting (which, by the way, could be done in the HTML with Vue as well). You can see a basic check on `this.name` being empty, and then we hit the API. If it's bad, we add an error as before. If it's good, right now we do nothing (just an alert), but you could navigate the user to a new page with the product name in the URL, or do other actions as well. You can run this demo below:
+
+See the Pen form validation 4 by Raymond Camden (@cfjedimaster ) on CodePen .
+
+
+## Alternative Patterns
+
+While this cookbook entry focused on doing form validation "by hand", there are, of course, some great Vue libraries that will handle a lot of this for you. Switching to a prepackage library may impact the final size of your application, but the benefits could be tremendous. You have code that is (most likely) heavily tested and also updated on a regular basis. Some examples of form validation libraries for Vue include:
+
+* [vuelidate](https://github.com/monterail/vuelidate)
+* [VeeValidate](https://vee-validate.logaretm.com/v3/)
diff --git a/src/v2/cookbook/index.md b/src/v2/cookbook/index.md
index 1a0f0c24a9..54b401ed02 100644
--- a/src/v2/cookbook/index.md
+++ b/src/v2/cookbook/index.md
@@ -16,6 +16,8 @@ How is the cookbook different from the guide? Why is this necessary?
* **Exploring the Ecosystem**: For advanced features, we assume some ecosystem knowledge. For example, if you want to use single-file components in Webpack, we don't explain how to configure the non-Vue parts of the Webpack config. In the cookbook, we have the space to explore these ecosystem libraries in more depth - at least to the extent that is universally useful for Vue developers.
+With all these differences, please note that the cookbook is still _not_ a step-by-step manual. For most of its content, you are expected to have a basic understanding of concepts like HTML, CSS, JavaScript, npm/yarn, etc.
+
## Cookbook Contributions
### What we're looking for
diff --git a/src/v2/cookbook/packaging-sfc-for-npm.md b/src/v2/cookbook/packaging-sfc-for-npm.md
new file mode 100644
index 0000000000..fd7c9ce485
--- /dev/null
+++ b/src/v2/cookbook/packaging-sfc-for-npm.md
@@ -0,0 +1,219 @@
+---
+title: Packaging Vue Components for npm
+type: cookbook
+order: 12
+---
+
+## Base Example
+
+Vue components by nature are meant to be re-used. This is easy when the component is only used within a single application. But how can you write a component once and use it in multiple sites/applications? Perhaps the easiest solution is via npm.
+
+By packaging your component to be shared via npm, it can be imported/required into a build process for use in full-fledged web applications:
+
+```js
+import MyComponent from 'my-component';
+
+export default {
+ components: {
+ MyComponent,
+ },
+ // rest of the component
+}
+```
+
+Or even used via `
+
+ ...
+
+ ...
+```
+
+Not only does this help you avoid copy/pasting components around, but it also allows you to give back to the Vue community!
+
+## Can't I Just Share `.vue` Files Directly?
+
+Vue already allows components to be written as a single file. Because a Single File Component (SFC) is already just one file, you might ask:
+
+> "Why can't people use my `.vue` file directly? Isn't that the simplest way to share components?"
+
+It's true, you can share `.vue` files directly, and anyone using a [Vue build](/v2/guide/installation.html#Explanation-of-Different-Builds) containing the Vue compiler can consume it immediately. Also, the SSR build uses string concatenation as an optimization, so the `.vue` file might be preferred in this scenario (see [Packaging Components for npm > SSR Usage](#SSR-Usage) for details). However, this excludes anyone who wishes to use the component directly in a browser via `
+```
+
+Still no scoped slots, so let's add one.
+
+### 3. Expose `google` and `map` properties to the parent component by adding a scoped slot.
+
+Finally, we can add a scoped slot that will do the job and allow us to access the child component props in the parent component. We do that by adding the `` tag in the child component and passing the props that we want to expose (using `v-bind` directive or `:propName` shorthand). It does not differ from passing the props down to the child component, but doing it in the `` tag will reverse the direction of data flow.
+
+`GoogleMapLoader.vue`
+
+```html
+
+
+
+```
+
+Now, when we have the slot in the child component, we need to receive and consume the exposed props in the parent component.
+
+### 4. Receive exposed props in the parent component using `slot-scope` attribute.
+
+To receive the props in the parent component, we declare a template element and use the `slot-scope` attribute. This attribute has access to the object carrying all the props exposed from the child component. We can grab the whole object or we can [de-structure that object](/v2/guide/components-slots.html#Destructuring-slot-scope) and only what we need.
+
+Let’s de-structure this thing to get what we need.
+
+`TravelMap.vue`
+
+```html
+
+
+ {{ map }}
+ {{ google }}
+
+
+```
+
+Even though the `google` and `map` props do not exist in the `TravelMap` scope, the component has access to them and we can use them in the template.
+
+You might wonder why would we do things like that and what is the use of all that?
+
+Scoped slots allow us to pass a template to the slot instead of a rendered element. It’s called a `scoped` slot because it will have access to certain child component data even though the template is rendered in the parent component scope. This gives us the freedom to fill the template with custom content from the parent component.
+
+### 5. Create factory components for Markers and Polylines
+
+Now when we have our map ready we will create two factory components that will be used to add elements to the `TravelMap`.
+
+`GoogleMapMarker.vue`
+
+```js
+import { POINT_MARKER_ICON_CONFIG } from '@/constants/mapSettings'
+
+export default {
+ props: {
+ google: {
+ type: Object,
+ required: true
+ },
+ map: {
+ type: Object,
+ required: true
+ },
+ marker: {
+ type: Object,
+ required: true
+ }
+ },
+
+ mounted() {
+ new this.google.maps.Marker({
+ position: this.marker.position,
+ marker: this.marker,
+ map: this.map,
+ icon: POINT_MARKER_ICON_CONFIG
+ })
+ }
+}
+```
+
+`GoogleMapLine.vue`
+
+```js
+import { LINE_PATH_CONFIG } from '@/constants/mapSettings'
+
+export default {
+ props: {
+ google: {
+ type: Object,
+ required: true
+ },
+ map: {
+ type: Object,
+ required: true
+ },
+ path: {
+ type: Array,
+ required: true
+ }
+ },
+
+ mounted() {
+ new this.google.maps.Polyline({
+ path: this.path,
+ map: this.map,
+ ...LINE_PATH_CONFIG
+ })
+ }
+}
+```
+
+Both of these receive `google` that we use to extract the required object (Marker or Polyline) as well as `map` which gives as a reference to the map on which we want to place our element.
+
+Each component also expects an extra prop to create a corresponding element. In this case, we have `marker` and `path`, respectively.
+
+On the mounted hook, we create an element (Marker/Polyline) and attach it to our map by passing the `map` property to the object constructor.
+
+There’s still one more step to go...
+
+### 6. Add elements to map
+
+Let’s use our factory components to add elements to our map. We must render the factory component and pass the `google` and `map` objects so data flows to the right places.
+
+We also need to provide the data that’s required by the element itself. In our case, that’s the `marker` object with the position of the marker and the `path` object with Polyline coordinates.
+
+Here we go, integrating the data points directly into the template:
+
+```html
+
+
+
+
+
+
+```
+
+We need to import the required factory components in our script and set the data that will be passed to the markers and lines:
+
+```js
+import { mapSettings } from '@/constants/mapSettings'
+
+export default {
+ components: {
+ GoogleMapLoader,
+ GoogleMapMarker,
+ GoogleMapLine
+ },
+
+ data () {
+ return {
+ markers: [
+ { id: 'a', position: { lat: 3, lng: 101 } },
+ { id: 'b', position: { lat: 5, lng: 99 } },
+ { id: 'c', position: { lat: 6, lng: 97 } },
+ ],
+ lines: [
+ { id: '1', path: [{ lat: 3, lng: 101 }, { lat: 5, lng: 99 }] },
+ { id: '2', path: [{ lat: 5, lng: 99 }, { lat: 6, lng: 97 }] }
+ ],
+ }
+ },
+
+ computed: {
+ mapConfig () {
+ return {
+ ...mapSettings,
+ center: this.mapCenter
+ }
+ },
+
+ mapCenter () {
+ return this.markers[1].position
+ }
+ },
+}
+```
+
+## When To Avoid This Pattern
+It might be tempting to create a very complex solution based on the example, but at some point we can get to the situation where this abstraction becomes an independent part of the code living in our codebase. If we get to that point it might be worth considering extraction to an add-on.
+
+## Wrapping Up
+That's it. With all those bits and pieces created we can now re-use the `GoogleMapLoader` component as a base for all our maps by passing different templates to each one of them. Imagine that you need to create another map with different Markers or just Markers without Polylines. By using the above pattern it becomes very easy as we just need to pass different content to the `GoogleMapLoader` component.
+
+This pattern is not strictly connected to Google Maps; it can be used with any library to set the base component and expose the library's API that might be then used in the component that summoned the base component.
diff --git a/src/v2/cookbook/serverless-blog.md b/src/v2/cookbook/serverless-blog.md
index 9b99d496d5..45dd6e3987 100644
--- a/src/v2/cookbook/serverless-blog.md
+++ b/src/v2/cookbook/serverless-blog.md
@@ -4,27 +4,33 @@ type: cookbook
order: 5
---
-So you've just launched your Vue.js website, congrats! Now you want to add a blog that quickly plugs into your website and you don't want to have to spin up a whole server just to host a Wordpress instance (or any DB-powered CMS for that matter). You want to just be able to add a few Vue.js blog components and some routes and have it all just work, right? What you're looking for a blog that's powered entirely by API's you can consume directly from your Vue.js application. This tutorial will teach you how to do just that, let's dive in!
+So you've just launched your Vue.js website, congrats! Now you want to add a blog that quickly plugs into your website and you don't want to have to spin up a whole server just to host a Wordpress instance (or any DB-powered CMS for that matter). You want to just be able to add a few Vue.js blog components and some routes and have it all just work, right? What you're looking for is a blog that's powered entirely by API's you can consume directly from your Vue.js application. This tutorial will teach you how to do just that, let's dive in!
We're going to quickly build a CMS-powered blog with Vue.js. It uses [ButterCMS](https://buttercms.com/), an API-first CMS that lets you manage content using the ButterCMS dashboard and integrate our content API into your Vue.js app. You can use ButterCMS for new or existing Vue.js projects.
-
+

## Install
Run this in your commandline:
-`npm install buttercms --save`
+```bash
+npm install buttercms --save
+```
-Butter can also be loaded using a CDN:
+Butter can also be loaded using a CDN:
-``
+```html
+
+```
## Quickstart
Set your API token:
-`var butter = require('buttercms')('your_api_token');`
+```javascript
+var butter = require('buttercms')('your_api_token');
+```
Using ES6:
@@ -33,7 +39,7 @@ import Butter from 'buttercms';
const butter = Butter('your_api_token');
```
-Using CDN:
+Using CDN:
```html
@@ -41,9 +47,9 @@ Using CDN:
var butter = Butter('your_api_token');
```
-
+
Import this file into any component you want to use ButterCMS. Then from the console run:
-
+
```javascript
butter.post.list({page: 1, page_size: 10}).then(function(response) {
console.log(response)
@@ -54,7 +60,7 @@ This API request fetches your blog posts. Your account comes with one example po
## Display posts
-To display posts we create a `/blog` route (using Vue Router) in our app and fetch blog posts from the Butter API, as well as a `/blog/:slug` route to handle individual posts.
+To display posts we create a `/blog` route (using Vue Router) in our app and fetch blog posts from the Butter API, as well as a `/blog/:slug` route to handle individual posts.
See the ButterCMS [API reference](https://buttercms.com/docs/api/?javascript#blog-posts) for additional options such as filtering by category or author. The response also includes some metadata we'll use for pagination.
@@ -103,7 +109,7 @@ Then create `components/BlogHome.vue` which will be your blog homepage that list
butter.post.list({
page: 1,
page_size: 10
- }).then((res) => {
+ }).then(res => {
this.posts = res.data.data
})
}
@@ -118,14 +124,25 @@ Then create `components/BlogHome.vue` which will be your blog homepage that list
{{ page_title }}
-
+
@@ -190,7 +215,7 @@ Here's a preview:
Now our app is pulling all blog posts and we can navigate to individual posts. However, our next/previous post buttons are not working.
-One thing to note when using routes with params is that when the user navigates from `/blog/foo` to `/blog/bar`, the same component instance will be reused. Since both routes render the same component, this is more efficient than destroying the old instance and then creating a new one.
+One thing to note when using routes with params is that when the user navigates from `/blog/foo` to `/blog/bar`, the same component instance will be reused. Since both routes render the same component, this is more efficient than destroying the old instance and then creating a new one.
Be aware, that using the component this way will mean that the lifecycle hooks of the component will not be called. Visit the Vue Router's docs to learn more about [Dynamic Route Matching](https://router.vuejs.org/en/essentials/dynamic-matching.html)
@@ -205,27 +230,26 @@ Updated `
@@ -247,10 +271,10 @@ Here's an example of listing all categories and getting posts by category. Call
```javascript
methods: {
- ...
+ // ...
getCategories() {
butter.category.list()
- .then((res) => {
+ .then(res => {
console.log('List of Categories:')
console.log(res.data.data)
})
@@ -259,14 +283,14 @@ methods: {
butter.category.retrieve('example-category', {
include: 'recent_posts'
})
- .then((res) => {
+ .then(res => {
console.log('Posts with specific category:')
console.log(res)
})
}
},
created() {
- ...
+ // ...
this.getCategories()
this.getPostsByCategory()
}
@@ -274,7 +298,7 @@ created() {
## Alternative Patterns
-An alternative pattern to consider, especially if you prefer writing only in Markdown, is using something like [Nuxtent](https://nuxtent.now.sh/guide/writing#async-components). Nuxtent allows you to use `Vue Component` inside of Markdown files. This approach would be akin to a static site approach (i.e. Jekyll) where you compose your blog posts in Markdown files. Nuxtent adds a nice integration between Vue.js and Markdown allowing you to live in a 100% Vue.js world.
+An alternative pattern to consider, especially if you prefer writing only in Markdown, is using something like [Nuxtent](https://nuxtent-module.netlify.com/guide/writing/#async-components). Nuxtent allows you to use `Vue Component` inside of Markdown files. This approach would be akin to a static site approach (i.e. Jekyll) where you compose your blog posts in Markdown files. Nuxtent adds a nice integration between Vue.js and Markdown allowing you to live in a 100% Vue.js world.
## Wrap up
diff --git a/src/v2/cookbook/unit-testing-vue-components.md b/src/v2/cookbook/unit-testing-vue-components.md
index 88aed1e9a6..e22e584bd7 100644
--- a/src/v2/cookbook/unit-testing-vue-components.md
+++ b/src/v2/cookbook/unit-testing-vue-components.md
@@ -14,7 +14,7 @@ This simple example tests whether some text is rendered:
-
@@ -44,11 +44,12 @@ export default {
```
```js
-import { shallow } from '@vue/test-utils'
+import { shallowMount } from '@vue/test-utils'
+import Hello from './Hello.vue'
-test('Foo', () => {
+test('Hello', () => {
// render the component
- const wrapper = shallow(Hello)
+ const wrapper = shallowMount(Hello)
// should not allow for `username` less than 7 characters, excludes whitespace
wrapper.setData({ username: ' '.repeat(7) })
@@ -57,9 +58,7 @@ test('Foo', () => {
expect(wrapper.find('.error').exists()).toBe(true)
// update the name to be long enough
- wrapper.setData({
- username: 'Lachlan'
- })
+ wrapper.setData({ username: 'Lachlan' })
// assert the error has gone away
expect(wrapper.find('.error').exists()).toBe(false)
@@ -82,7 +81,7 @@ Automated testing allows large teams of developers to maintain complex codebases
#### Getting started
-[Vue Test Utils](https://github.com/vuejs/vue-test-utils) is the official library for unit testing Vue components. The [vue-cli](https://github.com/vuejs/vue-cli) `webpack` template comes with either Karma or Jest, both well supported test runners, and there are some [guides](https://vue-test-utils.vuejs.org/en/guides/) in the Vue Test Utils documentation.
+[Vue Test Utils](https://github.com/vuejs/vue-test-utils) is the official library for unit testing Vue components. The [vue-cli](https://github.com/vuejs/vue-cli) `webpack` template comes with either Karma or Jest, both well supported test runners, and there are some [guides](https://vue-test-utils.vuejs.org/guides/) in the Vue Test Utils documentation.
## Real-World Example
@@ -107,7 +106,7 @@ Let's take a look at the component code first:
{{ message }}
Enter your username:
-
@@ -145,26 +144,29 @@ The things that we should test are:
And our first attempt at test:
```js
-import { shallow } from '@vue/test-utils'
+import { shallowMount } from '@vue/test-utils'
+import Foo from './Foo.vue'
describe('Foo', () => {
it('renders a message and responds correctly to user input', () => {
- const wrapper = shallow(Foo, {
- data: {
- message: 'Hello World',
- username: ''
- }
- })
-
- // see if the message renders
- expect(wrapper.find('.message').text()).toEqual('Hello World')
-
- // assert the error is rendered
- expect(wrapper.find('.error').exists()).toBeTruthy()
+ const wrapper = shallowMount(Foo, {
+ data() {
+ return {
+ message: 'Hello World',
+ username: ''
+ }
+ }
+ })
+
+ // see if the message renders
+ expect(wrapper.find('.message').text()).toEqual('Hello World')
+
+ // assert the error is rendered
+ expect(wrapper.find('.error').exists()).toBeTruthy()
- // update the `username` and assert error is longer rendered
- wrapper.setData({ username: 'Lachlan' })
- expect(wrapper.find('.error').exists()).toBeFalsy()
+ // update the `username` and assert error is no longer rendered
+ wrapper.setData({ username: 'Lachlan' })
+ expect(wrapper.find('.error').exists()).toBeFalsy()
})
})
```
@@ -178,17 +180,21 @@ The below example improves the test by:
- only making one assertion per `it` block
- having short, clear test descriptions
-- providing only the minimum data requires for the test
+- providing only the minimum data required for the test
- refactoring duplicated logic (creating the `wrapper` and setting the `username` variable) into a factory function
*Updated test*:
```js
-import { shallow } from '@vue/test-utils'
+import { shallowMount } from '@vue/test-utils'
import Foo from './Foo'
const factory = (values = {}) => {
- return shallow(Foo, {
- data: { ...values }
+ return shallowMount(Foo, {
+ data () {
+ return {
+ ...values
+ }
+ }
})
}
@@ -221,7 +227,7 @@ describe('Foo', () => {
Points to note:
-At the top, we declare the factory function which merges the `values` object into `data` and returns a new `wrapper` instance. This way, we don't need to duplicate `const wrapper = shallow(Foo)` in every test. Another great benefit to this is when more complex components with a method or computed property you might want to mock or stub in every test, you only need to declare it once.
+At the top, we declare the factory function which merges the `values` object into `data` and returns a new `wrapper` instance. This way, we don't need to duplicate `const wrapper = shallowMount(Foo)` in every test. Another great benefit to this is when more complex components with a method or computed property you might want to mock or stub in every test, you only need to declare it once.
## Additional Context
@@ -231,7 +237,7 @@ The above test is fairly simple, but in practice Vue components often have other
- committing or dispatching mutations or actions with a `Vuex` store
- testing interaction
-There are more complete examples showing such tests in the Vue Test Utils [guides](https://vue-test-utils.vuejs.org/en/guides/).
+There are more complete examples showing such tests in the Vue Test Utils [guides](https://vue-test-utils.vuejs.org/guides/).
Vue Test Utils and the enormous JavaScript ecosystem provides plenty of tooling to facilitate almost 100% test coverage. Unit tests are only one part of the testing pyramid, though. Some other types of tests include e2e (end to end) tests, and snapshot tests. Unit tests are the smallest and most simple of tests - they make assertions on the smallest units of work, isolating each part of a single component.
diff --git a/src/v2/cookbook/using-axios-to-consume-apis.md b/src/v2/cookbook/using-axios-to-consume-apis.md
index 4528031adc..584478e368 100644
--- a/src/v2/cookbook/using-axios-to-consume-apis.md
+++ b/src/v2/cookbook/using-axios-to-consume-apis.md
@@ -61,7 +61,10 @@ This is a lot easier for us to display, so we can now update our HTML to display
```html
Bitcoin Price Index
-
+
{{ currency.description }}:
{{ currency.rate_float | currencydecimal }}
@@ -124,7 +127,7 @@ new Vue({
.catch(error => {
console.log(error)
this.errored = true
- }).
+ })
.finally(() => this.loading = false)
}
})
@@ -141,7 +144,11 @@ new Vue({
Loading...
-
+
{{ currency.description }}:
{{ currency.rate_float | currencydecimal }}
@@ -157,7 +164,7 @@ You can hit the rerun button on this pen to see the loading status briefly while
See the Pen Fourth Step Axios and Vue by Vue (@Vue ) on CodePen .
-This can be even futher improved with the use of components for different sections and more distinct error reporting, depending on the API you're using and the complexity of your application.
+This can be even further improved with the use of components for different sections and more distinct error reporting, depending on the API you're using and the complexity of your application.
## Alternative Patterns
diff --git a/src/v2/examples/commits.md b/src/v2/examples/commits.md
index 7481498d3a..7acb346822 100644
--- a/src/v2/examples/commits.md
+++ b/src/v2/examples/commits.md
@@ -6,4 +6,4 @@ order: 1
> This example fetches latest Vue.js commits data from GitHub's API and displays them as a list. You can switch between the master and dev branches.
-
+
diff --git a/src/v2/examples/deepstream.md b/src/v2/examples/deepstream.md
index 382e3bd3b8..acae9a0be8 100644
--- a/src/v2/examples/deepstream.md
+++ b/src/v2/examples/deepstream.md
@@ -6,4 +6,4 @@ order: 9
> This example uses [deepstreamHub](https://deepstreamhub.com/) to synchronize realtime data, send events and make remote procedure calls between clients (you can try opening it in multiple browser windows).
-
+
diff --git a/src/v2/examples/elastic-header.md b/src/v2/examples/elastic-header.md
index 186ba37a92..0c16def661 100644
--- a/src/v2/examples/elastic-header.md
+++ b/src/v2/examples/elastic-header.md
@@ -4,4 +4,4 @@ type: examples
order: 7
---
-
+
diff --git a/src/v2/examples/firebase.md b/src/v2/examples/firebase.md
index e67c6c0f7c..944602ac1e 100644
--- a/src/v2/examples/firebase.md
+++ b/src/v2/examples/firebase.md
@@ -6,4 +6,4 @@ order: 10
> This example uses [Firebase](https://firebase.google.com/) as the data persistence backend and syncs between clients in real time (you can try opening it in multiple browser tabs). In addition, it performs instant validation using computed properties and triggers CSS transitions when adding/removing items.
-
+
diff --git a/src/v2/examples/grid-component.md b/src/v2/examples/grid-component.md
index 19b339cb15..5d2825af8a 100644
--- a/src/v2/examples/grid-component.md
+++ b/src/v2/examples/grid-component.md
@@ -6,4 +6,4 @@ order: 3
> This is an example of creating a reusable grid component and using it with external data.
-
+
diff --git a/src/v2/examples/hackernews.md b/src/v2/examples/hackernews.md
index 9f87349a16..32e9b60f38 100644
--- a/src/v2/examples/hackernews.md
+++ b/src/v2/examples/hackernews.md
@@ -8,13 +8,13 @@ order: 12
{% raw %}
{% endraw %}
-> [Live Demo](https://vue-hn.now.sh/)
+> [Live Demo](https://vue-hn.herokuapp.com/)
> Note: the demo may need some spin up time if nobody has accessed it for a certain period.
>
> [[Source](https://github.com/vuejs/vue-hackernews-2.0)]
diff --git a/src/v2/examples/index.md b/src/v2/examples/index.md
index 5fdff15702..374ac9f384 100644
--- a/src/v2/examples/index.md
+++ b/src/v2/examples/index.md
@@ -6,4 +6,4 @@ order: 0
> Dead simple Markdown editor.
-
+
diff --git a/src/v2/examples/modal.md b/src/v2/examples/modal.md
index fc1e0a9e3f..76ab7debd4 100644
--- a/src/v2/examples/modal.md
+++ b/src/v2/examples/modal.md
@@ -6,4 +6,4 @@ order: 6
> Features used: component, prop passing, content insertion, transitions.
-
+
diff --git a/src/v2/examples/select2.md b/src/v2/examples/select2.md
index 0731a39471..ca2d885c61 100644
--- a/src/v2/examples/select2.md
+++ b/src/v2/examples/select2.md
@@ -6,4 +6,4 @@ order: 8
> In this example we are integrating a 3rd party jQuery plugin (select2) by wrapping it inside a custom component.
-
+
diff --git a/src/v2/examples/svg.md b/src/v2/examples/svg.md
index 38756f623e..f153b9db52 100644
--- a/src/v2/examples/svg.md
+++ b/src/v2/examples/svg.md
@@ -6,4 +6,4 @@ order: 5
> This example showcases a combination of custom component, computed property, two-way binding and SVG support.
-
+
diff --git a/src/v2/examples/todomvc.md b/src/v2/examples/todomvc.md
index b3eee18d9a..362cf841c1 100644
--- a/src/v2/examples/todomvc.md
+++ b/src/v2/examples/todomvc.md
@@ -6,6 +6,6 @@ order: 11
> This is a fully spec-compliant TodoMVC implementation in under 120 effective lines of JavaScript (excluding comments and blank lines).
-Note that if your web browser is configured to block 3rd-party data/cookies, the example below will not work, as the `localStorage` data will fail to be saved from JSFiddle. You'll have to click on `Edit in JSFiddle` to see the live result.
+Note that if your web browser is configured to block 3rd-party data/cookies, the example below will not work, as the `localStorage` data will fail to be saved. You'll have to click on `Open Sandbox` to see the live result.
-
+
diff --git a/src/v2/examples/tree-view.md b/src/v2/examples/tree-view.md
index f0d34bfe8d..4922224947 100644
--- a/src/v2/examples/tree-view.md
+++ b/src/v2/examples/tree-view.md
@@ -6,4 +6,4 @@ order: 4
> Example of a simple tree view implementation showcasing recursive usage of components.
-
+
diff --git a/src/v2/examples/vue-10-two-way-currency-filter-v2/index.html b/src/v2/examples/vue-10-two-way-currency-filter-v2/index.html
new file mode 100644
index 0000000000..caf5244f40
--- /dev/null
+++ b/src/v2/examples/vue-10-two-way-currency-filter-v2/index.html
@@ -0,0 +1,88 @@
+
+
+
+ Two-way Currency Filter
+
+
+
+
+
+
+
+
+
+
+
Total: ${{ total }}
+
+
+
+
+
diff --git a/src/v2/examples/vue-10-two-way-currency-filter-v2/package.json b/src/v2/examples/vue-10-two-way-currency-filter-v2/package.json
new file mode 100644
index 0000000000..3dcc5dba3f
--- /dev/null
+++ b/src/v2/examples/vue-10-two-way-currency-filter-v2/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-10-two-way-currency-filter-v2",
+ "version": "1.0.0",
+ "description": "Showing how delayed state updates can cause strange behavior.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-10-two-way-currency-filter-v2/sandbox.config.json b/src/v2/examples/vue-10-two-way-currency-filter-v2/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-10-two-way-currency-filter-v2/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-10-two-way-currency-filter-v3/currency-validator.js b/src/v2/examples/vue-10-two-way-currency-filter-v3/currency-validator.js
new file mode 100644
index 0000000000..80ab295e34
--- /dev/null
+++ b/src/v2/examples/vue-10-two-way-currency-filter-v3/currency-validator.js
@@ -0,0 +1,61 @@
+var currencyValidator = {
+ format: function(number) {
+ return (Math.trunc(number * 100) / 100).toFixed(2);
+ },
+ parse: function(newString, oldNumber) {
+ var CleanParse = function(value) {
+ return { value: value };
+ };
+ var CurrencyWarning = function(warning, value) {
+ return {
+ warning: warning,
+ value: value,
+ attempt: newString
+ };
+ };
+ var NotAValidDollarAmountWarning = function(value) {
+ return new CurrencyWarning(
+ newString + " is not a valid dollar amount",
+ value
+ );
+ };
+ var AutomaticConversionWarning = function(value) {
+ return new CurrencyWarning(
+ newString + " was automatically converted to " + value,
+ value
+ );
+ };
+
+ var newNumber = Number(newString);
+ var indexOfDot = newString.indexOf(".");
+ var indexOfE = newString.indexOf("e");
+
+ if (isNaN(newNumber)) {
+ if (
+ indexOfDot === -1 &&
+ indexOfE > 0 &&
+ indexOfE === newString.length - 1 &&
+ Number(newString.slice(0, indexOfE)) !== 0
+ ) {
+ return new CleanParse(oldNumber);
+ } else {
+ return new NotAValidDollarAmountWarning(oldNumber);
+ }
+ }
+
+ var newCurrencyString = currencyValidator.format(newNumber);
+ var newCurrencyNumber = Number(newCurrencyString);
+
+ if (newCurrencyNumber === newNumber) {
+ if (indexOfE !== -1 && indexOfE === newString.length - 2) {
+ return new AutomaticConversionWarning(newNumber);
+ } else {
+ return new CleanParse(newNumber);
+ }
+ } else {
+ return new NotAValidDollarAmountWarning(
+ newNumber > newCurrencyNumber ? newCurrencyNumber : oldNumber
+ );
+ }
+ }
+};
diff --git a/src/v2/examples/vue-10-two-way-currency-filter-v3/index.html b/src/v2/examples/vue-10-two-way-currency-filter-v3/index.html
new file mode 100644
index 0000000000..40d6041b2a
--- /dev/null
+++ b/src/v2/examples/vue-10-two-way-currency-filter-v3/index.html
@@ -0,0 +1,97 @@
+
+
+
+ Two-way Currency Filter
+
+
+
+
+
+
+
+
+
+
+
Total: ${{ total }}
+
+
+
+
+
diff --git a/src/v2/examples/vue-10-two-way-currency-filter-v3/package.json b/src/v2/examples/vue-10-two-way-currency-filter-v3/package.json
new file mode 100644
index 0000000000..082e912c93
--- /dev/null
+++ b/src/v2/examples/vue-10-two-way-currency-filter-v3/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-10-two-way-currency-filter-v3",
+ "version": "1.0.0",
+ "description": "Showing how delayed state updates can cause strange behavior.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-10-two-way-currency-filter-v3/sandbox.config.json b/src/v2/examples/vue-10-two-way-currency-filter-v3/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-10-two-way-currency-filter-v3/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-10-two-way-currency-filter/index.html b/src/v2/examples/vue-10-two-way-currency-filter/index.html
new file mode 100644
index 0000000000..e63f64f86b
--- /dev/null
+++ b/src/v2/examples/vue-10-two-way-currency-filter/index.html
@@ -0,0 +1,56 @@
+
+
+
+ Two-way Currency Filter
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-10-two-way-currency-filter/package.json b/src/v2/examples/vue-10-two-way-currency-filter/package.json
new file mode 100644
index 0000000000..ee92d5f0a8
--- /dev/null
+++ b/src/v2/examples/vue-10-two-way-currency-filter/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-10-two-way-currency-filter",
+ "version": "1.0.0",
+ "description": "Showing how delayed state updates can cause strange behavior.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-10-two-way-currency-filter/sandbox.config.json b/src/v2/examples/vue-10-two-way-currency-filter/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-10-two-way-currency-filter/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-accessing-parent-component-instance/index.html b/src/v2/examples/vue-20-accessing-parent-component-instance/index.html
new file mode 100644
index 0000000000..44606424db
--- /dev/null
+++ b/src/v2/examples/vue-20-accessing-parent-component-instance/index.html
@@ -0,0 +1,91 @@
+
+
+
+ Dependency Injection Google Maps Demo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-accessing-parent-component-instance/package.json b/src/v2/examples/vue-20-accessing-parent-component-instance/package.json
new file mode 100644
index 0000000000..f01eaa982e
--- /dev/null
+++ b/src/v2/examples/vue-20-accessing-parent-component-instance/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-accessing-parent-component-instance",
+ "version": "1.0.0",
+ "description": "Vue.js example accessing Parent Component Instance using Google Maps.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-accessing-parent-component-instance/sandbox.config.json b/src/v2/examples/vue-20-accessing-parent-component-instance/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-accessing-parent-component-instance/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-component-blog-post-example/index.html b/src/v2/examples/vue-20-component-blog-post-example/index.html
new file mode 100644
index 0000000000..5682f7ef64
--- /dev/null
+++ b/src/v2/examples/vue-20-component-blog-post-example/index.html
@@ -0,0 +1,43 @@
+
+
+
+ Component Blog Post Example
+
+
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-component-blog-post-example/package.json b/src/v2/examples/vue-20-component-blog-post-example/package.json
new file mode 100644
index 0000000000..65197ee445
--- /dev/null
+++ b/src/v2/examples/vue-20-component-blog-post-example/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-component-blog-post-example",
+ "version": "1.0.0",
+ "description": "Dynamically passing props, like when fetching posts from an API.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-component-blog-post-example/sandbox.config.json b/src/v2/examples/vue-20-component-blog-post-example/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-component-blog-post-example/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-dependency-injection/index.html b/src/v2/examples/vue-20-dependency-injection/index.html
new file mode 100644
index 0000000000..78f72a66f0
--- /dev/null
+++ b/src/v2/examples/vue-20-dependency-injection/index.html
@@ -0,0 +1,97 @@
+
+
+
+ Dependency Injection Google Maps Demo
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-dependency-injection/package.json b/src/v2/examples/vue-20-dependency-injection/package.json
new file mode 100644
index 0000000000..a4a7d58da3
--- /dev/null
+++ b/src/v2/examples/vue-20-dependency-injection/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-dependency-injection",
+ "version": "1.0.0",
+ "description": "Vue.js Dependency Injection example using Google Maps.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-dependency-injection/sandbox.config.json b/src/v2/examples/vue-20-dependency-injection/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-dependency-injection/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-dynamic-components-with-binding/index.html b/src/v2/examples/vue-20-dynamic-components-with-binding/index.html
new file mode 100644
index 0000000000..57ba72a4b0
--- /dev/null
+++ b/src/v2/examples/vue-20-dynamic-components-with-binding/index.html
@@ -0,0 +1,74 @@
+
+
+
+ Dynamic Components Example
+
+
+
+
+
+
+ {{ tab.name }}
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-dynamic-components-with-binding/package.json b/src/v2/examples/vue-20-dynamic-components-with-binding/package.json
new file mode 100644
index 0000000000..fdff914b68
--- /dev/null
+++ b/src/v2/examples/vue-20-dynamic-components-with-binding/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-dynamic-components-with-binding",
+ "version": "1.0.0",
+ "description": "Showing binding to a component's options object.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-dynamic-components-with-binding/sandbox.config.json b/src/v2/examples/vue-20-dynamic-components-with-binding/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-dynamic-components-with-binding/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-dynamic-components/index.html b/src/v2/examples/vue-20-dynamic-components/index.html
new file mode 100644
index 0000000000..6d627b7ccb
--- /dev/null
+++ b/src/v2/examples/vue-20-dynamic-components/index.html
@@ -0,0 +1,68 @@
+
+
+
+ Dynamic Components Example
+
+
+
+
+
+
+ {{ tab }}
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-dynamic-components/package.json b/src/v2/examples/vue-20-dynamic-components/package.json
new file mode 100644
index 0000000000..67cb7f7c07
--- /dev/null
+++ b/src/v2/examples/vue-20-dynamic-components/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-dynamic-components",
+ "version": "1.0.0",
+ "description": "Used to dynamically switch between components, like in a tabbed interface.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-dynamic-components/sandbox.config.json b/src/v2/examples/vue-20-dynamic-components/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-dynamic-components/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-dynamic-state-transitions/index.html b/src/v2/examples/vue-20-dynamic-state-transitions/index.html
new file mode 100644
index 0000000000..ff026bb789
--- /dev/null
+++ b/src/v2/examples/vue-20-dynamic-state-transitions/index.html
@@ -0,0 +1,129 @@
+
+
+
+ Dynamic State Transitions
+
+
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-dynamic-state-transitions/package.json b/src/v2/examples/vue-20-dynamic-state-transitions/package.json
new file mode 100644
index 0000000000..6880b42447
--- /dev/null
+++ b/src/v2/examples/vue-20-dynamic-state-transitions/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-dynamic-state-transitions",
+ "version": "1.0.0",
+ "description": "Data backing state transitions can be updated in real time, like in this example.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-dynamic-state-transitions/sandbox.config.json b/src/v2/examples/vue-20-dynamic-state-transitions/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-dynamic-state-transitions/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-elastic-header/index.html b/src/v2/examples/vue-20-elastic-header/index.html
new file mode 100644
index 0000000000..b14e193495
--- /dev/null
+++ b/src/v2/examples/vue-20-elastic-header/index.html
@@ -0,0 +1,115 @@
+
+
+
+ Elastic Header
+
+
+
+
+
+
+
+
+
+
+ Elastic Draggable SVG Header
+
+ with Vue.js +
+ dynamics.js
+
+
+
+
+ Note this is just an effect demo - there are of course many
+ additional details if you want to use this in production, e.g.
+ handling responsive sizes, reload threshold and content scrolling.
+ Those are out of scope for this quick little hack. However, the idea
+ is that you can hide them as internal details of a Vue.js component
+ and expose a simple Web-Component-like interface.
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-elastic-header/package.json b/src/v2/examples/vue-20-elastic-header/package.json
new file mode 100644
index 0000000000..6362227733
--- /dev/null
+++ b/src/v2/examples/vue-20-elastic-header/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-elastic-header",
+ "version": "1.0.0",
+ "description": "Elastic Draggable SVG Header",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-elastic-header/sandbox.config.json b/src/v2/examples/vue-20-elastic-header/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-elastic-header/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-elastic-header/style.css b/src/v2/examples/vue-20-elastic-header/style.css
new file mode 100644
index 0000000000..f3fc3f0b5c
--- /dev/null
+++ b/src/v2/examples/vue-20-elastic-header/style.css
@@ -0,0 +1,45 @@
+h1 {
+ font-weight: 300;
+ font-size: 1.8em;
+ margin-top: 0;
+}
+a {
+ color: #fff;
+}
+.draggable-header-view {
+ background-color: #fff;
+ box-shadow: 0 4px 16px rgba(0, 0, 0, 0.15);
+ width: 320px;
+ height: 560px;
+ overflow: hidden;
+ margin: 30px auto;
+ position: relative;
+ font-family: "Roboto", Helvetica, Arial, sans-serif;
+ color: #fff;
+ font-size: 14px;
+ font-weight: 300;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+.draggable-header-view .bg {
+ position: absolute;
+ top: 0;
+ left: 0;
+ z-index: 0;
+}
+.draggable-header-view .header,
+.draggable-header-view .content {
+ position: relative;
+ z-index: 1;
+ padding: 30px;
+ box-sizing: border-box;
+}
+.draggable-header-view .header {
+ height: 160px;
+}
+.draggable-header-view .content {
+ color: #333;
+ line-height: 1.5em;
+}
diff --git a/src/v2/examples/vue-20-firebase-validation/index.html b/src/v2/examples/vue-20-firebase-validation/index.html
new file mode 100644
index 0000000000..dcdcd7af02
--- /dev/null
+++ b/src/v2/examples/vue-20-firebase-validation/index.html
@@ -0,0 +1,96 @@
+
+
+
+ Firebase + Validation
+
+
+
+
+
+
+
+
+
+
+ {{user.name}} - {{user.email}}
+ X
+
+
+
+
+ Name cannot be empty.
+
+ Please provide a valid email address.
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-firebase-validation/package.json b/src/v2/examples/vue-20-firebase-validation/package.json
new file mode 100644
index 0000000000..570fb291d7
--- /dev/null
+++ b/src/v2/examples/vue-20-firebase-validation/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-firebase-validation",
+ "version": "1.0.0",
+ "description": "This example uses Firebase as the data persistence backend and syncs between clients in real time (you can try opening it in multiple browser tabs). In addition, it performs instant validation using computed properties and triggers CSS transitions when adding/removing items.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-firebase-validation/sandbox.config.json b/src/v2/examples/vue-20-firebase-validation/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-firebase-validation/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-firebase-validation/style.css b/src/v2/examples/vue-20-firebase-validation/style.css
new file mode 100644
index 0000000000..761054c0c1
--- /dev/null
+++ b/src/v2/examples/vue-20-firebase-validation/style.css
@@ -0,0 +1,33 @@
+body {
+ font-family: Helvetica, Arial, sans-serif;
+}
+
+ul {
+ padding: 0;
+}
+
+.user {
+ height: 30px;
+ line-height: 30px;
+ padding: 10px;
+ border-top: 1px solid #eee;
+ overflow: hidden;
+ transition: all 0.25s ease;
+}
+
+.user:last-child {
+ border-bottom: 1px solid #eee;
+}
+
+.v-enter,
+.v-leave-active {
+ height: 0;
+ padding-top: 0;
+ padding-bottom: 0;
+ border-top-width: 0;
+ border-bottom-width: 0;
+}
+
+.errors {
+ color: #f00;
+}
diff --git a/src/v2/examples/vue-20-github-commits/index.html b/src/v2/examples/vue-20-github-commits/index.html
new file mode 100644
index 0000000000..fcd5d00d68
--- /dev/null
+++ b/src/v2/examples/vue-20-github-commits/index.html
@@ -0,0 +1,91 @@
+
+
+
+ GitHub Commits
+
+
+
+
+
+
Latest Vue.js Commits
+
+
+ {{ branch }}
+
+
vuejs/vue@{{ currentBranch }}
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-github-commits/package.json b/src/v2/examples/vue-20-github-commits/package.json
new file mode 100644
index 0000000000..8afebc6358
--- /dev/null
+++ b/src/v2/examples/vue-20-github-commits/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-github-commits",
+ "version": "1.0.0",
+ "description": "This example fetches latest Vue.js commits data from GitHub's API and displays them as a list. You can switch between the master and dev branches.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-github-commits/sandbox.config.json b/src/v2/examples/vue-20-github-commits/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-github-commits/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-github-commits/style.css b/src/v2/examples/vue-20-github-commits/style.css
new file mode 100644
index 0000000000..c0e705b77b
--- /dev/null
+++ b/src/v2/examples/vue-20-github-commits/style.css
@@ -0,0 +1,15 @@
+#demo {
+ font-family: "Helvetica", Arial, sans-serif;
+}
+a {
+ text-decoration: none;
+ color: #f66;
+}
+li {
+ line-height: 1.5em;
+ margin-bottom: 20px;
+}
+.author,
+.date {
+ font-weight: bold;
+}
diff --git a/src/v2/examples/vue-20-grid-component/index.html b/src/v2/examples/vue-20-grid-component/index.html
new file mode 100644
index 0000000000..40e8a947aa
--- /dev/null
+++ b/src/v2/examples/vue-20-grid-component/index.html
@@ -0,0 +1,121 @@
+
+
+
+ Grid Component
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-grid-component/package.json b/src/v2/examples/vue-20-grid-component/package.json
new file mode 100644
index 0000000000..1734610da9
--- /dev/null
+++ b/src/v2/examples/vue-20-grid-component/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-grid-component",
+ "version": "1.0.0",
+ "description": "This is an example of creating a reusable grid component and using it with external data.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-grid-component/sandbox.config.json b/src/v2/examples/vue-20-grid-component/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-grid-component/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-grid-component/style.css b/src/v2/examples/vue-20-grid-component/style.css
new file mode 100644
index 0000000000..f10002ab8f
--- /dev/null
+++ b/src/v2/examples/vue-20-grid-component/style.css
@@ -0,0 +1,60 @@
+body {
+ font-family: Helvetica Neue, Arial, sans-serif;
+ font-size: 14px;
+ color: #444;
+}
+
+table {
+ border: 2px solid #42b983;
+ border-radius: 3px;
+ background-color: #fff;
+}
+
+th {
+ background-color: #42b983;
+ color: rgba(255, 255, 255, 0.66);
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+td {
+ background-color: #f9f9f9;
+}
+
+th,
+td {
+ min-width: 120px;
+ padding: 10px 20px;
+}
+
+th.active {
+ color: #fff;
+}
+
+th.active .arrow {
+ opacity: 1;
+}
+
+.arrow {
+ display: inline-block;
+ vertical-align: middle;
+ width: 0;
+ height: 0;
+ margin-left: 5px;
+ opacity: 0.66;
+}
+
+.arrow.asc {
+ border-left: 4px solid transparent;
+ border-right: 4px solid transparent;
+ border-bottom: 4px solid #fff;
+}
+
+.arrow.dsc {
+ border-left: 4px solid transparent;
+ border-right: 4px solid transparent;
+ border-top: 4px solid #fff;
+}
diff --git a/src/v2/examples/vue-20-hello-world/index.html b/src/v2/examples/vue-20-hello-world/index.html
new file mode 100644
index 0000000000..95121199a6
--- /dev/null
+++ b/src/v2/examples/vue-20-hello-world/index.html
@@ -0,0 +1,21 @@
+
+
+
+ My first Vue app
+
+
+
+
+ {{ message }}
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-hello-world/package.json b/src/v2/examples/vue-20-hello-world/package.json
new file mode 100644
index 0000000000..c02e41273c
--- /dev/null
+++ b/src/v2/examples/vue-20-hello-world/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-hello-world",
+ "version": "1.0.0",
+ "description": "The easiest way to try out Vue.js, edit this Hello World example",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-hello-world/sandbox.config.json b/src/v2/examples/vue-20-hello-world/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-hello-world/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-keep-alive-with-dynamic-components/index.html b/src/v2/examples/vue-20-keep-alive-with-dynamic-components/index.html
new file mode 100644
index 0000000000..339d651065
--- /dev/null
+++ b/src/v2/examples/vue-20-keep-alive-with-dynamic-components/index.html
@@ -0,0 +1,97 @@
+
+
+
+ Vue Component Blog Post Example
+
+
+
+
+
+
+ {{ tab }}
+
+
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-keep-alive-with-dynamic-components/package.json b/src/v2/examples/vue-20-keep-alive-with-dynamic-components/package.json
new file mode 100644
index 0000000000..7bf11e28e3
--- /dev/null
+++ b/src/v2/examples/vue-20-keep-alive-with-dynamic-components/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-keep-alive-with-dynamic-components",
+ "version": "1.0.0",
+ "description": "The Posts tab maintains its state (the selected post) even when it's not rendered.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-keep-alive-with-dynamic-components/sandbox.config.json b/src/v2/examples/vue-20-keep-alive-with-dynamic-components/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-keep-alive-with-dynamic-components/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-keep-alive-with-dynamic-components/style.css b/src/v2/examples/vue-20-keep-alive-with-dynamic-components/style.css
new file mode 100644
index 0000000000..5681ac6cb3
--- /dev/null
+++ b/src/v2/examples/vue-20-keep-alive-with-dynamic-components/style.css
@@ -0,0 +1,49 @@
+.tab-button {
+ padding: 6px 10px;
+ border-top-left-radius: 3px;
+ border-top-right-radius: 3px;
+ border: 1px solid #ccc;
+ cursor: pointer;
+ background: #f0f0f0;
+ margin-bottom: -1px;
+ margin-right: -1px;
+}
+.tab-button:hover {
+ background: #e0e0e0;
+}
+.tab-button.active {
+ background: #e0e0e0;
+}
+.tab {
+ border: 1px solid #ccc;
+ padding: 10px;
+}
+.posts-tab {
+ display: flex;
+}
+.posts-sidebar {
+ max-width: 40vw;
+ margin: 0;
+ padding: 0 10px 0 0;
+ list-style-type: none;
+ border-right: 1px solid #ccc;
+}
+.posts-sidebar li {
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ overflow: hidden;
+ cursor: pointer;
+}
+.posts-sidebar li:hover {
+ background: #eee;
+}
+.posts-sidebar li.selected {
+ background: lightblue;
+}
+.selected-post-container {
+ padding-left: 10px;
+}
+.selected-post > :first-child {
+ margin-top: 0;
+ padding-top: 0;
+}
diff --git a/src/v2/examples/vue-20-list-move-transitions/index.html b/src/v2/examples/vue-20-list-move-transitions/index.html
new file mode 100644
index 0000000000..536a9ba25c
--- /dev/null
+++ b/src/v2/examples/vue-20-list-move-transitions/index.html
@@ -0,0 +1,43 @@
+
+
+
+ List Move Transitions Sudoku Example
+
+
+
+
+
+
+
Lazy Sudoku
+
Keep hitting the shuffle button until you win.
+
+
+ Shuffle
+
+
+
+ {{ cell.number }}
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-list-move-transitions/package.json b/src/v2/examples/vue-20-list-move-transitions/package.json
new file mode 100644
index 0000000000..f18a53b340
--- /dev/null
+++ b/src/v2/examples/vue-20-list-move-transitions/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-list-move-transitions",
+ "version": "1.0.0",
+ "description": "Example showing list entering/leaving transitions in Sudoku.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-list-move-transitions/sandbox.config.json b/src/v2/examples/vue-20-list-move-transitions/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-list-move-transitions/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-list-move-transitions/style.css b/src/v2/examples/vue-20-list-move-transitions/style.css
new file mode 100644
index 0000000000..103973e3ca
--- /dev/null
+++ b/src/v2/examples/vue-20-list-move-transitions/style.css
@@ -0,0 +1,25 @@
+.container {
+ display: flex;
+ flex-wrap: wrap;
+ width: 238px;
+ margin-top: 10px;
+}
+.cell {
+ display: flex;
+ justify-content: space-around;
+ align-items: center;
+ width: 25px;
+ height: 25px;
+ border: 1px solid #aaa;
+ margin-right: -1px;
+ margin-bottom: -1px;
+}
+.cell:nth-child(3n) {
+ margin-right: 0;
+}
+.cell:nth-child(27n) {
+ margin-bottom: 0;
+}
+.cell-move {
+ transition: transform 1s;
+}
diff --git a/src/v2/examples/vue-20-markdown-editor/index.html b/src/v2/examples/vue-20-markdown-editor/index.html
new file mode 100644
index 0000000000..e740dfb816
--- /dev/null
+++ b/src/v2/examples/vue-20-markdown-editor/index.html
@@ -0,0 +1,35 @@
+
+
+
+ Markdown Editor
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-markdown-editor/package.json b/src/v2/examples/vue-20-markdown-editor/package.json
new file mode 100644
index 0000000000..7866640c16
--- /dev/null
+++ b/src/v2/examples/vue-20-markdown-editor/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-markdown-editor",
+ "version": "1.0.0",
+ "description": "Dead simple Markdown editor.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-markdown-editor/sandbox.config.json b/src/v2/examples/vue-20-markdown-editor/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-markdown-editor/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-markdown-editor/style.css b/src/v2/examples/vue-20-markdown-editor/style.css
new file mode 100644
index 0000000000..01cacdc9d3
--- /dev/null
+++ b/src/v2/examples/vue-20-markdown-editor/style.css
@@ -0,0 +1,33 @@
+html,
+body,
+#editor {
+ margin: 0;
+ height: 100%;
+ font-family: "Helvetica Neue", Arial, sans-serif;
+ color: #333;
+}
+
+textarea,
+#editor div {
+ display: inline-block;
+ width: 49%;
+ height: 100%;
+ vertical-align: top;
+ box-sizing: border-box;
+ padding: 0 20px;
+}
+
+textarea {
+ border: none;
+ border-right: 1px solid #ccc;
+ resize: none;
+ outline: none;
+ background-color: #f6f6f6;
+ font-size: 14px;
+ font-family: "Monaco", courier, monospace;
+ padding: 20px;
+}
+
+code {
+ color: #f66;
+}
diff --git a/src/v2/examples/vue-20-modal-component/index.html b/src/v2/examples/vue-20-modal-component/index.html
new file mode 100644
index 0000000000..60235e8e7e
--- /dev/null
+++ b/src/v2/examples/vue-20-modal-component/index.html
@@ -0,0 +1,69 @@
+
+
+
+ Modal Component
+
+
+
+
+
+
+
+
+ Show Modal
+
+
+
+ custom header
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-modal-component/package.json b/src/v2/examples/vue-20-modal-component/package.json
new file mode 100644
index 0000000000..6d64ba2432
--- /dev/null
+++ b/src/v2/examples/vue-20-modal-component/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-modal-component",
+ "version": "1.0.0",
+ "description": "Features used: component, prop passing, content insertion, transitions.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-modal-component/sandbox.config.json b/src/v2/examples/vue-20-modal-component/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-modal-component/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-modal-component/style.css b/src/v2/examples/vue-20-modal-component/style.css
new file mode 100644
index 0000000000..d36f166fb4
--- /dev/null
+++ b/src/v2/examples/vue-20-modal-component/style.css
@@ -0,0 +1,63 @@
+.modal-mask {
+ position: fixed;
+ z-index: 9998;
+ top: 0;
+ left: 0;
+ width: 100%;
+ height: 100%;
+ background-color: rgba(0, 0, 0, 0.5);
+ display: table;
+ transition: opacity 0.3s ease;
+}
+
+.modal-wrapper {
+ display: table-cell;
+ vertical-align: middle;
+}
+
+.modal-container {
+ width: 300px;
+ margin: 0px auto;
+ padding: 20px 30px;
+ background-color: #fff;
+ border-radius: 2px;
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.33);
+ transition: all 0.3s ease;
+ font-family: Helvetica, Arial, sans-serif;
+}
+
+.modal-header h3 {
+ margin-top: 0;
+ color: #42b983;
+}
+
+.modal-body {
+ margin: 20px 0;
+}
+
+.modal-default-button {
+ float: right;
+}
+
+/*
+ * The following styles are auto-applied to elements with
+ * transition="modal" when their visibility is toggled
+ * by Vue.js.
+ *
+ * You can easily play with the modal transition by editing
+ * these styles.
+ */
+
+.modal-enter {
+ opacity: 0;
+}
+
+.modal-leave-active {
+ opacity: 0;
+}
+
+.modal-enter .modal-container,
+.modal-leave-active .modal-container {
+ -webkit-transform: scale(1.1);
+ transform: scale(1.1);
+}
diff --git a/src/v2/examples/vue-20-priority-d-rules-correct-example/index.html b/src/v2/examples/vue-20-priority-d-rules-correct-example/index.html
new file mode 100644
index 0000000000..50b2cba0e8
--- /dev/null
+++ b/src/v2/examples/vue-20-priority-d-rules-correct-example/index.html
@@ -0,0 +1,47 @@
+
+
+
+ Priority D Rules Correct Example
+
+
+
+
+
+
+
+ Save
+
+
+ Edit
+
+
+
+
+ With a unique key on each conditional element, the
+ transition is now applied.
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-priority-d-rules-correct-example/package.json b/src/v2/examples/vue-20-priority-d-rules-correct-example/package.json
new file mode 100644
index 0000000000..7afc08c225
--- /dev/null
+++ b/src/v2/examples/vue-20-priority-d-rules-correct-example/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-priority-d-rules-correct-example",
+ "version": "1.0.0",
+ "description": "A unique key on each conditional element so the transition is applied.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-priority-d-rules-correct-example/sandbox.config.json b/src/v2/examples/vue-20-priority-d-rules-correct-example/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-priority-d-rules-correct-example/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-priority-d-rules-unintended-consequences/index.html b/src/v2/examples/vue-20-priority-d-rules-unintended-consequences/index.html
new file mode 100644
index 0000000000..81951e7667
--- /dev/null
+++ b/src/v2/examples/vue-20-priority-d-rules-unintended-consequences/index.html
@@ -0,0 +1,54 @@
+
+
+
+ Priority D Rules Unintended Consequences
+
+
+
+
+
+
+
+ Save
+
+
+ Edit
+
+
+
+
+ When clicking on the <button> above, the transition
+ is never applied because Vue is reusing the same element for render
+ efficiency. To force Vue to treat these as separate elements, a
+ unique key must be added
+ to each conditional element.
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-priority-d-rules-unintended-consequences/package.json b/src/v2/examples/vue-20-priority-d-rules-unintended-consequences/package.json
new file mode 100644
index 0000000000..43c1c3a9f2
--- /dev/null
+++ b/src/v2/examples/vue-20-priority-d-rules-unintended-consequences/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-priority-d-rules-unintended-consequences",
+ "version": "1.0.0",
+ "description": "Lacking a unique key on each conditional element, the transition is never applied.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-priority-d-rules-unintended-consequences/sandbox.config.json b/src/v2/examples/vue-20-priority-d-rules-unintended-consequences/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-priority-d-rules-unintended-consequences/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-programmatic-event-listeners/index.html b/src/v2/examples/vue-20-programmatic-event-listeners/index.html
new file mode 100644
index 0000000000..ba0503c97d
--- /dev/null
+++ b/src/v2/examples/vue-20-programmatic-event-listeners/index.html
@@ -0,0 +1,32 @@
+
+
+
+ Programmatic Event Listeners using Pikaday
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-programmatic-event-listeners/package.json b/src/v2/examples/vue-20-programmatic-event-listeners/package.json
new file mode 100644
index 0000000000..42312caa1f
--- /dev/null
+++ b/src/v2/examples/vue-20-programmatic-event-listeners/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-programmatic-event-listeners",
+ "version": "1.0.0",
+ "description": "Vue.js Programmatic Event Listeners example using Pikaday",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-programmatic-event-listeners/sandbox.config.json b/src/v2/examples/vue-20-programmatic-event-listeners/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-programmatic-event-listeners/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-realtime-with-deepstreamhub/index.html b/src/v2/examples/vue-20-realtime-with-deepstreamhub/index.html
new file mode 100644
index 0000000000..e9396f3868
--- /dev/null
+++ b/src/v2/examples/vue-20-realtime-with-deepstreamhub/index.html
@@ -0,0 +1,184 @@
+
+
+
+ Realtime with deepstreamHub
+
+
+
+
+
+
+
+
+
+ Connection-State is: {{connectionState}}
+
+
+
+
+
+
+
+
+
Realtime Datastore
+
+ Firstname
+
+
+
+ Lastname
+
+
+
+
+
+
+
+
+
Publish
+
+ Send test-event with
+
+
+
+
+
+
+
+
+
+
+
Request
+
+ Make multiply request
+
+
+
+ {{displayResponse}}
+
+
+
+
Response
+
Multiply number with:
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-realtime-with-deepstreamhub/package.json b/src/v2/examples/vue-20-realtime-with-deepstreamhub/package.json
new file mode 100644
index 0000000000..abf1458b23
--- /dev/null
+++ b/src/v2/examples/vue-20-realtime-with-deepstreamhub/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-realtime-with-deepstreamhub",
+ "version": "1.0.0",
+ "description": "This example uses deepstreamHub to synchronize realtime data, send events and make remote procedure calls between clients (you can try opening it in multiple browser windows).",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-realtime-with-deepstreamhub/sandbox.config.json b/src/v2/examples/vue-20-realtime-with-deepstreamhub/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-realtime-with-deepstreamhub/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-realtime-with-deepstreamhub/style.css b/src/v2/examples/vue-20-realtime-with-deepstreamhub/style.css
new file mode 100644
index 0000000000..b643051dfb
--- /dev/null
+++ b/src/v2/examples/vue-20-realtime-with-deepstreamhub/style.css
@@ -0,0 +1,122 @@
+* {
+ margin: 0;
+ padding: 0;
+ list-style-type: none;
+ font-family: RobotoCondensed, sans-serif;
+ font-size: 14px;
+ color: #333;
+ box-sizing: border-box;
+ outline: none;
+ transition: all 200ms ease;
+}
+
+body {
+ background-color: #fff;
+}
+
+.group {
+ width: 80%;
+ max-width: 800px;
+ margin: 40px auto;
+ padding: 20px;
+ position: relative;
+ overflow: hidden;
+}
+
+.group.connectionState {
+ margin: 10px auto 0;
+ padding: 0 20px;
+}
+
+h2 {
+ font-size: 20px;
+ border-bottom: 1px solid #ccc;
+ padding-bottom: 4px;
+ margin-bottom: 10px;
+ position: relative;
+}
+
+h2 small {
+ position: absolute;
+ right: 0;
+}
+
+h2 small * {
+ display: inline-block;
+ vertical-align: middle;
+ font-weight: normal;
+ color: #333;
+ font-size: 12px;
+ cursor: pointer;
+}
+
+button,
+input,
+.item {
+ height: 32px;
+ padding: 6px;
+}
+
+button {
+ border: none;
+ background: #7185ec;
+ color: #fff;
+ font-weight: 500;
+ border-radius: 4px;
+ cursor: pointer;
+ text-align: center;
+ cursor: pointer;
+ font-weight: bold;
+ box-shadow: 1px 1px 3px 0px rgba(0, 0, 0, 0.2);
+}
+
+button:hover {
+ background-color: #586cd8;
+}
+
+button:active {
+ position: relative;
+ top: 1px;
+ left: 1px;
+ box-shadow: none;
+}
+
+.half {
+ width: 48%;
+ float: left;
+ position: relative;
+}
+
+.half.left {
+ margin-right: 4%;
+}
+
+label {
+ font-size: 11px;
+ font-style: italic;
+}
+
+input {
+ border-radius: 4px;
+ border: 1px solid #ccc;
+}
+
+input:focus {
+ border-color: #7185ec;
+}
+
+.input-group input {
+ width: 100%;
+}
+
+span.response {
+ display: inline-block;
+ background-color: #dddddd;
+}
+
+@media screen and (max-width: 900px) {
+ .half {
+ width: 100%;
+ margin: 0 0 10px !important;
+ }
+}
diff --git a/src/v2/examples/vue-20-single-file-components/Hello.vue b/src/v2/examples/vue-20-single-file-components/Hello.vue
new file mode 100644
index 0000000000..9ca04cbb4c
--- /dev/null
+++ b/src/v2/examples/vue-20-single-file-components/Hello.vue
@@ -0,0 +1,20 @@
+
+ {{ greeting }} World!
+
+
+
+
+
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-single-file-components/index.html b/src/v2/examples/vue-20-single-file-components/index.html
new file mode 100644
index 0000000000..865e670f40
--- /dev/null
+++ b/src/v2/examples/vue-20-single-file-components/index.html
@@ -0,0 +1 @@
+
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-single-file-components/index.js b/src/v2/examples/vue-20-single-file-components/index.js
new file mode 100644
index 0000000000..4cd7af61fb
--- /dev/null
+++ b/src/v2/examples/vue-20-single-file-components/index.js
@@ -0,0 +1,10 @@
+import Vue from "vue";
+import App from "./Hello";
+
+Vue.config.productionTip = false;
+
+new Vue({
+ el: "#app",
+ template: " ",
+ components: { App }
+});
diff --git a/src/v2/examples/vue-20-single-file-components/package.json b/src/v2/examples/vue-20-single-file-components/package.json
new file mode 100644
index 0000000000..36dd9df6e4
--- /dev/null
+++ b/src/v2/examples/vue-20-single-file-components/package.json
@@ -0,0 +1,17 @@
+{
+ "name": "vue-20-single-file-components",
+ "version": "0.1.0",
+ "private": true,
+ "scripts": {
+ "serve": "vue-cli-service serve",
+ "build": "vue-cli-service build",
+ "lint": "vue-cli-service lint"
+ },
+ "dependencies": {
+ "vue": "^2.6.11"
+ },
+ "devDependencies": {},
+ "browserslist": ["> 1%", "last 2 versions", "not ie <= 8"],
+ "keywords": [],
+ "description": "Hello.vue single-file components example using a .vue extension."
+}
diff --git a/src/v2/examples/vue-20-svg-graph/index.html b/src/v2/examples/vue-20-svg-graph/index.html
new file mode 100644
index 0000000000..885a3fbbef
--- /dev/null
+++ b/src/v2/examples/vue-20-svg-graph/index.html
@@ -0,0 +1,142 @@
+
+
+
+ SVG Graph
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{stat.label}}
+
+ {{stat.value}}
+ X
+
+
+
{{ stats }}
+
+
+ * input[type="range"] requires IE10 or above.
+
+
+
+
diff --git a/src/v2/examples/vue-20-svg-graph/package.json b/src/v2/examples/vue-20-svg-graph/package.json
new file mode 100644
index 0000000000..afbe362f77
--- /dev/null
+++ b/src/v2/examples/vue-20-svg-graph/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-svg-graph",
+ "version": "1.0.0",
+ "description": "This example showcases a combination of custom component, computed property, two-way binding and SVG support.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-svg-graph/sandbox.config.json b/src/v2/examples/vue-20-svg-graph/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-svg-graph/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-svg-graph/style.css b/src/v2/examples/vue-20-svg-graph/style.css
new file mode 100644
index 0000000000..b533e006a6
--- /dev/null
+++ b/src/v2/examples/vue-20-svg-graph/style.css
@@ -0,0 +1,31 @@
+body {
+ font-family: Helvetica Neue, Arial, sans-serif;
+}
+
+polygon {
+ fill: #42b983;
+ opacity: 0.75;
+}
+
+circle {
+ fill: transparent;
+ stroke: #999;
+}
+
+text {
+ font-family: Helvetica Neue, Arial, sans-serif;
+ font-size: 10px;
+ fill: #666;
+}
+
+label {
+ display: inline-block;
+ margin-left: 10px;
+ width: 20px;
+}
+
+#raw {
+ position: absolute;
+ top: 0;
+ left: 300px;
+}
diff --git a/src/v2/examples/vue-20-template-compilation/index.html b/src/v2/examples/vue-20-template-compilation/index.html
new file mode 100644
index 0000000000..1582c6ea42
--- /dev/null
+++ b/src/v2/examples/vue-20-template-compilation/index.html
@@ -0,0 +1,83 @@
+
+
+
+ Template Compilation
+
+
+
+
+
+
+
+
render:
+
{{ result.render }}
+
staticRenderFns:
+
_m({{ index }}): {{ fn }}
+
{{ result.staticRenderFns }}
+
+
+
Compilation Error:
+
{{ result }}
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-template-compilation/package.json b/src/v2/examples/vue-20-template-compilation/package.json
new file mode 100644
index 0000000000..c802e56604
--- /dev/null
+++ b/src/v2/examples/vue-20-template-compilation/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-template-compilation",
+ "version": "1.0.0",
+ "description": "A demo using Vue.compile to live-compile a template string.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-template-compilation/sandbox.config.json b/src/v2/examples/vue-20-template-compilation/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-template-compilation/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-template-compilation/style.css b/src/v2/examples/vue-20-template-compilation/style.css
new file mode 100644
index 0000000000..02a88e4503
--- /dev/null
+++ b/src/v2/examples/vue-20-template-compilation/style.css
@@ -0,0 +1,45 @@
+*,
+*::before,
+*::after {
+ box-sizing: border-box;
+}
+
+body {
+ font-family: "Source Sans Pro", "Helvetica Neue", Arial, sans-serif;
+ -webkit-user-select: inherit;
+ user-select: inherit;
+ font-size: 14px;
+ color: #34495e;
+}
+
+pre {
+ padding: 10px;
+ overflow-x: auto;
+ background: #f2f2f2;
+}
+
+code {
+ white-space: pre;
+ padding: 0;
+}
+
+code,
+pre,
+textarea {
+ font-family: "Roboto Mono", Monaco, courier, monospace;
+}
+
+textarea {
+ width: 100%;
+ font-size: 14px;
+ margin-bottom: 8px;
+ border-color: #bbb;
+ padding: 8px;
+ border-bottom-width: 2px;
+ outline: none;
+ color: #34495e;
+}
+
+textarea:focus {
+ background: lightyellow;
+}
diff --git a/src/v2/examples/vue-20-todomvc/index.html b/src/v2/examples/vue-20-todomvc/index.html
new file mode 100644
index 0000000000..04463a3b7c
--- /dev/null
+++ b/src/v2/examples/vue-20-todomvc/index.html
@@ -0,0 +1,258 @@
+
+
+
+ TodoMVC
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-todomvc/package.json b/src/v2/examples/vue-20-todomvc/package.json
new file mode 100644
index 0000000000..8fb7dbe6d5
--- /dev/null
+++ b/src/v2/examples/vue-20-todomvc/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-todomvc",
+ "version": "1.0.0",
+ "description": "This is a fully spec-compliant TodoMVC implementation in under 120 effective lines of JavaScript (excluding comments and blank lines).",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-todomvc/sandbox.config.json b/src/v2/examples/vue-20-todomvc/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-todomvc/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-tree-view/index.html b/src/v2/examples/vue-20-tree-view/index.html
new file mode 100644
index 0000000000..63476085e2
--- /dev/null
+++ b/src/v2/examples/vue-20-tree-view/index.html
@@ -0,0 +1,121 @@
+
+
+
+ Tree View
+
+
+
+
+
+
+
+ (You can double click on an item to turn it into a folder.)
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-tree-view/package.json b/src/v2/examples/vue-20-tree-view/package.json
new file mode 100644
index 0000000000..911f9e37e4
--- /dev/null
+++ b/src/v2/examples/vue-20-tree-view/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-tree-view",
+ "version": "1.0.0",
+ "description": "Example of a simple tree view implementation showcasing recursive usage of components.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-tree-view/sandbox.config.json b/src/v2/examples/vue-20-tree-view/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-tree-view/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-tree-view/style.css b/src/v2/examples/vue-20-tree-view/style.css
new file mode 100644
index 0000000000..39c9133b8c
--- /dev/null
+++ b/src/v2/examples/vue-20-tree-view/style.css
@@ -0,0 +1,15 @@
+body {
+ font-family: Menlo, Consolas, monospace;
+ color: #444;
+}
+.item {
+ cursor: pointer;
+}
+.bold {
+ font-weight: bold;
+}
+ul {
+ padding-left: 1em;
+ line-height: 1.5em;
+ list-style-type: dot;
+}
diff --git a/src/v2/examples/vue-20-two-way-currency-filter/currency-validator.js b/src/v2/examples/vue-20-two-way-currency-filter/currency-validator.js
new file mode 100644
index 0000000000..80ab295e34
--- /dev/null
+++ b/src/v2/examples/vue-20-two-way-currency-filter/currency-validator.js
@@ -0,0 +1,61 @@
+var currencyValidator = {
+ format: function(number) {
+ return (Math.trunc(number * 100) / 100).toFixed(2);
+ },
+ parse: function(newString, oldNumber) {
+ var CleanParse = function(value) {
+ return { value: value };
+ };
+ var CurrencyWarning = function(warning, value) {
+ return {
+ warning: warning,
+ value: value,
+ attempt: newString
+ };
+ };
+ var NotAValidDollarAmountWarning = function(value) {
+ return new CurrencyWarning(
+ newString + " is not a valid dollar amount",
+ value
+ );
+ };
+ var AutomaticConversionWarning = function(value) {
+ return new CurrencyWarning(
+ newString + " was automatically converted to " + value,
+ value
+ );
+ };
+
+ var newNumber = Number(newString);
+ var indexOfDot = newString.indexOf(".");
+ var indexOfE = newString.indexOf("e");
+
+ if (isNaN(newNumber)) {
+ if (
+ indexOfDot === -1 &&
+ indexOfE > 0 &&
+ indexOfE === newString.length - 1 &&
+ Number(newString.slice(0, indexOfE)) !== 0
+ ) {
+ return new CleanParse(oldNumber);
+ } else {
+ return new NotAValidDollarAmountWarning(oldNumber);
+ }
+ }
+
+ var newCurrencyString = currencyValidator.format(newNumber);
+ var newCurrencyNumber = Number(newCurrencyString);
+
+ if (newCurrencyNumber === newNumber) {
+ if (indexOfE !== -1 && indexOfE === newString.length - 2) {
+ return new AutomaticConversionWarning(newNumber);
+ } else {
+ return new CleanParse(newNumber);
+ }
+ } else {
+ return new NotAValidDollarAmountWarning(
+ newNumber > newCurrencyNumber ? newCurrencyNumber : oldNumber
+ );
+ }
+ }
+};
diff --git a/src/v2/examples/vue-20-two-way-currency-filter/index.html b/src/v2/examples/vue-20-two-way-currency-filter/index.html
new file mode 100644
index 0000000000..c3fd6e2550
--- /dev/null
+++ b/src/v2/examples/vue-20-two-way-currency-filter/index.html
@@ -0,0 +1,90 @@
+
+
+
+ Two-way Currency Filter
+
+
+
+
+
+
+
+
+
+
+
Total: ${{ total }}
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-two-way-currency-filter/package.json b/src/v2/examples/vue-20-two-way-currency-filter/package.json
new file mode 100644
index 0000000000..ef67bd57a8
--- /dev/null
+++ b/src/v2/examples/vue-20-two-way-currency-filter/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-two-way-currency-filter",
+ "version": "1.0.0",
+ "description": "Using lifecycle hooks and DOM events in place of the hidden behavior of two-way filters",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
diff --git a/src/v2/examples/vue-20-two-way-currency-filter/sandbox.config.json b/src/v2/examples/vue-20-two-way-currency-filter/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-two-way-currency-filter/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/examples/vue-20-wrapper-component/index.html b/src/v2/examples/vue-20-wrapper-component/index.html
new file mode 100644
index 0000000000..7ee7577af8
--- /dev/null
+++ b/src/v2/examples/vue-20-wrapper-component/index.html
@@ -0,0 +1,90 @@
+
+
+
+ Wrapper Component
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/v2/examples/vue-20-wrapper-component/package.json b/src/v2/examples/vue-20-wrapper-component/package.json
new file mode 100644
index 0000000000..92fe02c5c7
--- /dev/null
+++ b/src/v2/examples/vue-20-wrapper-component/package.json
@@ -0,0 +1,14 @@
+{
+ "name": "vue-20-wrapper-component",
+ "version": "1.0.0",
+ "description": "In this example we are integrating a 3rd party jQuery plugin (select2) by wrapping it inside a custom component.",
+ "main": "index.html",
+ "scripts": {
+ "start": "serve"
+ },
+ "keywords": [],
+ "license": "MIT",
+ "devDependencies": {
+ "serve": "^11.2.0"
+ }
+}
\ No newline at end of file
diff --git a/src/v2/examples/vue-20-wrapper-component/sandbox.config.json b/src/v2/examples/vue-20-wrapper-component/sandbox.config.json
new file mode 100644
index 0000000000..5866ed7445
--- /dev/null
+++ b/src/v2/examples/vue-20-wrapper-component/sandbox.config.json
@@ -0,0 +1,3 @@
+{
+ "template": "static"
+}
diff --git a/src/v2/guide/class-and-style.md b/src/v2/guide/class-and-style.md
index 5db43bbab3..60171d440b 100644
--- a/src/v2/guide/class-and-style.md
+++ b/src/v2/guide/class-and-style.md
@@ -7,6 +7,7 @@ order: 6
A common need for data binding is manipulating an element's class list and its inline styles. Since they are both attributes, we can use `v-bind` to handle them: we only need to calculate a final string with our expressions. However, meddling with string concatenation is annoying and error-prone. For this reason, Vue provides special enhancements when `v-bind` is used with `class` and `style`. In addition to strings, the expressions can also evaluate to objects or arrays.
## Binding HTML Classes
+
### Object Syntax
@@ -21,9 +22,10 @@ The above syntax means the presence of the `active` class will be determined by
You can have multiple classes toggled by having more fields in the object. In addition, the `v-bind:class` directive can also co-exist with the plain `class` attribute. So given the following template:
``` html
-
-
+
```
And the following data:
diff --git a/src/v2/guide/comparison.md b/src/v2/guide/comparison.md
index e940d312ee..c4b87ffd4d 100644
--- a/src/v2/guide/comparison.md
+++ b/src/v2/guide/comparison.md
@@ -8,7 +8,7 @@ This is definitely the most difficult page in the guide to write, but we do feel
We also try very hard to avoid bias. As the core team, we obviously like Vue a lot. There are some problems we think it solves better than anything else out there. If we didn't believe that, we wouldn't be working on it. We do want to be fair and accurate though. Where other libraries offer significant advantages, such as React's vast ecosystem of alternative renderers or Knockout's browser support back to IE6, we try to list these as well.
-We'd also like **your** help keeping this document up-to-date because the JavaScript world moves fast! If you notice an inaccuracy or something that doesn't seem quite right, please let us know by [opening an issue](https://github.com/vuejs/vuejs.org/issues/new?title=Inaccuracy+in+comparisons+guide).
+We'd also like **your** help keeping this document up-to-date because the JavaScript world moves fast! If you notice an inaccuracy or something that doesn't seem quite right, please let us know by [opening an issue](https://github.com/vuejs/v2.vuejs.org/issues/new?title=Inaccuracy+in+comparisons+guide).
## React
@@ -22,11 +22,11 @@ Being so similar in scope, we've put more time into fine-tuning this comparison
With that said, it's inevitable that the comparison would appear biased towards Vue to some React users, as many of the subjects explored are to some extent subjective. We acknowledge the existence of varying technical taste, and this comparison primarily aims to outline the reasons why Vue could potentially be a better fit if your preferences happen to coincide with ours.
-The React community [has been instrumental](https://github.com/vuejs/vuejs.org/issues/364) in helping us achieve this balance, with special thanks to Dan Abramov from the React team. He was extremely generous with his time and considerable expertise to help us refine this document until we were [both happy](https://github.com/vuejs/vuejs.org/issues/364#issuecomment-244575740) with the final result.
+Some of the sections below may also be slightly outdated due to recent updates in React 16+, and we are planning to work with the React community to revamp this section in the near future.
### Runtime Performance
-Both React and Vue are exceptionally and similarly fast, so speed is unlikely to be a deciding factor in choosing between them. For specific metrics though, check out this [3rd party benchmark](http://www.stefankrause.net/js-frameworks-benchmark7/table.html), which focuses on raw render/update performance with very simple component trees.
+Both React and Vue are exceptionally and similarly fast, so speed is unlikely to be a deciding factor in choosing between them. For specific metrics though, check out this [3rd party benchmark](https://stefankrause.net/js-frameworks-benchmark8/table.html), which focuses on raw render/update performance with very simple component trees.
#### Optimization Efforts
@@ -68,7 +68,7 @@ On a higher level, we can divide components into two categories: presentational
#### Component-Scoped CSS
-Unless you spread components out over multiple files (for example with [CSS Modules](https://github.com/gajus/react-css-modules)), scoping CSS in React is often done via CSS-in-JS solutions (e.g. [styled-components](https://github.com/styled-components/styled-components), [glamorous](https://github.com/paypal/glamorous), and [emotion](https://github.com/emotion-js/emotion)). This introduces a new component-oriented styling paradigm that is different from the normal CSS authoring process. Additionally, although there is support for extracting CSS into a single stylesheet at build time, it is still common that a runtime will need to be included in the bundle for styling to work properly. While you gain access to the dynamism of JavaScript while constructing your styles, the tradeoff is often increased bundle size and runtime cost.
+Unless you spread components out over multiple files (for example with [CSS Modules](https://github.com/gajus/react-css-modules)), scoping CSS in React is often done via CSS-in-JS solutions (e.g. [styled-components](https://github.com/styled-components/styled-components) and [emotion](https://github.com/emotion-js/emotion)). This introduces a new component-oriented styling paradigm that is different from the normal CSS authoring process. Additionally, although there is support for extracting CSS into a single stylesheet at build time, it is still common that a runtime will need to be included in the bundle for styling to work properly. While you gain access to the dynamism of JavaScript while constructing your styles, the tradeoff is often increased bundle size and runtime cost.
If you are a fan of CSS-in-JS, many of the popular CSS-in-JS libraries support Vue (e.g. [styled-components-vue](https://github.com/styled-components/vue-styled-components) and [vue-emotion](https://github.com/egoist/vue-emotion)). The main difference between React and Vue here is that the default method of styling in Vue is through more familiar `style` tags in [single-file components](single-file-components.html).
@@ -86,21 +86,21 @@ If you are a fan of CSS-in-JS, many of the popular CSS-in-JS libraries support V
The optional `scoped` attribute automatically scopes this CSS to your component by adding a unique attribute (such as `data-v-21e5b78`) to elements and compiling `.list-container:hover` to something like `.list-container[data-v-21e5b78]:hover`.
-Lastly, the styling in Vue's single-file component's is very flexible. Through [vue-loader](https://github.com/vuejs/vue-loader), you can use any preprocessor, post-processor, and even deep integration with [CSS Modules](https://vue-loader.vuejs.org/en/features/css-modules.html) -- all within the `
+{% endraw %}
+
+You'll notice that if you select a post, switch to the _Archive_ tab, then switch back to _Posts_, it's no longer showing the post you selected. That's because each time you switch to a new tab, Vue creates a new instance of the `currentTabComponent`.
+
+Recreating dynamic components is normally useful behavior, but in this case, we'd really like those tab component instances to be cached once they're created for the first time. To solve this problem, we can wrap our dynamic component with a `` element:
+
+``` html
+
+
+
+
+```
+
+Check out the result below:
+
+{% raw %}
+
+ {{ tab }}
+
+
+
+
+
+{% endraw %}
+
+Now the _Posts_ tab maintains its state (the selected post) even when it's not rendered. See [this example](https://codesandbox.io/s/github/vuejs/v2.vuejs.org/tree/master/src/v2/examples/vue-20-keep-alive-with-dynamic-components) for the complete code.
+
+Note that `` requires the components being switched between to all have names, either using the `name` option on a component, or through local/global registration.
+
+Check out more details on `` in the [API reference](../api/#keep-alive).
+
+## Async Components
+
+
+
+In large applications, we may need to divide the app into smaller chunks and only load a component from the server when it's needed. To make that easier, Vue allows you to define your component as a factory function that asynchronously resolves your component definition. Vue will only trigger the factory function when the component needs to be rendered and will cache the result for future re-renders. For example:
+
+``` js
+Vue.component('async-example', function (resolve, reject) {
+ setTimeout(function () {
+ // Pass the component definition to the resolve callback
+ resolve({
+ template: 'I am async!
'
+ })
+ }, 1000)
+})
+```
+
+As you can see, the factory function receives a `resolve` callback, which should be called when you have retrieved your component definition from the server. You can also call `reject(reason)` to indicate the load has failed. The `setTimeout` here is for demonstration; how to retrieve the component is up to you. One recommended approach is to use async components together with [Webpack's code-splitting feature](https://webpack.js.org/guides/code-splitting/):
+
+``` js
+Vue.component('async-webpack-example', function (resolve) {
+ // This special require syntax will instruct Webpack to
+ // automatically split your built code into bundles which
+ // are loaded over Ajax requests.
+ require(['./my-async-component'], resolve)
+})
+```
+
+You can also return a `Promise` in the factory function, so with Webpack 2 and ES2015 syntax you can make use of dynamic imports:
+
+``` js
+Vue.component(
+ 'async-webpack-example',
+ // A dynamic import returns a Promise.
+ () => import('./my-async-component')
+)
+```
+
+When using [local registration](components-registration.html#Local-Registration), you can also directly provide a function that returns a `Promise`:
+
+``` js
+new Vue({
+ // ...
+ components: {
+ 'my-component': () => import('./my-async-component')
+ }
+})
+```
+
+If you're a Browserify user that would like to use async components, its creator has unfortunately [made it clear](https://github.com/substack/node-browserify/issues/58#issuecomment-21978224) that async loading "is not something that Browserify will ever support." Officially, at least. The Browserify community has found [some workarounds](https://github.com/vuejs/v2.vuejs.org/issues/620), which may be helpful for existing and complex applications. For all other scenarios, we recommend using Webpack for built-in, first-class async support.
+
+### Handling Loading State
+
+> New in 2.3.0+
+
+The async component factory can also return an object of the following format:
+
+``` js
+const AsyncComponent = () => ({
+ // The component to load (should be a Promise)
+ component: import('./MyComponent.vue'),
+ // A component to use while the async component is loading
+ loading: LoadingComponent,
+ // A component to use if the load fails
+ error: ErrorComponent,
+ // Delay before showing the loading component. Default: 200ms.
+ delay: 200,
+ // The error component will be displayed if a timeout is
+ // provided and exceeded. Default: Infinity.
+ timeout: 3000
+})
+```
+
+> Note that you must use [Vue Router](https://github.com/vuejs/vue-router) 2.4.0+ if you wish to use the above syntax for route components.
diff --git a/src/v2/guide/components-edge-cases.md b/src/v2/guide/components-edge-cases.md
new file mode 100644
index 0000000000..ce67f1b0e5
--- /dev/null
+++ b/src/v2/guide/components-edge-cases.md
@@ -0,0 +1,385 @@
+---
+title: Handling Edge Cases
+type: guide
+order: 106
+---
+
+> This page assumes you've already read the [Components Basics](components.html). Read that first if you are new to components.
+
+All the features on this page document the handling of edge cases, meaning unusual situations that sometimes require bending Vue's rules a little. Note however, that they all have disadvantages or situations where they could be dangerous. These are noted in each case, so keep them in mind when deciding to use each feature.
+
+## Element & Component Access
+
+In most cases, it's best to avoid reaching into other component instances or manually manipulating DOM elements. There are cases, however, when it can be appropriate.
+
+### Accessing the Root Instance
+
+In every subcomponent of a `new Vue` instance, this root instance can be accessed with the `$root` property. For example, in this root instance:
+
+```js
+// The root Vue instance
+new Vue({
+ data: {
+ foo: 1
+ },
+ computed: {
+ bar: function () { /* ... */ }
+ },
+ methods: {
+ baz: function () { /* ... */ }
+ }
+})
+```
+
+All subcomponents will now be able to access this instance and use it as a global store:
+
+```js
+// Get root data
+this.$root.foo
+
+// Set root data
+this.$root.foo = 2
+
+// Access root computed properties
+this.$root.bar
+
+// Call root methods
+this.$root.baz()
+```
+
+This can be convenient for demos or very small apps with a handful of components. However, the pattern does not scale well to medium or large-scale applications, so we strongly recommend using Vuex to manage state in most cases.
+
+### Accessing the Parent Component Instance
+
+Similar to `$root`, the `$parent` property can be used to access the parent instance from a child. This can be tempting to reach for as a lazy alternative to passing data with a prop.
+
+In most cases, reaching into the parent makes your application more difficult to debug and understand, especially if you mutate data in the parent. When looking at that component later, it will be very difficult to figure out where that mutation came from.
+
+There are cases however, particularly shared component libraries, when this _might_ be appropriate. For example, in abstract components that interact with JavaScript APIs instead of rendering HTML, like these hypothetical Google Maps components:
+
+```html
+
+
+
+```
+
+The `` component might define a `map` property that all subcomponents need access to. In this case `` might want to access that map with something like `this.$parent.getMap`, in order to add a set of markers to it. You can see this pattern [in action here](https://codesandbox.io/s/github/vuejs/v2.vuejs.org/tree/master/src/v2/examples/vue-20-accessing-parent-component-instance).
+
+Keep in mind, however, that components built with this pattern are still inherently fragile. For example, imagine we add a new `` component and when `` appears within that, it should only render markers that fall within that region:
+
+```html
+
+
+
+
+
+```
+
+Then inside `` you might find yourself reaching for a hack like this:
+
+```js
+var map = this.$parent.map || this.$parent.$parent.map
+```
+
+This has quickly gotten out of hand. That's why to provide context information to descendant components arbitrarily deep, we instead recommend [dependency injection](#Dependency-Injection).
+
+### Accessing Child Component Instances & Child Elements
+
+Despite the existence of props and events, sometimes you might still need to directly access a child component in JavaScript. To achieve this you can assign a reference ID to the child component using the `ref` attribute. For example:
+
+```html
+
+```
+
+Now in the component where you've defined this `ref`, you can use:
+
+```js
+this.$refs.usernameInput
+```
+
+to access the `` instance. This may be useful when you want to, for example, programmatically focus this input from a parent. In that case, the `` component may similarly use a `ref` to provide access to specific elements inside it, such as:
+
+```html
+
+```
+
+And even define methods for use by the parent:
+
+```js
+methods: {
+ // Used to focus the input from the parent
+ focus: function () {
+ this.$refs.input.focus()
+ }
+}
+```
+
+Thus allowing the parent component to focus the input inside `` with:
+
+```js
+this.$refs.usernameInput.focus()
+```
+
+When `ref` is used together with `v-for`, the ref you get will be an array containing the child components mirroring the data source.
+
+$refs are only populated after the component has been rendered, and they are not reactive. It is only meant as an escape hatch for direct child manipulation - you should avoid accessing $refs from within templates or computed properties.
+
+### Dependency Injection
+
+Earlier, when we described [Accessing the Parent Component Instance](#Accessing-the-Parent-Component-Instance), we showed an example like this:
+
+```html
+
+
+
+
+
+```
+
+In this component, all descendants of `` needed access to a `getMap` method, in order to know which map to interact with. Unfortunately, using the `$parent` property didn't scale well to more deeply nested components. That's where dependency injection can be useful, using two new instance options: `provide` and `inject`.
+
+The `provide` options allows us to specify the data/methods we want to **provide** to descendant components. In this case, that's the `getMap` method inside ``:
+
+```js
+provide: function () {
+ return {
+ getMap: this.getMap
+ }
+}
+```
+
+Then in any descendants, we can use the `inject` option to receive specific properties we'd like to add to that instance:
+
+```js
+inject: ['getMap']
+```
+
+You can see the [full example here](https://codesandbox.io/s/github/vuejs/v2.vuejs.org/tree/master/src/v2/examples/vue-20-dependency-injection). The advantage over using `$parent` is that we can access `getMap` in _any_ descendant component, without exposing the entire instance of ``. This allows us to more safely keep developing that component, without fear that we might change/remove something that a child component is relying on. The interface between these components remains clearly defined, just as with `props`.
+
+In fact, you can think of dependency injection as sort of "long-range props", except:
+
+* ancestor components don't need to know which descendants use the properties it provides
+* descendant components don't need to know where injected properties are coming from
+
+However, there are downsides to dependency injection. It couples components in your application to the way they're currently organized, making refactoring more difficult. Provided properties are also not reactive. This is by design, because using them to create a central data store scales just as poorly as using $root for the same purpose. If the properties you want to share are specific to your app, rather than generic, or if you ever want to update provided data inside ancestors, then that's a good sign that you probably need a real state management solution like Vuex instead.
+
+Learn more about dependency injection in [the API doc](/v2/api/#provide-inject).
+
+## Programmatic Event Listeners
+
+So far, you've seen uses of `$emit`, listened to with `v-on`, but Vue instances also offer other methods in its events interface. We can:
+
+- Listen for an event with `$on(eventName, eventHandler)`
+- Listen for an event only once with `$once(eventName, eventHandler)`
+- Stop listening for an event with `$off(eventName, eventHandler)`
+
+You normally won't have to use these, but they're available for cases when you need to manually listen for events on a component instance. They can also be useful as a code organization tool. For example, you may often see this pattern for integrating a 3rd-party library:
+
+```js
+// Attach the datepicker to an input once
+// it's mounted to the DOM.
+mounted: function () {
+ // Pikaday is a 3rd-party datepicker library
+ this.picker = new Pikaday({
+ field: this.$refs.input,
+ format: 'YYYY-MM-DD'
+ })
+},
+// Right before the component is destroyed,
+// also destroy the datepicker.
+beforeDestroy: function () {
+ this.picker.destroy()
+}
+```
+
+This has two potential issues:
+
+- It requires saving the `picker` to the component instance, when it's possible that only lifecycle hooks need access to it. This isn't terrible, but it could be considered clutter.
+- Our setup code is kept separate from our cleanup code, making it more difficult to programmatically clean up anything we set up.
+
+You could resolve both issues with a programmatic listener:
+
+```js
+mounted: function () {
+ var picker = new Pikaday({
+ field: this.$refs.input,
+ format: 'YYYY-MM-DD'
+ })
+
+ this.$once('hook:beforeDestroy', function () {
+ picker.destroy()
+ })
+}
+```
+
+Using this strategy, we could even use Pikaday with several input elements, with each new instance automatically cleaning up after itself:
+
+```js
+mounted: function () {
+ this.attachDatepicker('startDateInput')
+ this.attachDatepicker('endDateInput')
+},
+methods: {
+ attachDatepicker: function (refName) {
+ var picker = new Pikaday({
+ field: this.$refs[refName],
+ format: 'YYYY-MM-DD'
+ })
+
+ this.$once('hook:beforeDestroy', function () {
+ picker.destroy()
+ })
+ }
+}
+```
+
+See [this example](https://codesandbox.io/s/github/vuejs/v2.vuejs.org/tree/master/src/v2/examples/vue-20-programmatic-event-listeners) for the full code. Note, however, that if you find yourself having to do a lot of setup and cleanup within a single component, the best solution will usually be to create more modular components. In this case, we'd recommend creating a reusable `` component.
+
+To learn more about programmatic listeners, check out the API for [Events Instance Methods](/v2/api/#Instance-Methods-Events).
+
+Note that Vue's event system is different from the browser's EventTarget API . Though they work similarly, $emit, $on, and $off are not aliases for dispatchEvent, addEventListener, and removeEventListener.
+
+## Circular References
+
+### Recursive Components
+
+Components can recursively invoke themselves in their own template. However, they can only do so with the `name` option:
+
+``` js
+name: 'unique-name-of-my-component'
+```
+
+When you register a component globally using `Vue.component`, the global ID is automatically set as the component's `name` option.
+
+``` js
+Vue.component('unique-name-of-my-component', {
+ // ...
+})
+```
+
+If you're not careful, recursive components can also lead to infinite loops:
+
+``` js
+name: 'stack-overflow',
+template: '
'
+```
+
+A component like the above will result in a "max stack size exceeded" error, so make sure recursive invocation is conditional (i.e. uses a `v-if` that will eventually be `false`).
+
+### Circular References Between Components
+
+Let's say you're building a file directory tree, like in Finder or File Explorer. You might have a `tree-folder` component with this template:
+
+``` html
+
+ {{ folder.name }}
+
+
+```
+
+Then a `tree-folder-contents` component with this template:
+
+``` html
+
+
+
+ {{ child.name }}
+
+
+```
+
+When you look closely, you'll see that these components will actually be each other's descendant _and_ ancestor in the render tree - a paradox! When registering components globally with `Vue.component`, this paradox is resolved for you automatically. If that's you, you can stop reading here.
+
+However, if you're requiring/importing components using a __module system__, e.g. via Webpack or Browserify, you'll get an error:
+
+```
+Failed to mount component: template or render function not defined.
+```
+
+To explain what's happening, let's call our components A and B. The module system sees that it needs A, but first A needs B, but B needs A, but A needs B, etc. It's stuck in a loop, not knowing how to fully resolve either component without first resolving the other. To fix this, we need to give the module system a point at which it can say, "A needs B _eventually_, but there's no need to resolve B first."
+
+In our case, let's make that point the `tree-folder` component. We know the child that creates the paradox is the `tree-folder-contents` component, so we'll wait until the `beforeCreate` lifecycle hook to register it:
+
+``` js
+beforeCreate: function () {
+ this.$options.components.TreeFolderContents = require('./tree-folder-contents.vue').default
+}
+```
+
+Or alternatively, you could use Webpack's asynchronous `import` when you register the component locally:
+
+``` js
+components: {
+ TreeFolderContents: () => import('./tree-folder-contents.vue')
+}
+```
+
+Problem solved!
+
+## Alternate Template Definitions
+
+### Inline Templates
+
+When the `inline-template` special attribute is present on a child component, the component will use its inner content as its template, rather than treating it as distributed content. This allows more flexible template-authoring.
+
+``` html
+
+
+
These are compiled as the component's own template.
+
Not parent's transclusion content.
+
+
+```
+
+Your inline template needs to be defined inside the DOM element to which Vue is attached.
+
+However, inline-template makes the scope of your templates harder to reason about. As a best practice, prefer defining templates inside the component using the template option or in a <template> element in a .vue file.
+
+### X-Templates
+
+Another way to define templates is inside of a script element with the type `text/x-template`, then referencing the template by an id. For example:
+
+``` html
+
+```
+
+``` js
+Vue.component('hello-world', {
+ template: '#hello-world-template'
+})
+```
+
+Your x-template needs to be defined outside the DOM element to which Vue is attached.
+
+These can be useful for demos with large templates or in extremely small applications, but should otherwise be avoided, because they separate templates from the rest of the component definition.
+
+## Controlling Updates
+
+Thanks to Vue's Reactivity system, it always knows when to update (if you use it correctly). There are edge cases, however, when you might want to force an update, despite the fact that no reactive data has changed. Then there are other cases when you might want to prevent unnecessary updates.
+
+### Forcing an Update
+
+If you find yourself needing to force an update in Vue, in 99.99% of cases, you've made a mistake somewhere.
+
+You may not have accounted for change detection caveats [with arrays](/v2/guide/list.html#Caveats) or [objects](/v2/guide/list.html#Object-Change-Detection-Caveats), or you may be relying on state that isn't tracked by Vue's reactivity system, e.g. with `data`.
+
+However, if you've ruled out the above and find yourself in this extremely rare situation of having to manually force an update, you can do so with [`$forceUpdate`](../api/#vm-forceUpdate).
+
+### Cheap Static Components with `v-once`
+
+Rendering plain HTML elements is very fast in Vue, but sometimes you might have a component that contains **a lot** of static content. In these cases, you can ensure that it's only evaluated once and then cached by adding the `v-once` directive to the root element, like this:
+
+``` js
+Vue.component('terms-of-service', {
+ template: `
+
+
Terms of Service
+ ... a lot of static content ...
+
+ `
+})
+```
+
+Once again, try not to overuse this pattern. While convenient in those rare cases when you have to render a lot of static content, it's simply not necessary unless you actually notice slow rendering -- plus, it could cause a lot of confusion later. For example, imagine another developer who's not familiar with v-once or simply misses it in the template. They might spend hours trying to figure out why the template isn't updating correctly.
diff --git a/src/v2/guide/components-props.md b/src/v2/guide/components-props.md
new file mode 100644
index 0000000000..1f274c595a
--- /dev/null
+++ b/src/v2/guide/components-props.md
@@ -0,0 +1,361 @@
+---
+title: Props
+type: guide
+order: 102
+---
+
+
+
+> This page assumes you've already read the [Components Basics](components.html). Read that first if you are new to components.
+
+
+
+## Prop Casing (camelCase vs kebab-case)
+
+HTML attribute names are case-insensitive, so browsers will interpret any uppercase characters as lowercase. That means when you're using in-DOM templates, camelCased prop names need to use their kebab-cased (hyphen-delimited) equivalents:
+
+``` js
+Vue.component('blog-post', {
+ // camelCase in JavaScript
+ props: ['postTitle'],
+ template: '{{ postTitle }} '
+})
+```
+
+``` html
+
+
+```
+
+Again, if you're using string templates, this limitation does not apply.
+
+## Prop Types
+
+So far, we've only seen props listed as an array of strings:
+
+```js
+props: ['title', 'likes', 'isPublished', 'commentIds', 'author']
+```
+
+Usually though, you'll want every prop to be a specific type of value. In these cases, you can list props as an object, where the properties' names and values contain the prop names and types, respectively:
+
+```js
+props: {
+ title: String,
+ likes: Number,
+ isPublished: Boolean,
+ commentIds: Array,
+ author: Object,
+ callback: Function,
+ contactsPromise: Promise // or any other constructor
+}
+```
+
+This not only documents your component, but will also warn users in the browser's JavaScript console if they pass the wrong type. You'll learn much more about [type checks and other prop validations](#Prop-Validation) further down this page.
+
+## Passing Static or Dynamic Props
+
+So far, you've seen props passed a static value, like in:
+
+```html
+
+```
+
+You've also seen props assigned dynamically with `v-bind`, such as in:
+
+```html
+
+
+
+
+
+```
+
+In the two examples above, we happen to pass string values, but _any_ type of value can actually be passed to a prop.
+
+### Passing a Number
+
+```html
+
+
+
+
+
+
+```
+
+### Passing a Boolean
+
+```html
+
+
+
+
+
+
+
+
+
+```
+
+### Passing an Array
+
+```html
+
+
+
+
+
+
+```
+
+### Passing an Object
+
+```html
+
+
+
+
+
+
+```
+
+### Passing the Properties of an Object
+
+If you want to pass all the properties of an object as props, you can use `v-bind` without an argument (`v-bind` instead of `v-bind:prop-name`). For example, given a `post` object:
+
+``` js
+post: {
+ id: 1,
+ title: 'My Journey with Vue'
+}
+```
+
+The following template:
+
+``` html
+
+```
+
+Will be equivalent to:
+
+``` html
+
+```
+
+## One-Way Data Flow
+
+All props form a **one-way-down binding** between the child property and the parent one: when the parent property updates, it will flow down to the child, but not the other way around. This prevents child components from accidentally mutating the parent's state, which can make your app's data flow harder to understand.
+
+In addition, every time the parent component is updated, all props in the child component will be refreshed with the latest value. This means you should **not** attempt to mutate a prop inside a child component. If you do, Vue will warn you in the console.
+
+There are usually two cases where it's tempting to mutate a prop:
+
+1. **The prop is used to pass in an initial value; the child component wants to use it as a local data property afterwards.** In this case, it's best to define a local data property that uses the prop as its initial value:
+
+ ``` js
+ props: ['initialCounter'],
+ data: function () {
+ return {
+ counter: this.initialCounter
+ }
+ }
+ ```
+
+2. **The prop is passed in as a raw value that needs to be transformed.** In this case, it's best to define a computed property using the prop's value:
+
+ ``` js
+ props: ['size'],
+ computed: {
+ normalizedSize: function () {
+ return this.size.trim().toLowerCase()
+ }
+ }
+ ```
+
+Note that objects and arrays in JavaScript are passed by reference, so if the prop is an array or object, mutating the object or array itself inside the child component **will** affect parent state.
+
+## Prop Validation
+
+Components can specify requirements for their props, such as the types you've already seen. If a requirement isn't met, Vue will warn you in the browser's JavaScript console. This is especially useful when developing a component that's intended to be used by others.
+
+To specify prop validations, you can provide an object with validation requirements to the value of `props`, instead of an array of strings. For example:
+
+``` js
+Vue.component('my-component', {
+ props: {
+ // Basic type check (`null` and `undefined` values will pass any type validation)
+ propA: Number,
+ // Multiple possible types
+ propB: [String, Number],
+ // Required string
+ propC: {
+ type: String,
+ required: true
+ },
+ // Number with a default value
+ propD: {
+ type: Number,
+ default: 100
+ },
+ // Object with a default value
+ propE: {
+ type: Object,
+ // Object or array defaults must be returned from
+ // a factory function
+ default: function () {
+ return { message: 'hello' }
+ }
+ },
+ // Custom validator function
+ propF: {
+ validator: function (value) {
+ // The value must match one of these strings
+ return ['success', 'warning', 'danger'].includes(value)
+ }
+ }
+ }
+})
+```
+
+When prop validation fails, Vue will produce a console warning (if using the development build).
+
+Note that props are validated **before** a component instance is created, so instance properties (e.g. `data`, `computed`, etc) will not be available inside `default` or `validator` functions.
+
+### Type Checks
+
+The `type` can be one of the following native constructors:
+
+- String
+- Number
+- Boolean
+- Array
+- Object
+- Date
+- Function
+- Symbol
+
+In addition, `type` can also be a custom constructor function and the assertion will be made with an `instanceof` check. For example, given the following constructor function exists:
+
+```js
+function Person (firstName, lastName) {
+ this.firstName = firstName
+ this.lastName = lastName
+}
+```
+
+You could use:
+
+```js
+Vue.component('blog-post', {
+ props: {
+ author: Person
+ }
+})
+```
+
+to validate that the value of the `author` prop was created with `new Person`.
+
+## Non-Prop Attributes
+
+A non-prop attribute is an attribute that is passed to a component, but does not have a corresponding prop defined.
+
+While explicitly defined props are preferred for passing information to a child component, authors of component libraries can't always foresee the contexts in which their components might be used. That's why components can accept arbitrary attributes, which are added to the component's root element.
+
+For example, imagine we're using a 3rd-party `bootstrap-date-input` component with a Bootstrap plugin that requires a `data-date-picker` attribute on the `input`. We can add this attribute to our component instance:
+
+``` html
+
+```
+
+And the `data-date-picker="activated"` attribute will automatically be added to the root element of `bootstrap-date-input`.
+
+### Replacing/Merging with Existing Attributes
+
+Imagine this is the template for `bootstrap-date-input`:
+
+``` html
+
+```
+
+To specify a theme for our date picker plugin, we might need to add a specific class, like this:
+
+``` html
+
+```
+
+In this case, two different values for `class` are defined:
+
+- `form-control`, which is set by the component in its template
+- `date-picker-theme-dark`, which is passed to the component by its parent
+
+For most attributes, the value provided to the component will replace the value set by the component. So for example, passing `type="text"` will replace `type="date"` and probably break it! Fortunately, the `class` and `style` attributes are a little smarter, so both values are merged, making the final value: `form-control date-picker-theme-dark`.
+
+### Disabling Attribute Inheritance
+
+If you do **not** want the root element of a component to inherit attributes, you can set `inheritAttrs: false` in the component's options. For example:
+
+```js
+Vue.component('my-component', {
+ inheritAttrs: false,
+ // ...
+})
+```
+
+This can be especially useful in combination with the `$attrs` instance property, which contains the attribute names and values passed to a component, such as:
+
+```js
+{
+ required: true,
+ placeholder: 'Enter your username'
+}
+```
+
+With `inheritAttrs: false` and `$attrs`, you can manually decide which element you want to forward attributes to, which is often desirable for [base components](../style-guide/#Base-component-names-strongly-recommended):
+
+```js
+Vue.component('base-input', {
+ inheritAttrs: false,
+ props: ['label', 'value'],
+ template: `
+
+ {{ label }}
+
+
+ `
+})
+```
+
+Note that `inheritAttrs: false` option does **not** affect `style` and `class` bindings.
+
+This pattern allows you to use base components more like raw HTML elements, without having to care about which element is actually at its root:
+
+```html
+
+```
diff --git a/src/v2/guide/components-registration.md b/src/v2/guide/components-registration.md
new file mode 100644
index 0000000000..9d4c027fc3
--- /dev/null
+++ b/src/v2/guide/components-registration.md
@@ -0,0 +1,232 @@
+---
+title: Component Registration
+type: guide
+order: 101
+---
+
+> This page assumes you've already read the [Components Basics](components.html). Read that first if you are new to components.
+
+
+
+## Component Names
+
+When registering a component, it will always be given a name. For example, in the global registration we've seen so far:
+
+```js
+Vue.component('my-component-name', { /* ... */ })
+```
+
+The component's name is the first argument of `Vue.component`.
+
+The name you give a component may depend on where you intend to use it. When using a component directly in the DOM (as opposed to in a string template or [single-file component](single-file-components.html)), we strongly recommend following the [W3C rules](https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name) for custom tag names (all-lowercase, must contain a hyphen). This helps you avoid conflicts with current and future HTML elements.
+
+You can see other recommendations for component names in the [Style Guide](../style-guide/#Base-component-names-strongly-recommended).
+
+### Name Casing
+
+You have two options when defining component names:
+
+#### With kebab-case
+
+```js
+Vue.component('my-component-name', { /* ... */ })
+```
+
+When defining a component with kebab-case, you must also use kebab-case when referencing its custom element, such as in ``.
+
+#### With PascalCase
+
+```js
+Vue.component('MyComponentName', { /* ... */ })
+```
+
+When defining a component with PascalCase, you can use either case when referencing its custom element. That means both `` and `` are acceptable. Note, however, that only kebab-case names are valid directly in the DOM (i.e. non-string templates).
+
+## Global Registration
+
+So far, we've only created components using `Vue.component`:
+
+```js
+Vue.component('my-component-name', {
+ // ... options ...
+})
+```
+
+These components are **globally registered**. That means they can be used in the template of any root Vue instance (`new Vue`) created after registration. For example:
+
+```js
+Vue.component('component-a', { /* ... */ })
+Vue.component('component-b', { /* ... */ })
+Vue.component('component-c', { /* ... */ })
+
+new Vue({ el: '#app' })
+```
+
+```html
+
+
+
+
+
+```
+
+This even applies to all subcomponents, meaning all three of these components will also be available _inside each other_.
+
+## Local Registration
+
+Global registration often isn't ideal. For example, if you're using a build system like Webpack, globally registering all components means that even if you stop using a component, it could still be included in your final build. This unnecessarily increases the amount of JavaScript your users have to download.
+
+In these cases, you can define your components as plain JavaScript objects:
+
+```js
+var ComponentA = { /* ... */ }
+var ComponentB = { /* ... */ }
+var ComponentC = { /* ... */ }
+```
+
+Then define the components you'd like to use in a `components` option:
+
+```js
+new Vue({
+ el: '#app',
+ components: {
+ 'component-a': ComponentA,
+ 'component-b': ComponentB
+ }
+})
+```
+
+For each property in the `components` object, the key will be the name of the custom element, while the value will contain the options object for the component.
+
+Note that **locally registered components are _not_ also available in subcomponents**. For example, if you wanted `ComponentA` to be available in `ComponentB`, you'd have to use:
+
+```js
+var ComponentA = { /* ... */ }
+
+var ComponentB = {
+ components: {
+ 'component-a': ComponentA
+ },
+ // ...
+}
+```
+
+Or if you're using ES2015 modules, such as through Babel and Webpack, that might look more like:
+
+```js
+import ComponentA from './ComponentA.vue'
+
+export default {
+ components: {
+ ComponentA
+ },
+ // ...
+}
+```
+
+Note that in ES2015+, placing a variable name like `ComponentA` inside an object is shorthand for `ComponentA: ComponentA`, meaning the name of the variable is both:
+
+- the custom element name to use in the template, and
+- the name of the variable containing the component options
+
+## Module Systems
+
+If you're not using a module system with `import`/`require`, you can probably skip this section for now. If you are, we have some special instructions and tips just for you.
+
+### Local Registration in a Module System
+
+If you're still here, then it's likely you're using a module system, such as with Babel and Webpack. In these cases, we recommend creating a `components` directory, with each component in its own file.
+
+Then you'll need to import each component you'd like to use, before you locally register it. For example, in a hypothetical `ComponentB.js` or `ComponentB.vue` file:
+
+```js
+import ComponentA from './ComponentA'
+import ComponentC from './ComponentC'
+
+export default {
+ components: {
+ ComponentA,
+ ComponentC
+ },
+ // ...
+}
+```
+
+Now both `ComponentA` and `ComponentC` can be used inside `ComponentB`'s template.
+
+### Automatic Global Registration of Base Components
+
+Many of your components will be relatively generic, possibly only wrapping an element like an input or a button. We sometimes refer to these as [base components](../style-guide/#Base-component-names-strongly-recommended) and they tend to be used very frequently across your components.
+
+The result is that many components may include long lists of base components:
+
+```js
+import BaseButton from './BaseButton.vue'
+import BaseIcon from './BaseIcon.vue'
+import BaseInput from './BaseInput.vue'
+
+export default {
+ components: {
+ BaseButton,
+ BaseIcon,
+ BaseInput
+ }
+}
+```
+
+Just to support relatively little markup in a template:
+
+```html
+
+
+
+
+```
+
+Fortunately, if you're using Webpack (or [Vue CLI 3+](https://github.com/vuejs/vue-cli), which uses Webpack internally), you can use `require.context` to globally register only these very common base components. Here's an example of the code you might use to globally import base components in your app's entry file (e.g. `src/main.js`):
+
+```js
+import Vue from 'vue'
+import upperFirst from 'lodash/upperFirst'
+import camelCase from 'lodash/camelCase'
+
+const requireComponent = require.context(
+ // The relative path of the components folder
+ './components',
+ // Whether or not to look in subfolders
+ false,
+ // The regular expression used to match base component filenames
+ /Base[A-Z]\w+\.(vue|js)$/
+)
+
+requireComponent.keys().forEach(fileName => {
+ // Get component config
+ const componentConfig = requireComponent(fileName)
+
+ // Get PascalCase name of component
+ const componentName = upperFirst(
+ camelCase(
+ // Gets the file name regardless of folder depth
+ fileName
+ .split('/')
+ .pop()
+ .replace(/\.\w+$/, '')
+ )
+ )
+
+
+ // Register component globally
+ Vue.component(
+ componentName,
+ // Look for the component options on `.default`, which will
+ // exist if the component was exported with `export default`,
+ // otherwise fall back to module's root.
+ componentConfig.default || componentConfig
+ )
+})
+```
+
+Remember that **global registration must take place before the root Vue instance is created (with `new Vue`)**. [Here's an example](https://github.com/chrisvfritz/vue-enterprise-boilerplate/blob/master/src/components/_globals.js) of this pattern in a real project context.
diff --git a/src/v2/guide/components-slots.md b/src/v2/guide/components-slots.md
new file mode 100644
index 0000000000..6ba9bc2710
--- /dev/null
+++ b/src/v2/guide/components-slots.md
@@ -0,0 +1,560 @@
+---
+title: Slots
+type: guide
+order: 104
+---
+
+> This page assumes you've already read the [Components Basics](components.html). Read that first if you are new to components.
+
+> In 2.6.0, we introduced a new unified syntax (the `v-slot` directive) for named and scoped slots. It replaces the `slot` and `slot-scope` attributes, which are now deprecated, but have _not_ been removed and are still documented [here](#Deprecated-Syntax). The rationale for introducing the new syntax is described in this [RFC](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0001-new-slot-syntax.md).
+
+## Slot Content
+
+Vue implements a content distribution API inspired by the [Web Components spec draft](https://github.com/w3c/webcomponents/blob/gh-pages/proposals/Slots-Proposal.md), using the `` element to serve as distribution outlets for content.
+
+This allows you to compose components like this:
+
+``` html
+
+ Your Profile
+
+```
+
+Then in the template for ``, you might have:
+
+``` html
+
+
+
+```
+
+When the component renders, ` ` will be replaced by "Your Profile". Slots can contain any template code, including HTML:
+
+``` html
+
+
+
+ Your Profile
+
+```
+
+Or even other components:
+
+``` html
+
+
+
+ Your Profile
+
+```
+
+If ``'s template did **not** contain a `` element, any content provided between its opening and closing tag would be discarded.
+
+## Compilation Scope
+
+When you want to use data inside a slot, such as in:
+
+``` html
+
+ Logged in as {{ user.name }}
+
+```
+
+That slot has access to the same instance properties (i.e. the same "scope") as the rest of the template. The slot does **not** have access to ``'s scope. For example, trying to access `url` would not work:
+
+``` html
+
+ Clicking here will send you to: {{ url }}
+
+
+```
+
+As a rule, remember that:
+
+> Everything in the parent template is compiled in parent scope; everything in the child template is compiled in the child scope.
+
+## Fallback Content
+
+There are cases when it's useful to specify fallback (i.e. default) content for a slot, to be rendered only when no content is provided. For example, in a `` component:
+
+```html
+
+
+
+```
+
+We might want the text "Submit" to be rendered inside the `` most of the time. To make "Submit" the fallback content, we can place it in between the `` tags:
+
+```html
+
+ Submit
+
+```
+
+Now when we use `` in a parent component, providing no content for the slot:
+
+```html
+
+```
+
+will render the fallback content, "Submit":
+
+```html
+
+ Submit
+
+```
+
+But if we provide content:
+
+```html
+
+ Save
+
+```
+
+Then the provided content will be rendered instead:
+
+```html
+
+ Save
+
+```
+
+## Named Slots
+
+> Updated in 2.6.0+. [See here](#Deprecated-Syntax) for the deprecated syntax using the `slot` attribute.
+
+There are times when it's useful to have multiple slots. For example, in a `` component with the following template:
+
+``` html
+
+
+
+
+
+
+
+```
+
+For these cases, the `` element has a special attribute, `name`, which can be used to define additional slots:
+
+``` html
+
+
+
+
+
+
+
+```
+
+A `` outlet without `name` implicitly has the name "default".
+
+To provide content to named slots, we can use the `v-slot` directive on a ``, providing the name of the slot as `v-slot`'s argument:
+
+```html
+
+
+ Here might be a page title
+
+
+ A paragraph for the main content.
+ And another one.
+
+
+ Here's some contact info
+
+
+```
+
+Now everything inside the `` elements will be passed to the corresponding slots. Any content not wrapped in a `` using `v-slot` is assumed to be for the default slot.
+
+However, you can still wrap default slot content in a `` if you wish to be explicit:
+
+```html
+
+
+ Here might be a page title
+
+
+
+ A paragraph for the main content.
+ And another one.
+
+
+
+ Here's some contact info
+
+
+```
+
+Either way, the rendered HTML will be:
+
+``` html
+
+
+ Here might be a page title
+
+
+ A paragraph for the main content.
+ And another one.
+
+
+ Here's some contact info
+
+
+```
+
+Note that **`v-slot` can only be added to a ``** (with [one exception](#Abbreviated-Syntax-for-Lone-Default-Slots)), unlike the deprecated [`slot` attribute](#Deprecated-Syntax).
+
+## Scoped Slots
+
+> Updated in 2.6.0+. [See here](#Deprecated-Syntax) for the deprecated syntax using the `slot-scope` attribute.
+
+Sometimes, it's useful for slot content to have access to data only available in the child component. For example, imagine a `` component with the following template:
+
+```html
+
+ {{ user.lastName }}
+
+```
+
+We might want to replace this fallback content to display the user's first name, instead of last, like this:
+
+``` html
+
+ {{ user.firstName }}
+
+```
+
+That won't work, however, because only the `` component has access to the `user` and the content we're providing is rendered in the parent.
+
+To make `user` available to the slot content in the parent, we can bind `user` as an attribute to the `` element:
+
+``` html
+
+
+ {{ user.lastName }}
+
+
+```
+
+Attributes bound to a `` element are called **slot props**. Now, in the parent scope, we can use `v-slot` with a value to define a name for the slot props we've been provided:
+
+``` html
+
+
+ {{ slotProps.user.firstName }}
+
+
+```
+
+In this example, we've chosen to name the object containing all our slot props `slotProps`, but you can use any name you like.
+
+### Abbreviated Syntax for Lone Default Slots
+
+In cases like above, when _only_ the default slot is provided content, the component's tags can be used as the slot's template. This allows us to use `v-slot` directly on the component:
+
+``` html
+
+ {{ slotProps.user.firstName }}
+
+```
+
+This can be shortened even further. Just as non-specified content is assumed to be for the default slot, `v-slot` without an argument is assumed to refer to the default slot:
+
+``` html
+
+ {{ slotProps.user.firstName }}
+
+```
+
+Note that the abbreviated syntax for default slot **cannot** be mixed with named slots, as it would lead to scope ambiguity:
+
+``` html
+
+
+ {{ slotProps.user.firstName }}
+
+ slotProps is NOT available here
+
+
+```
+
+Whenever there are multiple slots, use the full `` based syntax for _all_ slots:
+
+``` html
+
+
+ {{ slotProps.user.firstName }}
+
+
+
+ ...
+
+
+```
+
+### Destructuring Slot Props
+
+Internally, scoped slots work by wrapping your slot content in a function passed a single argument:
+
+```js
+function (slotProps) {
+ // ... slot content ...
+}
+```
+
+That means the value of `v-slot` can actually accept any valid JavaScript expression that can appear in the argument position of a function definition. So in supported environments ([single-file components](single-file-components.html) or [modern browsers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Browser_compatibility)), you can also use [ES2015 destructuring](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring) to pull out specific slot props, like so:
+
+``` html
+
+ {{ user.firstName }}
+
+```
+
+This can make the template much cleaner, especially when the slot provides many props. It also opens other possibilities, such as renaming props, e.g. `user` to `person`:
+
+``` html
+
+ {{ person.firstName }}
+
+```
+
+You can even define fallbacks, to be used in case a slot prop is undefined:
+
+``` html
+
+ {{ user.firstName }}
+
+```
+
+## Dynamic Slot Names
+
+> New in 2.6.0+
+
+[Dynamic directive arguments](syntax.html#Dynamic-Arguments) also work on `v-slot`, allowing the definition of dynamic slot names:
+
+``` html
+
+
+ ...
+
+
+```
+
+## Named Slots Shorthand
+
+> New in 2.6.0+
+
+Similar to `v-on` and `v-bind`, `v-slot` also has a shorthand, replacing everything before the argument (`v-slot:`) with the special symbol `#`. For example, `v-slot:header` can be rewritten as `#header`:
+
+```html
+
+
+ Here might be a page title
+
+
+ A paragraph for the main content.
+ And another one.
+
+
+ Here's some contact info
+
+
+```
+
+However, just as with other directives, the shorthand is only available when an argument is provided. That means the following syntax is invalid:
+
+``` html
+
+
+ {{ user.firstName }}
+
+```
+
+Instead, you must always specify the name of the slot if you wish to use the shorthand:
+
+``` html
+
+ {{ user.firstName }}
+
+```
+
+## Other Examples
+
+**Slot props allow us to turn slots into reusable templates that can render different content based on input props.** This is most useful when you are designing a reusable component that encapsulates data logic while allowing the consuming parent component to customize part of its layout.
+
+For example, we are implementing a `` component that contains the layout and filtering logic for a list:
+
+```html
+
+```
+
+Instead of hard-coding the content for each todo, we can let the parent component take control by making every todo a slot, then binding `todo` as a slot prop:
+
+```html
+
+
+
+
+
+ {{ todo.text }}
+
+
+
+```
+
+Now when we use the `` component, we can optionally define an alternative `` for todo items, but with access to data from the child:
+
+```html
+
+
+ ✓
+ {{ todo.text }}
+
+
+```
+
+However, even this barely scratches the surface of what scoped slots are capable of. For real-life, powerful examples of scoped slot usage, we recommend browsing libraries such as [Vue Virtual Scroller](https://github.com/Akryum/vue-virtual-scroller), [Vue Promised](https://github.com/posva/vue-promised), and [Portal Vue](https://github.com/LinusBorg/portal-vue).
+
+## Deprecated Syntax
+
+> The `v-slot` directive was introduced in Vue 2.6.0, offering an improved, alternative API to the still-supported `slot` and `slot-scope` attributes. The full rationale for introducing `v-slot` is described in this [RFC](https://github.com/vuejs/rfcs/blob/master/active-rfcs/0001-new-slot-syntax.md). The `slot` and `slot-scope` attributes will continue to be supported in all future 2.x releases, but are officially deprecated and will eventually be removed in Vue 3.
+
+### Named Slots with the `slot` Attribute
+
+> Deprecated in 2.6.0+. See [here](#Named-Slots) for the new, recommended syntax.
+
+To pass content to named slots from the parent, use the special `slot` attribute on `` (using the `` component described [here](#Named-Slots) as example):
+
+```html
+
+
+ Here might be a page title
+
+
+ A paragraph for the main content.
+ And another one.
+
+
+ Here's some contact info
+
+
+```
+
+Or, the `slot` attribute can also be used directly on a normal element:
+
+``` html
+
+ Here might be a page title
+
+ A paragraph for the main content.
+ And another one.
+
+ Here's some contact info
+
+```
+
+There can still be one unnamed slot, which is the **default slot** that serves as a catch-all for any unmatched content. In both examples above, the rendered HTML would be:
+
+``` html
+
+
+ Here might be a page title
+
+
+ A paragraph for the main content.
+ And another one.
+
+
+ Here's some contact info
+
+
+```
+
+### Scoped Slots with the `slot-scope` Attribute
+
+> Deprecated in 2.6.0+. See [here](#Scoped-Slots) for the new, recommended syntax.
+
+To receive props passed to a slot, the parent component can use `` with the `slot-scope` attribute (using the `` described [here](#Scoped-Slots) as example):
+
+``` html
+
+
+ {{ slotProps.msg }}
+
+
+```
+
+Here, `slot-scope` declares the received props object as the `slotProps` variable, and makes it available inside the `` scope. You can name `slotProps` anything you like similar to naming function arguments in JavaScript.
+
+Here `slot="default"` can be omitted as it is implied:
+
+``` html
+
+
+ {{ slotProps.msg }}
+
+
+```
+
+The `slot-scope` attribute can also be used directly on a non-`` element (including components):
+
+``` html
+
+
+ {{ slotProps.msg }}
+
+
+```
+
+The value of `slot-scope` can accept any valid JavaScript expression that can appear in the argument position of a function definition. This means in supported environments ([single-file components](single-file-components.html) or [modern browsers](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Browser_compatibility)) you can also use [ES2015 destructuring](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Destructuring_assignment#Object_destructuring) in the expression, like so:
+
+``` html
+
+
+ {{ msg }}
+
+
+```
+
+Using the `` described [here](#Other-Examples) as an example, here's the equivalent usage using `slot-scope`:
+
+``` html
+
+
+ ✓
+ {{ todo.text }}
+
+
+```
diff --git a/src/v2/guide/components.md b/src/v2/guide/components.md
index 8db71229a4..6a49d9a6fe 100644
--- a/src/v2/guide/components.md
+++ b/src/v2/guide/components.md
@@ -1,1481 +1,638 @@
---
-title: Components
+title: Components Basics
type: guide
order: 11
---
-## What are Components?
+
-Components are one of the most powerful features of Vue. They help you extend basic HTML elements to encapsulate reusable code. At a high level, components are custom elements that Vue's compiler attaches behavior to. In some cases, they may also appear as a native HTML element extended with the special `is` attribute.
+## Base Example
-All Vue components are also Vue instances, and so accept the same options object (except for a few root-specific options) and provide the same lifecycle hooks.
-
-## Using Components
-
-### Global Registration
-
-We've learned in the previous sections that we can create a new Vue instance with:
-
-``` js
-new Vue({
- el: '#some-element',
- // options
-})
-```
-
-To register a global component, you can use `Vue.component(tagName, options)`. For example:
-
-``` js
-Vue.component('my-component', {
- // options
-})
-```
-
-Note that Vue does not enforce the [W3C rules](https://www.w3.org/TR/custom-elements/#concepts) for custom tag names (all-lowercase, must contain a hyphen) though following this convention is considered good practice.
-
-Once registered, a component can be used in an instance's template as a custom element, ` `. Make sure the component is registered **before** you instantiate the root Vue instance. Here's the full example:
-
-``` html
-
-
-
-```
-
-``` js
-// register
-Vue.component('my-component', {
- template: 'A custom component!
'
-})
-
-// create a root instance
-new Vue({
- el: '#example'
-})
-```
-
-Which will render:
-
-``` html
-
-```
-
-{% raw %}
-
-
-
-
-{% endraw %}
-
-### Local Registration
-
-You don't have to register every component globally. You can make a component available only in the scope of another instance/component by registering it with the `components` instance option:
-
-``` js
-var Child = {
- template: 'A custom component!
'
-}
-
-new Vue({
- // ...
- components: {
- // will only be available in parent's template
- 'my-component': Child
- }
-})
-```
-
-The same encapsulation applies for other registerable Vue features, such as directives.
-
-### DOM Template Parsing Caveats
-
-When using the DOM as your template (e.g. using the `el` option to mount an element with existing content), you will be subject to some restrictions that are inherent to how HTML works, because Vue can only retrieve the template content **after** the browser has parsed and normalized it. Most notably, some elements such as ``, ``, `` and `` have restrictions on what elements can appear inside them, and some elements such as `` can only appear inside certain other elements.
-
-This will lead to issues when using custom components with elements that have such restrictions, for example:
-
-``` html
-
-```
-
-The custom component `` will be hoisted out as invalid content, thus causing errors in the eventual rendered output. A workaround is to use the `is` special attribute:
-
-``` html
-
-```
-
-**It should be noted that these limitations do not apply if you are using string templates from one of the following sources**:
-
-- `
-{% endraw %}
-
-Since all three component instances share the same `data` object, incrementing one counter increments them all! Ouch. Let's fix this by instead returning a fresh data object:
-
-``` js
-data: function () {
- return {
- counter: 0
- }
-}
-```
-
-Now all our counters each have their own internal state:
-
-{% raw %}
-
-
-
-
-
-
-{% endraw %}
-
-### Composing Components
-
-Components are meant to be used together, most commonly in parent-child relationships: component A may use component B in its own template. They inevitably need to communicate to one another: the parent may need to pass data down to the child, and the child may need to inform the parent of something that happened in the child. However, it is also very important to keep the parent and the child as decoupled as possible via a clearly-defined interface. This ensures each component's code can be written and reasoned about in relative isolation, thus making them more maintainable and potentially easier to reuse.
-
-In Vue, the parent-child component relationship can be summarized as **props down, events up**. The parent passes data down to the child via **props**, and the child sends messages to the parent via **events**. Let's see how they work next.
-
-
-
-
-
-## Props
-
-### Passing Data with Props
-
-Every component instance has its own **isolated scope**. This means you cannot (and should not) directly reference parent data in a child component's template. Data can be passed down to child components using **props**.
-
-A prop is a custom attribute for passing information from parent components. A child component needs to explicitly declare the props it expects to receive using the [`props` option](../api/#props):
-
-``` js
-Vue.component('child', {
- // declare the props
- props: ['message'],
- // like data, the prop can be used inside templates and
- // is also made available in the vm as this.message
- template: '{{ message }} '
-})
-```
-
-Then we can pass a plain string to it like so:
-
-``` html
-
-```
-
-Result:
-
-{% raw %}
-
-
-
-
-{% endraw %}
-
-### camelCase vs. kebab-case
-
-HTML attributes are case-insensitive, so when using non-string templates, camelCased prop names need to use their kebab-case (hyphen-delimited) equivalents:
-
-``` js
-Vue.component('child', {
- // camelCase in JavaScript
- props: ['myMessage'],
- template: '{{ myMessage }} '
-})
-```
-
-``` html
-
-
-```
-
-Again, if you're using string templates, then this limitation does not apply.
-
-### Dynamic Props
-
-Similar to binding a normal attribute to an expression, we can also use `v-bind` for dynamically binding props to data on the parent. Whenever the data is updated in the parent, it will also flow down to the child:
-
-``` html
-
-
-
-
-
-```
-
-``` js
-new Vue({
- el: '#prop-example-2',
- data: {
- parentMsg: 'Message from parent'
- }
-})
-```
-
-You can also use the shorthand syntax for `v-bind`:
-
-``` html
-
-```
-
-Result:
-
-{% raw %}
-
-
-
-
-
-
-{% endraw %}
-
-If you want to pass all the properties in an object as props, you can use `v-bind` without an argument (`v-bind` instead of `v-bind:prop-name`). For example, given a `todo` object:
-
-``` js
-todo: {
- text: 'Learn Vue',
- isComplete: false
-}
-```
-
-Then:
-
-``` html
-
-```
-
-Will be equivalent to:
-
-``` html
-
-```
-
-### Literal vs. Dynamic
-
-A common mistake beginners tend to make is attempting to pass down a number using the literal syntax:
-
-``` html
-
-
-```
-
-However, since this is a literal prop, its value is passed down as a plain string `"1"` instead of an actual number. If we want to pass down an actual JavaScript number, we need to use `v-bind` so that its value is evaluated as a JavaScript expression:
-
-``` html
-
-
-```
-
-### One-Way Data Flow
-
-All props form a **one-way-down** binding between the child property and the parent one: when the parent property updates, it will flow down to the child, but not the other way around. This prevents child components from accidentally mutating the parent's state, which can make your app's data flow harder to understand.
-
-In addition, every time the parent component is updated, all props in the child component will be refreshed with the latest value. This means you should **not** attempt to mutate a prop inside a child component. If you do, Vue will warn you in the console.
-
-There are usually two cases where it's tempting to mutate a prop:
-
-1. The prop is used to pass in an initial value; the child component wants to use it as a local data property afterwards.
-
-2. The prop is passed in as a raw value that needs to be transformed.
-
-The proper answer to these use cases are:
-
-1. Define a local data property that uses the prop's initial value as its initial value:
-
- ``` js
- props: ['initialCounter'],
- data: function () {
- return { counter: this.initialCounter }
- }
- ```
-
-2. Define a computed property that is computed from the prop's value:
-
- ``` js
- props: ['size'],
- computed: {
- normalizedSize: function () {
- return this.size.trim().toLowerCase()
- }
- }
- ```
-
-Note that objects and arrays in JavaScript are passed by reference, so if the prop is an array or object, mutating the object or array itself inside the child **will** affect parent state.
-
-### Prop Validation
-
-It is possible for a component to specify requirements for the props it is receiving. If a requirement is not met, Vue will emit warnings. This is especially useful when you are authoring a component that is intended to be used by others.
-
-Instead of defining the props as an array of strings, you can use an object with validation requirements:
-
-``` js
-Vue.component('example', {
- props: {
- // basic type check (`null` means accept any type)
- propA: Number,
- // multiple possible types
- propB: [String, Number],
- // a required string
- propC: {
- type: String,
- required: true
- },
- // a number with default value
- propD: {
- type: Number,
- default: 100
- },
- // object/array defaults should be returned from a
- // factory function
- propE: {
- type: Object,
- default: function () {
- return { message: 'hello' }
- }
- },
- // custom validator function
- propF: {
- validator: function (value) {
- return value > 10
- }
- }
- }
-})
-```
-
-The `type` can be one of the following native constructors:
-
-- String
-- Number
-- Boolean
-- Function
-- Object
-- Array
-- Symbol
-
-In addition, `type` can also be a custom constructor function and the assertion will be made with an `instanceof` check.
-
-When prop validation fails, Vue will produce a console warning (if using the development build). Note that props are validated __before__ a component instance is created, so within `default` or `validator` functions, instance properties such as from `data`, `computed`, or `methods` will not be available.
-
-## Non-Prop Attributes
-
-A non-prop attribute is an attribute that is passed to a component, but does not have a corresponding prop defined.
-
-While explicitly defined props are preferred for passing information to a child component, authors of component libraries can't always foresee the contexts in which their components might be used. That's why components can accept arbitrary attributes, which are added to the component's root element.
-
-For example, imagine we're using a 3rd-party `bs-date-input` component with a Bootstrap plugin that requires a `data-3d-date-picker` attribute on the `input`. We can add this attribute to our component instance:
-
-``` html
-
-```
-
-And the `data-3d-date-picker="true"` attribute will automatically be added to the root element of `bs-date-input`.
-
-### Replacing/Merging with Existing Attributes
-
-Imagine this is the template for `bs-date-input`:
-
-``` html
-
-```
-
-To specify a theme for our date picker plugin, we might need to add a specific class, like this:
-
-``` html
-
-```
-
-In this case, two different values for `class` are defined:
-
-- `form-control`, which is set by the component in its template
-- `date-picker-theme-dark`, which is passed to the component by its parent
-
-For most attributes, the value provided to the component will replace the value set by the component. So for example, passing `type="large"` will replace `type="date"` and probably break it! Fortunately, the `class` and `style` attributes are a little smarter, so both values are merged, making the final value: `form-control date-picker-theme-dark`.
-
-## Custom Events
-
-We have learned that the parent can pass data down to the child using props, but how do we communicate back to the parent when something happens? This is where Vue's custom event system comes in.
-
-### Using `v-on` with Custom Events
-
-Every Vue instance implements an [events interface](../api/#Instance-Methods-Events), which means it can:
-
-- Listen to an event using `$on(eventName)`
-- Trigger an event using `$emit(eventName, optionalPayload)`
-
-Note that Vue's event system is different from the browser's [EventTarget API](https://developer.mozilla.org/en-US/docs/Web/API/EventTarget). Though they work similarly, `$on` and `$emit` are __not__ aliases for `addEventListener` and `dispatchEvent`.
-
-In addition, a parent component can listen to the events emitted from a child component using `v-on` directly in the template where the child component is used.
-
-You cannot use `$on` to listen to events emitted by children. You must use `v-on` directly in the template, as in the example below.
-
-Here's an example:
-
-``` html
-
-```
+Here's an example of a Vue component:
``` js
+// Define a new component called button-counter
Vue.component('button-counter', {
- template: '{{ counter }} ',
- data: function () {
- return {
- counter: 0
- }
- },
- methods: {
- incrementCounter: function () {
- this.counter += 1
- this.$emit('increment')
- }
- },
-})
-
-new Vue({
- el: '#counter-event-example',
- data: {
- total: 0
- },
- methods: {
- incrementTotal: function () {
- this.total += 1
- }
- }
-})
-```
-
-{% raw %}
-
-
-{% endraw %}
-
-In this example, it's important to note that the child component is still completely decoupled from what happens outside of it. All it does is report information about its own activity, just in case a parent component might care.
-
-
-Here's an example on how to use payload data:
-
-``` html
-
-```
-
-``` js
-Vue.component('button-message', {
- template: `
-
- Send
-
`,
- data: function () {
- return {
- message: 'test message'
- }
- },
- methods: {
- handleSendMessage: function () {
- this.$emit('message', { message: this.message })
- }
- }
-})
-
-new Vue({
- el: '#message-event-example',
- data: {
- messages: []
- },
- methods: {
- handleMessage: function (payload) {
- this.messages.push(payload.message)
- }
- }
-})
-```
-
-{% raw %}
-
-
-{% endraw %}
-
-In this second example, it's important to note that the child component is still completely decoupled from what happens outside of it. All it does is report information about its own activity including a payload data into event emitter, just in case a parent component might care.
-
-### Binding Native Events to Components
-
-There may be times when you want to listen for a native event on the root element of a component. In these cases, you can use the `.native` modifier for `v-on`. For example:
-
-``` html
-
-```
-
-### `.sync` Modifier
-
-> 2.3.0+
-
-In some cases we may need "two-way binding" for a prop - in fact, in Vue 1.x this is exactly what the `.sync` modifier provided. When a child component mutates a prop that has `.sync`, the value change will be reflected in the parent. This is convenient, however it leads to maintenance issues in the long run because it breaks the one-way data flow assumption: the code that mutates child props are implicitly affecting parent state.
-
-This is why we removed the `.sync` modifier when 2.0 was released. However, we've found that there are indeed cases where it could be useful, especially when shipping reusable components. What we need to change is **making the code in the child that affects parent state more consistent and explicit.**
-
-In 2.3.0+ we re-introduced the `.sync` modifier for props, but this time it is only syntax sugar that automatically expands into an additional `v-on` listener:
-
-The following
-
-``` html
-
-```
-
-is expanded into:
-
-``` html
- bar = val">
-```
-
-For the child component to update `foo`'s value, it needs to explicitly emit an event instead of mutating the prop:
-
-``` js
-this.$emit('update:foo', newValue)
-```
-
-The `.sync` modifier can also be used with `v-bind` when using an object to set multiple properties at once:
-
-```html
-
-```
-
-This has the effect of adding `v-on` update listeners for both `foo` and `bar`.
-
-### Form Input Components using Custom Events
-
-Custom events can also be used to create custom inputs that work with `v-model`. Remember:
-
-``` html
-
-```
-
-is syntactic sugar for:
-
-``` html
-
-```
-
-When used with a component, it instead simplifies to:
-
-``` html
- { something = value }">
-
-```
-
-So for a component to work with `v-model`, it should (these can be configured in 2.2.0+):
-
-- accept a `value` prop
-- emit an `input` event with the new value
-
-Let's see it in action with a simple currency input:
-
-``` html
-
-```
-
-``` js
-Vue.component('currency-input', {
- template: '\
- \
- $\
- \
- \
- ',
- props: ['value'],
- methods: {
- // Instead of updating the value directly, this
- // method is used to format and place constraints
- // on the input's value
- updateValue: function (value) {
- var formattedValue = value
- // Remove whitespace on either side
- .trim()
- // Shorten to 2 decimal places
- .slice(
- 0,
- value.indexOf('.') === -1
- ? value.length
- : value.indexOf('.') + 3
- )
- // If the value was not already normalized,
- // manually override it to conform
- if (formattedValue !== value) {
- this.$refs.input.value = formattedValue
- }
- // Emit the number value through the input event
- this.$emit('input', Number(formattedValue))
- }
- }
-})
-```
-
-{% raw %}
-
-
-
-
-{% endraw %}
-
-The implementation above is pretty naive though. For example, users are allowed to enter multiple periods and even letters sometimes - yuck! So for those that want to see a non-trivial example, here's a more robust currency filter:
-
-
-
-### Customizing Component `v-model`
-
-> New in 2.2.0+
-
-By default, `v-model` on a component uses `value` as the prop and `input` as the event, but some input types such as checkboxes and radio buttons may want to use the `value` prop for a different purpose. Using the `model` option can avoid the conflict in such cases:
-
-``` js
-Vue.component('my-checkbox', {
- model: {
- prop: 'checked',
- event: 'change'
- },
- props: {
- checked: Boolean,
- // this allows using the `value` prop for a different purpose
- value: String
+ count: 0
+ }
},
- // ...
+ template: 'You clicked me {{ count }} times. '
})
```
-``` html
-
-```
-
-The above will be equivalent to:
+Components are reusable Vue instances with a name: in this case, ``. We can use this component as a custom element inside a root Vue instance created with `new Vue`:
-``` html
- { foo = val }"
- value="some value">
-
+```html
+
+
+
```
-Note that you still have to declare the `checked` prop explicitly.
-
-### Non Parent-Child Communication
+{% codeblock lang:js %}
+new Vue({ el: '#components-demo' })
+{% endcodeblock %}
-Sometimes two components may need to communicate with one-another but they are not parent/child to each other. In simple scenarios, you can use an empty Vue instance as a central event bus:
-
-``` js
-var bus = new Vue()
-```
-``` js
-// in component A's method
-bus.$emit('id-selected', 1)
-```
-``` js
-// in component B's created hook
-bus.$on('id-selected', function (id) {
- // ...
+{% raw %}
+
+
+
+
+{% endraw %}
-In more complex cases, you should consider employing a dedicated [state-management pattern](state-management.html).
+Since components are reusable Vue instances, they accept the same options as `new Vue`, such as `data`, `computed`, `watch`, `methods`, and lifecycle hooks. The only exceptions are a few root-specific options like `el`.
-## Content Distribution with Slots
+## Reusing Components
-When using components, it is often desired to compose them like this:
+Components can be reused as many times as you want:
-``` html
-
-
-
-
+```html
+
+
+
+
+
```
-There are two things to note here:
-
-1. The `` component does not know what content it will receive. It is decided by the component using ``.
-
-2. The `` component very likely has its own template.
+{% raw %}
+
+
+
+
+
+
+{% endraw %}
-To make the composition work, we need a way to interweave the parent "content" and the component's own template. This is a process called **content distribution** (or "transclusion" if you are familiar with Angular). Vue.js implements a content distribution API that is modeled after the current [Web Components spec draft](https://github.com/w3c/webcomponents/blob/gh-pages/proposals/Slots-Proposal.md), using the special `` element to serve as distribution outlets for the original content.
+Notice that when clicking on the buttons, each one maintains its own, separate `count`. That's because each time you use a component, a new **instance** of it is created.
-### Compilation Scope
+### `data` Must Be a Function
-Before we dig into the API, let's first clarify which scope the contents are compiled in. Imagine a template like this:
+When we defined the `` component, you may have noticed that `data` wasn't directly provided an object, like this:
-``` html
-
- {{ message }}
-
+```js
+data: {
+ count: 0
+}
```
-Should the `message` be bound to the parent's data or the child data? The answer is the parent. A simple rule of thumb for component scope is:
-
-> Everything in the parent template is compiled in parent scope; everything in the child template is compiled in child scope.
+Instead, **a component's `data` option must be a function**, so that each instance can maintain an independent copy of the returned data object:
-A common mistake is trying to bind a directive to a child property/method in the parent template:
-
-``` html
-
-
+```js
+data: function () {
+ return {
+ count: 0
+ }
+}
```
-Assuming `someChildProperty` is a property on the child component, the example above would not work. The parent's template is not aware of the state of a child component.
+If Vue didn't have this rule, clicking on one button would affect the data of _all other instances_, like below:
-If you need to bind child-scope directives on a component root node, you should do so in the child component's own template:
-
-``` js
-Vue.component('child-component', {
- // this does work, because we are in the right scope
- template: 'Child
',
+{% raw %}
+
+
+
+
+
+
+{% endraw %}
-Similarly, distributed content will be compiled in the parent scope.
+## Organizing Components
-### Single Slot
+It's common for an app to be organized into a tree of nested components:
-Parent content will be **discarded** unless the child component template contains at least one `` outlet. When there is only one slot with no attributes, the entire content fragment will be inserted at its position in the DOM, replacing the slot itself.
+
-Anything originally inside the `` tags is considered **fallback content**. Fallback content is compiled in the child scope and will only be displayed if the hosting element is empty and has no content to be inserted.
+For example, you might have components for a header, sidebar, and content area, each typically containing other components for navigation links, blog posts, etc.
-Suppose we have a component called `my-component` with the following template:
+To use these components in templates, they must be registered so that Vue knows about them. There are two types of component registration: **global** and **local**. So far, we've only registered components globally, using `Vue.component`:
-``` html
-
-
I'm the child title
-
- This will only be displayed if there is no content
- to be distributed.
-
-
+```js
+Vue.component('my-component-name', {
+ // ... options ...
+})
```
-And a parent that uses the component:
+Globally registered components can be used in the template of any root Vue instance (`new Vue`) created afterwards -- and even inside all subcomponents of that Vue instance's component tree.
-``` html
-
-
I'm the parent title
-
- This is some original content
- This is some more original content
-
-
-```
+That's all you need to know about registration for now, but once you've finished reading this page and feel comfortable with its content, we recommend coming back later to read the full guide on [Component Registration](components-registration.html).
-The rendered result will be:
+## Passing Data to Child Components with Props
-``` html
-
-
I'm the parent title
-
-
I'm the child title
-
This is some original content
-
This is some more original content
-
-
-```
+Earlier, we mentioned creating a component for blog posts. The problem is, that component won't be useful unless you can pass data to it, such as the title and content of the specific post we want to display. That's where props come in.
-### Named Slots
+Props are custom attributes you can register on a component. When a value is passed to a prop attribute, it becomes a property on that component instance. To pass a title to our blog post component, we can include it in the list of props this component accepts, using a `props` option:
-`` elements have a special attribute, `name`, which can be used to further customize how content should be distributed. You can have multiple slots with different names. A named slot will match any element that has a corresponding `slot` attribute in the content fragment.
+```js
+Vue.component('blog-post', {
+ props: ['title'],
+ template: '{{ title }} '
+})
+```
-There can still be one unnamed slot, which is the **default slot** that serves as a catch-all outlet for any unmatched content. If there is no default slot, unmatched content will be discarded.
+A component can have as many props as you'd like and by default, any value can be passed to any prop. In the template above, you'll see that we can access this value on the component instance, just like with `data`.
-For example, suppose we have an `app-layout` component with the following template:
+Once a prop is registered, you can pass data to it as a custom attribute, like this:
-``` html
-
-
-
-
-
-
-
+```html
+
+
+
```
-Parent markup:
-
-``` html
-
- Here might be a page title
+{% raw %}
+
+
+
+
+
+
+{% endraw %}
- A paragraph for the main content.
- And another one.
+In a typical app, however, you'll likely have an array of posts in `data`:
- Here's some contact info
-
+```js
+new Vue({
+ el: '#blog-post-demo',
+ data: {
+ posts: [
+ { id: 1, title: 'My journey with Vue' },
+ { id: 2, title: 'Blogging with Vue' },
+ { id: 3, title: 'Why Vue is so fun' }
+ ]
+ }
+})
```
-The rendered result will be:
+Then want to render a component for each one:
-``` html
-
-
- Here might be a page title
-
-
- A paragraph for the main content.
- And another one.
-
-
- Here's some contact info
-
-
+```html
+
```
-The content distribution API is a very useful mechanism when designing components that are meant to be composed together.
-
-### Scoped Slots
+Above, you'll see that we can use `v-bind` to dynamically pass props. This is especially useful when you don't know the exact content you're going to render ahead of time, like when [fetching posts from an API](https://codesandbox.io/s/github/vuejs/v2.vuejs.org/tree/master/src/v2/examples/vue-20-component-blog-post-example).
-> New in 2.1.0+
+That's all you need to know about props for now, but once you've finished reading this page and feel comfortable with its content, we recommend coming back later to read the full guide on [Props](components-props.html).
-A scoped slot is a special type of slot that functions as a reusable template (that can be passed data to) instead of already-rendered-elements.
+## A Single Root Element
-In a child component, pass data into a slot as if you are passing props to a component:
+When building out a `` component, your template will eventually contain more than just the title:
-``` html
-
-
-
+```html
+{{ title }}
```
-In the parent, a `` element with a special attribute `slot-scope` must exist, indicating that it is a template for a scoped slot. The value of `slot-scope` will be used as the name of a temporary variable that holds the props object passed from the child:
+At the very least, you'll want to include the post's content:
-``` html
-
-
-
- hello from parent
- {{ props.text }}
-
-
-
+```html
+{{ title }}
+
```
-If we render the above, the output will be:
+If you try this in your template, however, Vue will show an error, explaining that **every component must have a single root element**. You can fix this error by wrapping the template in a parent element, such as:
-``` html
-
-
- hello from parent
- hello from child
-
+```html
+
```
-> In 2.5.0+, `slot-scope` is no longer limited to `
` and can be used on any element or component.
-
-A more typical use case for scoped slots would be a list component that allows the component consumer to customize how each item in the list should be rendered:
+As our component grows, it's likely we'll not only need the title and content of a post, but also the published date, comments, and more. Defining a prop for each related piece of information could become very annoying:
-``` html
-
-
-
- {{ props.text }}
-
-
+```html
+
```
-And the template for the list component:
+So this might be a good time to refactor the `` component to accept a single `post` prop instead:
-``` html
-
+```html
+
```
-#### Destructuring
-
-`slot-scope`'s value is in fact a valid JavaScript expression that can appear in the argument position of a function signature. This means in supported environments (in single-file components or in modern browsers) you can also use ES2015 destructuring in the expression:
-
-``` html
-
- {{ text }}
-
+```js
+Vue.component('blog-post', {
+ props: ['post'],
+ template: `
+
+ `
+})
```
-## Dynamic Components
-
-You can use the same mount point and dynamically switch between multiple components using the reserved `` element and dynamically bind to its `is` attribute:
+The above example and some future ones use JavaScript's [template literal](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals) to make multi-line templates more readable. These are not supported by Internet Explorer (IE), so if you must support IE and are not transpiling (e.g. with Babel or TypeScript), use [newline escapes](https://css-tricks.com/snippets/javascript/multiline-string-variables-in-javascript/) instead.
-``` js
-var vm = new Vue({
- el: '#example',
- data: {
- currentView: 'home'
- },
- components: {
- home: { /* ... */ },
- posts: { /* ... */ },
- archive: { /* ... */ }
- }
-})
-```
+Now, whenever a new property is added to `post` objects, it will automatically be available inside ``.
-``` html
-
-
-
-```
+## Listening to Child Components Events
-If you prefer, you can also bind directly to component objects:
+As we develop our `` component, some features may require communicating back up to the parent. For example, we may decide to include an accessibility feature to enlarge the text of blog posts, while leaving the rest of the page its default size:
-``` js
-var Home = {
- template: 'Welcome home!
'
-}
+In the parent, we can support this feature by adding a `postFontSize` data property:
-var vm = new Vue({
- el: '#example',
+```js
+new Vue({
+ el: '#blog-posts-events-demo',
data: {
- currentView: Home
+ posts: [/* ... */],
+ postFontSize: 1
}
})
```
-### `keep-alive`
-
-If you want to keep the switched-out components in memory so that you can preserve their state or avoid re-rendering, you can wrap a dynamic component in a `` element:
+Which can be used in the template to control the font size of all blog posts:
-``` html
-
-
-
-
-
+```html
+
```
-Check out more details on `` in the [API reference](../api/#keep-alive).
-
-## Misc
-
-### Authoring Reusable Components
+Now let's add a button to enlarge the text right before the content of every post:
-When authoring components, it's good to keep in mind whether you intend to reuse it somewhere else later. It's OK for one-off components to be tightly coupled, but reusable components should define a clean public interface and make no assumptions about the context it's used in.
-
-The API for a Vue component comes in three parts - props, events, and slots:
-
-- **Props** allow the external environment to pass data into the component
-
-- **Events** allow the component to trigger side effects in the external environment
-
-- **Slots** allow the external environment to compose the component with extra content.
+```js
+Vue.component('blog-post', {
+ props: ['post'],
+ template: `
+
+
{{ post.title }}
+
+ Enlarge text
+
+
+
+ `
+})
+```
-With the dedicated shorthand syntaxes for `v-bind` and `v-on`, the intents can be clearly and succinctly conveyed in the template:
+The problem is, this button doesn't do anything:
-``` html
-
-
- Hello!
-
+```html
+
+ Enlarge text
+
```
-### Child Component Refs
-
-Despite the existence of props and events, sometimes you might still need to directly access a child component in JavaScript. To achieve this you have to assign a reference ID to the child component using `ref`. For example:
+When we click on the button, we need to communicate to the parent that it should enlarge the text of all posts. Fortunately, Vue instances provide a custom events system to solve this problem. The parent can choose to listen to any event on the child component instance with `v-on`, just as we would with a native DOM event:
-``` html
-
-
-
+```html
+
```
-``` js
-var parent = new Vue({ el: '#parent' })
-// access child component instance
-var child = parent.$refs.profile
+Then the child component can emit an event on itself by calling the built-in [**`$emit`** method](../api/#vm-emit), passing the name of the event:
+
+```html
+
+ Enlarge text
+
```
-When `ref` is used together with `v-for`, the ref you get will be an array containing the child components mirroring the data source.
+Thanks to the `v-on:enlarge-text="postFontSize += 0.1"` listener, the parent will receive the event and update `postFontSize` value.
-`$refs` are only populated after the component has been rendered, and it is not reactive. It is only meant as an escape hatch for direct child manipulation - you should avoid using `$refs` in templates or computed properties.
+{% raw %}
+
+
+{% endraw %}
-### Async Components
+### Emitting a Value With an Event
-In large applications, we may need to divide the app into smaller chunks and only load a component from the server when it's actually needed. To make that easier, Vue allows you to define your component as a factory function that asynchronously resolves your component definition. Vue will only trigger the factory function when the component actually needs to be rendered and will cache the result for future re-renders. For example:
+It's sometimes useful to emit a specific value with an event. For example, we may want the `` component to be in charge of how much to enlarge the text by. In those cases, we can use `$emit`'s 2nd parameter to provide this value:
-``` js
-Vue.component('async-example', function (resolve, reject) {
- setTimeout(function () {
- // Pass the component definition to the resolve callback
- resolve({
- template: 'I am async!
'
- })
- }, 1000)
-})
+```html
+
+ Enlarge text
+
```
-The factory function receives a `resolve` callback, which should be called when you have retrieved your component definition from the server. You can also call `reject(reason)` to indicate the load has failed. The `setTimeout` here is for demonstration; how to retrieve the component is up to you. One recommended approach is to use async components together with [Webpack's code-splitting feature](https://webpack.js.org/guides/code-splitting/):
+Then when we listen to the event in the parent, we can access the emitted event's value with `$event`:
-``` js
-Vue.component('async-webpack-example', function (resolve) {
- // This special require syntax will instruct Webpack to
- // automatically split your built code into bundles which
- // are loaded over Ajax requests.
- require(['./my-async-component'], resolve)
-})
+```html
+
```
-You can also return a `Promise` in the factory function, so with Webpack 2 + ES2015 syntax you can do:
+Or, if the event handler is a method:
-``` js
-Vue.component(
- 'async-webpack-example',
- // The `import` function returns a `Promise`.
- () => import('./my-async-component')
-)
+```html
+
```
-When using [local registration](components.html#Local-Registration), you can also directly provide a function that returns a `Promise`:
+Then the value will be passed as the first parameter of that method:
-``` js
-new Vue({
- // ...
- components: {
- 'my-component': () => import('./my-async-component')
+```js
+methods: {
+ onEnlargeText: function (enlargeAmount) {
+ this.postFontSize += enlargeAmount
}
-})
+}
```
-If you're a Browserify user that would like to use async components, its creator has unfortunately [made it clear](https://github.com/substack/node-browserify/issues/58#issuecomment-21978224) that async loading "is not something that Browserify will ever support." Officially, at least. The Browserify community has found [some workarounds](https://github.com/vuejs/vuejs.org/issues/620), which may be helpful for existing and complex applications. For all other scenarios, we recommend using Webpack for built-in, first-class async support.
-
-### Advanced Async Components
-
-> New in 2.3.0+
+### Using `v-model` on Components
-Starting in 2.3.0+ the async component factory can also return an object of the following format:
+Custom events can also be used to create custom inputs that work with `v-model`. Remember that:
-``` js
-const AsyncComp = () => ({
- // The component to load. Should be a Promise
- component: import('./MyComp.vue'),
- // A component to use while the async component is loading
- loading: LoadingComp,
- // A component to use if the load fails
- error: ErrorComp,
- // Delay before showing the loading component. Default: 200ms.
- delay: 200,
- // The error component will be displayed if a timeout is
- // provided and exceeded. Default: Infinity.
- timeout: 3000
-})
+```html
+
```
-Note that when used as a route component in `vue-router`, these properties will be ignored because async components are resolved upfront before the route navigation happens. You also need to use `vue-router` 2.4.0+ if you wish to use the above syntax for route components.
-
-### Component Naming Conventions
+does the same thing as:
-When registering components (or props), you can use kebab-case, camelCase, or PascalCase.
-
-``` js
-// in a component definition
-components: {
- // register using kebab-case
- 'kebab-cased-component': { /* ... */ },
- // register using camelCase
- 'camelCasedComponent': { /* ... */ },
- // register using PascalCase
- 'PascalCasedComponent': { /* ... */ }
-}
+```html
+
```
-Within HTML templates though, you have to use the kebab-case equivalents:
+When used on a component, `v-model` instead does this:
``` html
-
-
-
-
+
```
-When using _string_ templates however, we're not bound by HTML's case-insensitive restrictions. That means even in the template, you can reference your components using:
-
-- kebab-case
-- camelCase or kebab-case if the component has been defined using camelCase
-- kebab-case, camelCase or PascalCase if the component has been defined using PascalCase
+For this to actually work though, the ` ` inside the component must:
-``` js
-components: {
- 'kebab-cased-component': { /* ... */ },
- camelCasedComponent: { /* ... */ },
- PascalCasedComponent: { /* ... */ }
-}
-```
-
-``` html
-
+- Bind the `value` attribute to a `value` prop
+- On `input`, emit its own custom `input` event with the new value
-
-
+Here's that in action:
-
-
-
+```js
+Vue.component('custom-input', {
+ props: ['value'],
+ template: `
+
+ `
+})
```
-This means that the PascalCase is the most universal _declaration convention_ and kebab-case is the most universal _usage convention_.
-
-If your component isn't passed content via `slot` elements, you can even make it self-closing with a `/` after the name:
+Now `v-model` should work perfectly with this component:
-``` html
-
+```html
+
```
-Again, this _only_ works within string templates, as self-closing custom elements are not valid HTML and your browser's native parser will not understand them.
+That's all you need to know about custom component events for now, but once you've finished reading this page and feel comfortable with its content, we recommend coming back later to read the full guide on [Custom Events](components-custom-events.html).
-### Recursive Components
+## Content Distribution with Slots
-Components can recursively invoke themselves in their own template. However, they can only do so with the `name` option:
+Just like with HTML elements, it's often useful to be able to pass content to a component, like this:
-``` js
-name: 'unique-name-of-my-component'
+``` html
+
+ Something bad happened.
+
```
-When you register a component globally using `Vue.component`, the global ID is automatically set as the component's `name` option.
+Which might render something like:
-``` js
-Vue.component('unique-name-of-my-component', {
- // ...
+{% raw %}
+
+
+ Something bad happened.
+
+
+
+
+{% endraw %}
-If you're not careful, recursive components can also lead to infinite loops:
+Fortunately, this task is made very simple by Vue's custom `` element:
-``` js
-name: 'stack-overflow',
-template: '
'
+```js
+Vue.component('alert-box', {
+ template: `
+
+ Error!
+
+
+ `
+})
```
-A component like the above will result in a "max stack size exceeded" error, so make sure recursive invocation is conditional (i.e. uses a `v-if` that will eventually be `false`).
+As you'll see above, we just add the slot where we want it to go -- and that's it. We're done!
-### Circular References Between Components
+That's all you need to know about slots for now, but once you've finished reading this page and feel comfortable with its content, we recommend coming back later to read the full guide on [Slots](components-slots.html).
-Let's say you're building a file directory tree, like in Finder or File Explorer. You might have a `tree-folder` component with this template:
+## Dynamic Components
-``` html
-
- {{ folder.name }}
-
-
-```
+Sometimes, it's useful to dynamically switch between components, like in a tabbed interface:
+
+{% raw %}
+
+
+ {{ tab }}
+
+
+
+
+
+{% endraw %}
-Then a `tree-folder-contents` component with this template:
+The above is made possible by Vue's `` element with the `is` special attribute:
-``` html
-
-
-
- {{ child.name }}
-
-
+```html
+
+
```
-When you look closely, you'll see that these components will actually be each other's descendent _and_ ancestor in the render tree - a paradox! When registering components globally with `Vue.component`, this paradox is resolved for you automatically. If that's you, you can stop reading here.
+In the example above, `currentTabComponent` can contain either:
-However, if you're requiring/importing components using a __module system__, e.g. via Webpack or Browserify, you'll get an error:
+- the name of a registered component, or
+- a component's options object
-```
-Failed to mount component: template or render function not defined.
-```
+See [this example](https://codesandbox.io/s/github/vuejs/v2.vuejs.org/tree/master/src/v2/examples/vue-20-dynamic-components) to experiment with the full code, or [this version](https://codesandbox.io/s/github/vuejs/v2.vuejs.org/tree/master/src/v2/examples/vue-20-dynamic-components-with-binding) for an example binding to a component's options object, instead of its registered name.
-To explain what's happening, let's call our components A and B. The module system sees that it needs A, but first A needs B, but B needs A, but A needs B, etc, etc. It's stuck in a loop, not knowing how to fully resolve either component without first resolving the other. To fix this, we need to give the module system a point at which it can say, "A needs B _eventually_, but there's no need to resolve B first."
+Keep in mind that this attribute can be used with regular HTML elements, however they will be treated as components, which means all attributes **will be bound as DOM attributes**. For some properties such as `value` to work as you would expect, you will need to bind them using the [`.prop` modifier](../api/#v-bind).
-In our case, let's make that point the `tree-folder` component. We know the child that creates the paradox is the `tree-folder-contents` component, so we'll wait until the `beforeCreate` lifecycle hook to register it:
-
-``` js
-beforeCreate: function () {
- this.$options.components.TreeFolderContents = require('./tree-folder-contents.vue').default
-}
-```
+That's all you need to know about dynamic components for now, but once you've finished reading this page and feel comfortable with its content, we recommend coming back later to read the full guide on [Dynamic & Async Components](components-dynamic-async.html).
-Problem solved!
+## DOM Template Parsing Caveats
-### Inline Templates
+Some HTML elements, such as ``, ``, `` and `` have restrictions on what elements can appear inside them, and some elements such as ``, ``, and `` can only appear inside certain other elements.
-When the `inline-template` special attribute is present on a child component, the component will use its inner content as its template, rather than treating it as distributed content. This allows more flexible template-authoring.
+This will lead to issues when using components with elements that have such restrictions. For example:
``` html
-
-
-
These are compiled as the component's own template.
-
Not parent's transclusion content.
-
-
+
```
-However, `inline-template` makes the scope of your templates harder to reason about. As a best practice, prefer defining templates inside the component using the `template` option or in a `template` element in a `.vue` file.
-
-### X-Templates
-
-Another way to define templates is inside of a script element with the type `text/x-template`, then referencing the template by an id. For example:
+The custom component `` will be hoisted out as invalid content, causing errors in the eventual rendered output. Fortunately, the `is` special attribute offers a workaround:
``` html
-
-```
-
-``` js
-Vue.component('hello-world', {
- template: '#hello-world-template'
-})
+
```
-These can be useful for demos with large templates or in extremely small applications, but should otherwise be avoided, because they separate templates from the rest of the component definition.
+It should be noted that **this limitation does _not_ apply if you are using string templates from one of the following sources**:
-### Cheap Static Components with `v-once`
+- String templates (e.g. `template: '...'`)
+- [Single-file (`.vue`) components](single-file-components.html)
+- [`
+
## Computed Properties
+
+
In-template expressions are very convenient, but they are meant for simple operations. Putting too much logic in your templates can make them bloated and hard to maintain. For example:
``` html
@@ -94,7 +102,7 @@ methods: {
}
```
-Instead of a computed property, we can define the same function as a method instead. For the end result, the two approaches are indeed exactly the same. However, the difference is that **computed properties are cached based on their dependencies.** A computed property will only re-evaluate when some of its dependencies have changed. This means as long as `message` has not changed, multiple access to the `reversedMessage` computed property will immediately return the previously computed result without having to run the function again.
+Instead of a computed property, we can define the same function as a method. For the end result, the two approaches are indeed exactly the same. However, the difference is that **computed properties are cached based on their reactive dependencies.** A computed property will only re-evaluate when some of its reactive dependencies have changed. This means as long as `message` has not changed, multiple access to the `reversedMessage` computed property will immediately return the previously computed result without having to run the function again.
This also means the following computed property will never update, because `Date.now()` is not a reactive dependency:
@@ -201,7 +209,7 @@ For example:
-
+
@@ -273,28 +279,28 @@ var watchExampleVM = new Vue({
watch: {
question: function (newQuestion, oldQuestion) {
this.answer = 'Waiting for you to stop typing...'
- this.getAnswer()
+ this.debouncedGetAnswer()
}
},
+ created: function () {
+ this.debouncedGetAnswer = _.debounce(this.getAnswer, 500)
+ },
methods: {
- getAnswer: _.debounce(
- function () {
- var vm = this
- if (this.question.indexOf('?') === -1) {
- vm.answer = 'Questions usually contain a question mark. ;-)'
- return
- }
- vm.answer = 'Thinking...'
- axios.get('https://yesno.wtf/api')
- .then(function (response) {
- vm.answer = _.capitalize(response.data.answer)
- })
- .catch(function (error) {
- vm.answer = 'Error! Could not reach the API. ' + error
- })
- },
- 500
- )
+ getAnswer: function () {
+ if (this.question.indexOf('?') === -1) {
+ this.answer = 'Questions usually contain a question mark. ;-)'
+ return
+ }
+ this.answer = 'Thinking...'
+ var vm = this
+ axios.get('https://yesno.wtf/api')
+ .then(function (response) {
+ vm.answer = _.capitalize(response.data.answer)
+ })
+ .catch(function (error) {
+ vm.answer = 'Error! Could not reach the API. ' + error
+ })
+ }
}
})
diff --git a/src/v2/guide/conditional.md b/src/v2/guide/conditional.md
index 18d9459f87..d667ae5d73 100644
--- a/src/v2/guide/conditional.md
+++ b/src/v2/guide/conditional.md
@@ -4,28 +4,21 @@ type: guide
order: 7
---
-## `v-if`
-
-In string templates, for example Handlebars, we would write a conditional block like this:
+
-``` html
-
-{{#if ok}}
- Yes
-{{/if}}
-```
+## `v-if`
-In Vue, we use the `v-if` directive to achieve the same:
+The directive `v-if` is used to conditionally render a block. The block will only be rendered if the directive's expression returns a truthy value.
``` html
-Yes
+Vue is awesome!
```
It is also possible to add an "else block" with `v-else`:
``` html
-Yes
-No
+Vue is awesome!
+Oh no 😢
```
### Conditional Groups with `v-if` on ``
@@ -196,4 +189,6 @@ Generally speaking, `v-if` has higher toggle costs while `v-show` has higher ini
## `v-if` with `v-for`
-When used together with `v-if`, `v-for` has a higher priority than `v-if`. See the list rendering guide for details.
+Using `v-if` and `v-for` together is **not recommended**. See the [style guide](/v2/style-guide/#Avoid-v-if-with-v-for-essential) for further information.
+
+When used together with `v-if`, `v-for` has a higher priority than `v-if`. See the list rendering guide for details.
diff --git a/src/v2/guide/custom-directive.md b/src/v2/guide/custom-directive.md
index f950449d82..5951f163f9 100644
--- a/src/v2/guide/custom-directive.md
+++ b/src/v2/guide/custom-directive.md
@@ -6,6 +6,8 @@ order: 302
## Intro
+
+
In addition to the default set of directives shipped in core (`v-model` and `v-show`), Vue also allows you to register your own custom directives. Note that in Vue 2.0, the primary form of code reuse and abstraction is components - however there may be cases where you need some low-level DOM access on plain elements, and this is where custom directives would still be useful. An example would be focusing on an input element, like this one:
{% raw %}
@@ -66,6 +68,8 @@ A directive definition object can provide several hook functions (all optional):
- `update`: called after the containing component's VNode has updated, __but possibly before its children have updated__. The directive's value may or may not have changed, but you can skip unnecessary updates by comparing the binding's current and old values (see below on hook arguments).
+We'll cover VNodes in more detail [later](./render-function.html#The-Virtual-DOM), when we discuss [render functions](./render-function.html).
+
- `componentUpdated`: called after the containing component's VNode __and the VNodes of its children__ have updated.
- `unbind`: called only once, when the directive is unbound from the element.
@@ -141,6 +145,72 @@ new Vue({
{% endraw %}
+### Dynamic Directive Arguments
+
+Directive arguments can be dynamic. For example, in `v-mydirective:[argument]="value"`, the `argument` can be updated based on data properties in our component instance! This makes our custom directives flexible for use throughout our application.
+
+Let's say you want to make a custom directive that allows you to pin elements to your page using fixed positioning. We could create a custom directive where the value updates the vertical positioning in pixels, like this:
+
+```html
+
+
Scroll down the page
+
Stick me 200px from the top of the page
+
+```
+
+```js
+Vue.directive('pin', {
+ bind: function (el, binding, vnode) {
+ el.style.position = 'fixed'
+ el.style.top = binding.value + 'px'
+ }
+})
+
+new Vue({
+ el: '#baseexample'
+})
+```
+
+This would pin the element 200px from the top of the page. But what happens if we run into a scenario when we need to pin the element from the left, instead of the top? Here's where a dynamic argument that can be updated per component instance comes in very handy:
+
+
+```html
+
+
Scroll down inside this section ↓
+
I am pinned onto the page at 200px to the left.
+
+```
+
+```js
+Vue.directive('pin', {
+ bind: function (el, binding, vnode) {
+ el.style.position = 'fixed'
+ var s = (binding.arg == 'left' ? 'left' : 'top')
+ el.style[s] = binding.value + 'px'
+ }
+})
+
+new Vue({
+ el: '#dynamicexample',
+ data: function () {
+ return {
+ direction: 'left'
+ }
+ }
+})
+```
+
+Result:
+
+{% raw %}
+
+{% endraw %}
+
+Our custom directive is now flexible enough to support a few different use cases.
+
## Function Shorthand
In many cases, you may want the same behavior on `bind` and `update`, but don't care about the other hooks. For example:
diff --git a/src/v2/guide/deployment.md b/src/v2/guide/deployment.md
index e6dc44bdca..b863cf65ba 100644
--- a/src/v2/guide/deployment.md
+++ b/src/v2/guide/deployment.md
@@ -1,9 +1,11 @@
---
title: Production Deployment
type: guide
-order: 401
+order: 404
---
+> Most of the tips below are enabled by default if you are using [Vue CLI](https://cli.vuejs.org). This section is only relevant if you are using a custom build setup.
+
## Turn on Production Mode
During development, Vue provides a lot of warnings to help you with common errors and pitfalls. However, these warning strings become useless in production and bloat your app's payload size. In addition, some of these warning checks have small runtime costs that can be avoided in production mode.
@@ -18,7 +20,15 @@ When using a build tool like Webpack or Browserify, the production mode will be
#### Webpack
-Use Webpack's [DefinePlugin](https://webpack.js.org/plugins/define-plugin/) to indicate a production environment, so that warning blocks can be automatically dropped by UglifyJS during minification. Example config:
+In Webpack 4+, you can use the `mode` option:
+
+``` js
+module.exports = {
+ mode: 'production'
+}
+```
+
+But in Webpack 3 and earlier, you'll need to use [DefinePlugin](https://webpack.js.org/plugins/define-plugin/):
``` js
var webpack = require('webpack')
@@ -28,9 +38,7 @@ module.exports = {
plugins: [
// ...
new webpack.DefinePlugin({
- 'process.env': {
- NODE_ENV: '"production"'
- }
+ 'process.env.NODE_ENV': JSON.stringify('production')
})
]
}
@@ -61,13 +69,13 @@ module.exports = {
)
.bundle()
```
-
+
- Or, using [envify](https://github.com/hughsk/envify) with Grunt and [grunt-browserify](https://github.com/jmreidy/grunt-browserify):
``` js
// Use the envify custom module to specify environment variables
var envify = require('envify/custom')
-
+
browserify: {
dist: {
options: {
@@ -87,10 +95,10 @@ module.exports = {
#### Rollup
-Use [rollup-plugin-replace](https://github.com/rollup/rollup-plugin-replace):
+Use [@rollup/plugin-replace](https://github.com/rollup/plugins/tree/master/packages/replace):
``` js
-const replace = require('rollup-plugin-replace')
+const replace = require('@rollup/plugin-replace')
rollup({
// ...
diff --git a/src/v2/guide/events.md b/src/v2/guide/events.md
index 5af791af03..ede0254df2 100644
--- a/src/v2/guide/events.md
+++ b/src/v2/guide/events.md
@@ -4,6 +4,8 @@ type: guide
order: 9
---
+
+
## Listening to Events
We can use the `v-on` directive to listen to DOM events and run some JavaScript when they're triggered.
@@ -154,7 +156,9 @@ Sometimes we also need to access the original DOM event in an inline statement h
methods: {
warn: function (message, event) {
// now we have access to the native event
- if (event) event.preventDefault()
+ if (event) {
+ event.preventDefault()
+ }
alert(message)
}
}
@@ -171,6 +175,7 @@ To address this problem, Vue provides **event modifiers** for `v-on`. Recall tha
- `.capture`
- `.self`
- `.once`
+- `.passive`
``` html
@@ -203,7 +208,7 @@ To address this problem, Vue provides **event modifiers** for `v-on`. Recall tha
```
-Unlike the other modifiers, which are exclusive to native DOM events, the `.once` modifier can also be used on [component events](components.html#Using-v-on-with-Custom-Events). If you haven't read about components yet, don't worry about this for now.
+Unlike the other modifiers, which are exclusive to native DOM events, the `.once` modifier can also be used on [component events](components-custom-events.html). If you haven't read about components yet, don't worry about this for now.
> New in 2.3.0+
@@ -222,24 +227,32 @@ The `.passive` modifier is especially useful for improving performance on mobile
## Key Modifiers
-When listening for keyboard events, we often need to check for common key codes. Vue also allows adding key modifiers for `v-on` when listening for key events:
+When listening for keyboard events, we often need to check for specific keys. Vue allows adding key modifiers for `v-on` when listening for key events:
``` html
-
-
+
+
```
-Remembering all the `keyCode`s is a hassle, so Vue provides aliases for the most commonly used keys:
+You can directly use any valid key names exposed via [`KeyboardEvent.key`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values) as modifiers by converting them to kebab-case.
``` html
-
-
+
+```
-
-
+In the above example, the handler will only be called if `$event.key` is equal to `'PageDown'`.
+
+### Key Codes
+
+The use of `keyCode` events [is deprecated](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/keyCode) and may not be supported in new browsers.
+
+Using `keyCode` attributes is also permitted:
+
+``` html
+
```
-Here's the full list of key modifier aliases:
+Vue provides aliases for the most commonly used key codes when necessary for legacy browser support:
- `.enter`
- `.tab`
@@ -251,6 +264,8 @@ Here's the full list of key modifier aliases:
- `.left`
- `.right`
+A few keys (`.esc` and all arrow keys) have inconsistent `key` values in IE9, so these built-in aliases should be preferred if you need to support IE9.
+
You can also [define custom key modifier aliases](../api/#keyCodes) via the global `config.keyCodes` object:
``` js
@@ -258,20 +273,6 @@ You can also [define custom key modifier aliases](../api/#keyCodes) via the glob
Vue.config.keyCodes.f1 = 112
```
-### Automatic Key Modifiers
-
-> New in 2.5.0+
-
-You can also directly use any valid key names exposed via [`KeyboardEvent.key`](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values) as modifiers by converting them to kebab-case:
-
-``` html
-
-```
-
-In the above example, the handler will only be called if `$event.key === 'PageDown'`.
-
-A few keys (`.esc` and all arrow keys) have inconsistent `key` values in IE9, their built-in aliases should be preferred if you need to support IE9.
-
## System Modifier Keys
> New in 2.1.0+
@@ -283,16 +284,16 @@ You can use the following modifiers to trigger mouse or keyboard event listeners
- `.shift`
- `.meta`
-> Note: On Macintosh keyboards, meta is the command key (⌘). On Windows keyboards, meta is the windows key (⊞). On Sun Microsystems keyboards, meta is marked as a solid diamond (◆). On certain keyboards, specifically MIT and Lisp machine keyboards and successors, such as the Knight keyboard, space-cadet keyboard, meta is labeled “META”. On Symbolics keyboards, meta is labeled “META” or “Meta”.
+> Note: On Macintosh keyboards, meta is the command key (⌘). On Windows keyboards, meta is the Windows key (⊞). On Sun Microsystems keyboards, meta is marked as a solid diamond (◆). On certain keyboards, specifically MIT and Lisp machine keyboards and successors, such as the Knight keyboard, space-cadet keyboard, meta is labeled “META”. On Symbolics keyboards, meta is labeled “META” or “Meta”.
For example:
```html
-
+
-Do something
+Do something
```
Note that modifier keys are different from regular keys and when used with `keyup` events, they have to be pressed when the event is emitted. In other words, `keyup.ctrl` will only trigger if you release a key while holding down `ctrl`. It won't trigger if you release the `ctrl` key alone. If you do want such behaviour, use the `keyCode` for `ctrl` instead: `keyup.17`.
@@ -305,13 +306,13 @@ The `.exact` modifier allows control of the exact combination of system modifier
``` html
-A
+A
-A
+A
-A
+A
```
### Mouse Button Modifiers
diff --git a/src/v2/guide/filters.md b/src/v2/guide/filters.md
index 4a6eecdbf2..c86d48f52a 100644
--- a/src/v2/guide/filters.md
+++ b/src/v2/guide/filters.md
@@ -40,6 +40,8 @@ new Vue({
})
```
+When the global filter has the same name as the local filter, the local filter will be preferred.
+
Below is an example of our `capitalize` filter being used:
{% raw %}
diff --git a/src/v2/guide/forms.md b/src/v2/guide/forms.md
index 49c36dd1a3..c0a4296635 100644
--- a/src/v2/guide/forms.md
+++ b/src/v2/guide/forms.md
@@ -6,11 +6,16 @@ order: 10
## Basic Usage
-You can use the `v-model` directive to create two-way data bindings on form input and textarea elements. It automatically picks the correct way to update the element based on the input type. Although a bit magical, `v-model` is essentially syntax sugar for updating data on user input events, plus special care for some edge cases.
+You can use the `v-model` directive to create two-way data bindings on form input, textarea, and select elements. It automatically picks the correct way to update the element based on the input type. Although a bit magical, `v-model` is essentially syntax sugar for updating data on user input events, plus special care for some edge cases.
-`v-model` will ignore the initial `value`, `checked` or `selected` attributes found on any form elements. It will always treat the Vue instance data as the source of truth. You should declare the initial value on the JavaScript side, inside the `data` option of your component.
+`v-model` will ignore the initial `value`, `checked`, or `selected` attributes found on any form elements. It will always treat the Vue instance data as the source of truth. You should declare the initial value on the JavaScript side, inside the `data` option of your component.
-For languages that require an [IME](https://en.wikipedia.org/wiki/Input_method) (Chinese, Japanese, Korean etc.), you'll notice that `v-model` doesn't get updated during IME composition. If you want to cater for these updates as well, use `input` event instead.
+`v-model` internally uses different properties and emits different events for different input elements:
+- text and textarea elements use `value` property and `input` event;
+- checkboxes and radiobuttons use `checked` property and `change` event;
+- select fields use `value` as a prop and `change` as an event.
+
+For languages that require an [IME](https://en.wikipedia.org/wiki/Input_method) (Chinese, Japanese, Korean, etc.), you'll notice that `v-model` doesn't get updated during IME composition. If you want to cater to these updates as well, use the `input` event instead.
### Text
@@ -90,21 +95,19 @@ new Vue({
Multiple checkboxes, bound to the same Array:
``` html
-
-
- Jack
-
- John
-
- Mike
-
- Checked names: {{ checkedNames }}
-
+
+Jack
+
+John
+
+Mike
+
+Checked names: {{ checkedNames }}
```
``` js
new Vue({
- el: '#example-3',
+ el: '...',
data: {
checkedNames: []
}
@@ -204,7 +207,7 @@ new Vue({
{% endraw %}
-If the initial value of your `v-model` expression does not match any of the options, the `` element will render in an "unselected" state. On iOS this will cause the user not being able to select the first item because iOS does not fire a change event in this case. It is therefore recommended to provide a disabled option with an empty value, as demonstrated in the example above.
+If the initial value of your `v-model` expression does not match any of the options, the `` element will render in an "unselected" state. On iOS, this will prevent the user from being able to select the first item, because iOS does not fire a `change` event in this case. It is therefore recommended to provide a `disabled` option with an empty value, as demonstrated in the example above.
Multiple select (bound to Array):
@@ -286,7 +289,7 @@ new Vue({
## Value Bindings
-For radio, checkbox and select options, the `v-model` binding values are usually static strings (or booleans for checkbox):
+For radio, checkbox and select options, the `v-model` binding values are usually static strings (or booleans for checkboxes):
``` html
@@ -301,7 +304,7 @@ For radio, checkbox and select options, the `v-model` binding values are usually
```
-But sometimes we may want to bind the value to a dynamic property on the Vue instance. We can use `v-bind` to achieve that. In addition, using `v-bind` allows us to bind the input value to non-string values.
+But sometimes, we may want to bind the value to a dynamic property on the Vue instance. We can use `v-bind` to achieve that. In addition, using `v-bind` allows us to bind the input value to non-string values.
### Checkbox
@@ -321,7 +324,7 @@ vm.toggle === 'yes'
vm.toggle === 'no'
```
-The `true-value` and `false-value` attributes don't affect the input's `value` attribute, because browsers don't include unchecked boxes in form submissions. To guarantee that one of two values is submitted in a form (e.g. "yes" or "no"), use radio inputs instead.
+The `true-value` and `false-value` attributes don't affect the input's `value` attribute, because browsers don't include unchecked boxes in form submissions. To guarantee that one of two values is submitted in a form (i.e. "yes" or "no"), use radio inputs instead.
### Radio
@@ -353,26 +356,26 @@ vm.selected.number // => 123
### `.lazy`
-By default, `v-model` syncs the input with the data after each `input` event (with the exception of IME composition as [stated above](#vmodel-ime-tip)). You can add the `lazy` modifier to instead sync after `change` events:
+By default, `v-model` syncs the input with the data after each `input` event (with the exception of IME composition, as [stated above](#vmodel-ime-tip)). You can add the `lazy` modifier to instead sync _after_ `change` events:
``` html
-
+
```
### `.number`
-If you want user input to be automatically typecast as a number, you can add the `number` modifier to your `v-model` managed inputs:
+If you want user input to be automatically typecast as a Number, you can add the `number` modifier to your `v-model` managed inputs:
``` html
```
-This is often useful, because even with `type="number"`, the value of HTML input elements always returns a string.
+This is often useful, because even with `type="number"`, the value of HTML input elements always returns a string. If the value cannot be parsed with `parseFloat()`, then the original value is returned.
### `.trim`
-If you want user input to be trimmed automatically, you can add the `trim` modifier to your `v-model` managed inputs:
+If you want whitespace from user input to be trimmed automatically, you can add the `trim` modifier to your `v-model`-managed inputs:
```html
@@ -382,4 +385,6 @@ If you want user input to be trimmed automatically, you can add the `trim` modif
> If you're not yet familiar with Vue's components, you can skip this for now.
-HTML's built-in input types won't always meet your needs. Fortunately, Vue components allow you to build reusable inputs with completely customized behavior. These inputs even work with `v-model`! To learn more, read about [custom inputs](components.html#Form-Input-Components-using-Custom-Events) in the Components guide.
+HTML's built-in input types won't always meet your needs. Fortunately, Vue components allow you to build reusable inputs with completely customized behavior. These inputs even work with `v-model`!
+
+To learn more, read about [custom inputs](components.html#Using-v-model-on-Components) in the Components guide.
diff --git a/src/v2/guide/index.md b/src/v2/guide/index.md
index 98415eceb7..047220f0e1 100644
--- a/src/v2/guide/index.md
+++ b/src/v2/guide/index.md
@@ -12,28 +12,36 @@ If you’d like to learn more about Vue before diving in, we Watch a free video course on Vue Mastery
+
## Getting Started
+Installation
+
The official guide assumes intermediate level knowledge of HTML, CSS, and JavaScript. If you are totally new to frontend development, it might not be the best idea to jump right into a framework as your first step - grasp the basics then come back! Prior experience with other frameworks helps, but is not required.
-The easiest way to try out Vue.js is using the [JSFiddle Hello World example](https://jsfiddle.net/chrisvfritz/50wL7mdz/). Feel free to open it in another tab and follow along as we go through some basic examples. Or, you can create an index.html file and include Vue with:
+The easiest way to try out Vue.js is using the [Hello World example](https://codesandbox.io/s/github/vuejs/v2.vuejs.org/tree/master/src/v2/examples/vue-20-hello-world). Feel free to open it in another tab and follow along as we go through some basic examples. Or, you can create an index.html file and include Vue with:
``` html
-
+
```
or:
``` html
-
+
```
The [Installation](installation.html) page provides more options of installing Vue. Note: We **do not** recommend that beginners start with `vue-cli`, especially if you are not yet familiar with Node.js-based build tools.
+If you prefer something more interactive, you can also check out [this tutorial series on Scrimba](https://scrimba.com/g/gvuedocs), which gives you a mix of screencast and code playground that you can pause and play around with anytime.
+
## Declarative Rendering
+
+
At the core of Vue.js is a system that enables us to declaratively render data to the DOM using straightforward template syntax:
``` html
@@ -65,6 +73,8 @@ var app = new Vue({
We have already created our very first Vue app! This looks pretty similar to rendering a string template, but Vue has done a lot of work under the hood. The data and the DOM are now linked, and everything is now **reactive**. How do we know? Open your browser's JavaScript console (right now, on this page) and set `app.message` to a different value. You should see the rendered example above update accordingly.
+Note that we no longer have to interact with the HTML directly. A Vue app attaches itself to a single DOM element (`#app` in our case) then fully controls it. The HTML is our entry point, but everything else happens within the newly created Vue instance.
+
In addition to text interpolation, we can also bind element attributes like this:
``` html
@@ -105,6 +115,8 @@ If you open up your JavaScript console again and enter `app2.message = 'some new
## Conditionals and Loops
+
+
It's easy to toggle the presence of an element, too:
``` html
@@ -189,6 +201,8 @@ In the console, enter `app4.todos.push({ text: 'New item' })`. You should see a
## Handling User Input
+
+
To let users interact with your app, we can use the `v-on` directive to attach event listeners that invoke methods on our Vue instances:
``` html
@@ -265,6 +279,8 @@ var app6 = new Vue({
## Composing with Components
+
+
The component system is another important concept in Vue, because it's an abstraction that allows us to build large-scale applications composed of small, self-contained, and often reusable components. If we think about it, almost any type of application interface can be abstracted into a tree of components:

@@ -276,6 +292,8 @@ In Vue, a component is essentially a Vue instance with pre-defined options. Regi
Vue.component('todo-item', {
template: 'This is a todo '
})
+
+var app = new Vue(...)
```
Now you can compose it in another component's template:
@@ -313,8 +331,8 @@ Now we can pass the todo into each repeated component using `v-bind`:
-
+ v-bind:key="item.id"
+ >
```
@@ -377,12 +395,14 @@ In a large application, it is necessary to divide the whole app into components
You may have noticed that Vue components are very similar to **Custom Elements**, which are part of the [Web Components Spec](https://www.w3.org/wiki/WebComponents/). That's because Vue's component syntax is loosely modeled after the spec. For example, Vue components implement the [Slot API](https://github.com/w3c/webcomponents/blob/gh-pages/proposals/Slots-Proposal.md) and the `is` special attribute. However, there are a few key differences:
-1. The Web Components Spec is still in draft status, and is not natively implemented in every browser. In comparison, Vue components don't require any polyfills and work consistently in all supported browsers (IE9 and above). When needed, Vue components can also be wrapped inside a native custom element.
+1. The Web Components Spec has been finalized, but is not natively implemented in every browser. Safari 10.1+, Chrome 54+ and Firefox 63+ natively support web components. In comparison, Vue components don't require any polyfills and work consistently in all supported browsers (IE9 and above). When needed, Vue components can also be wrapped inside a native custom element.
2. Vue components provide important features that are not available in plain custom elements, most notably cross-component data flow, custom event communication and build tool integrations.
+Although Vue doesn't use custom elements internally, it has [great interoperability](https://custom-elements-everywhere.com/#vue) when it comes to consuming or distributing as custom elements. Vue CLI also supports building Vue components that register themselves as native custom elements.
+
## Ready for More?
We've briefly introduced the most basic features of Vue.js core - the rest of this guide will cover them and other advanced features with much finer details, so make sure to read through it all!
-
+
diff --git a/src/v2/guide/installation.md b/src/v2/guide/installation.md
index a87cab4622..23abed94c0 100644
--- a/src/v2/guide/installation.md
+++ b/src/v2/guide/installation.md
@@ -2,14 +2,18 @@
title: Installation
type: guide
order: 1
-vue_version: 2.5.13
-gz_size: "30.67"
+vue_version: 2.7.14
+gz_size: "37.51"
---
### Compatibility Note
Vue does **not** support IE8 and below, because it uses ECMAScript 5 features that are un-shimmable in IE8. However it supports all [ECMAScript 5 compliant browsers](https://caniuse.com/#feat=es5).
+### Semantic Versioning
+
+Vue follows [Semantic Versioning](https://semver.org/) in all its official projects for documented features and behavior. For undocumented behavior or exposed internals, changes are described in [release notes](https://github.com/vuejs/vue/releases).
+
### Release Notes
Latest stable version: {{vue_version}}
@@ -27,17 +31,31 @@ Simply download and include with a script tag. `Vue` will be registered as a glo
Don't use the minified version during development. You will miss out on all the nice warnings for common mistakes!
### CDN
-We recommend linking to a specific version number that you can update manually:
+For prototyping or learning purposes, you can use the latest version with:
+
+``` html
+
+```
+
+For production, we recommend linking to a specific version number and build to avoid unexpected breakage from newer versions:
+
+``` html
+
+```
+
+If you are using native ES Modules, there is also an ES Modules compatible build:
``` html
-
+
```
You can browse the source of the NPM package at [cdn.jsdelivr.net/npm/vue](https://cdn.jsdelivr.net/npm/vue/).
@@ -53,49 +71,45 @@ NPM is the recommended installation method when building large scale application
``` bash
# latest stable
-$ npm install vue
+$ npm install vue@^2
```
## CLI
-Vue.js provides an [official CLI](https://github.com/vuejs/vue-cli) for quickly scaffolding ambitious Single Page Applications. It provides batteries-included build setups for a modern frontend workflow. It takes only a few minutes to get up and running with hot-reload, lint-on-save, and production-ready builds:
-
-``` bash
-# install vue-cli
-$ npm install --global vue-cli
-# create a new project using the "webpack" template
-$ vue init webpack my-project
-# install dependencies and go!
-$ cd my-project
-$ npm run dev
-```
+Vue provides an [official CLI](https://github.com/vuejs/vue-cli) for quickly scaffolding ambitious Single Page Applications. It provides batteries-included build setups for a modern frontend workflow. It takes only a few minutes to get up and running with hot-reload, lint-on-save, and production-ready builds. See [the Vue CLI docs](https://cli.vuejs.org) for more details.
The CLI assumes prior knowledge of Node.js and the associated build tools. If you are new to Vue or front-end build tools, we strongly suggest going through the guide without any build tools before using the CLI.
+
+
## Explanation of Different Builds
-In the [`dist/` directory of the NPM package](https://cdn.jsdelivr.net/npm/vue/dist/) you will find many different builds of Vue.js. Here's an overview of the difference between them:
+In the [`dist/` directory of the NPM package](https://cdn.jsdelivr.net/npm/vue@2.7.14/dist/) you will find many different builds of Vue.js. Here's an overview of the difference between them:
-| | UMD | CommonJS | ES Module |
-| --- | --- | --- | --- |
-| **Full** | vue.js | vue.common.js | vue.esm.js |
-| **Runtime-only** | vue.runtime.js | vue.runtime.common.js | vue.runtime.esm.js |
-| **Full (production)** | vue.min.js | - | - |
-| **Runtime-only (production)** | vue.runtime.min.js | - | - |
+| | UMD | CommonJS | ES Module (for bundlers) | ES Module (for browsers) |
+| --- | --- | --- | --- | --- |
+| **Full** | vue.js | vue.common.js | vue.esm.js | vue.esm.browser.js |
+| **Runtime-only** | vue.runtime.js | vue.runtime.common.js | vue.runtime.esm.js | - |
+| **Full (production)** | vue.min.js | - | - | vue.esm.browser.min.js |
+| **Runtime-only (production)** | vue.runtime.min.js | - | - | - |
### Terms
-- **Full**: builds that contains both the compiler and the runtime.
+- **Full**: builds that contain both the compiler and the runtime.
- **Compiler**: code that is responsible for compiling template strings into JavaScript render functions.
- **Runtime**: code that is responsible for creating Vue instances, rendering and patching virtual DOM, etc. Basically everything minus the compiler.
-- **[UMD](https://github.com/umdjs/umd)**: UMD builds can be used directly in the browser via a `
+
## Creating a Vue Instance
Every Vue application starts by creating a new **Vue instance** with the `Vue` function:
@@ -24,10 +32,10 @@ A Vue application consists of a **root Vue instance** created with `new Vue`, op
Root Instance
└─ TodoList
├─ TodoItem
- │ ├─ DeleteTodoButton
- │ └─ EditTodoButton
+ │ ├─ TodoButtonDelete
+ │ └─ TodoButtonEdit
└─ TodoListFooter
- ├─ ClearTodosButton
+ ├─ TodosButtonClear
└─ TodoListStatistics
```
@@ -123,6 +131,8 @@ In the future, you can consult the [API reference](../api/#Instance-Properties)
## Instance Lifecycle Hooks
+
+
Each Vue instance goes through a series of initialization steps when it's created - for example, it needs to set up data observation, compile the template, mount the instance to the DOM, and update the DOM when data changes. Along the way, it also runs functions called **lifecycle hooks**, giving users the opportunity to add their own code at specific stages.
For example, the [`created`](../api/#created) hook can be used to run code after an instance is created:
@@ -142,7 +152,7 @@ new Vue({
There are also other hooks which will be called at different stages of the instance's lifecycle, such as [`mounted`](../api/#mounted), [`updated`](../api/#updated), and [`destroyed`](../api/#destroyed). All lifecycle hooks are called with their `this` context pointing to the Vue instance invoking it.
-Don't use [arrow functions](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions) on an options property or callback, such as `created: () => console.log(this.a)` or `vm.$watch('a', newValue => this.myMethod())`. Since arrow functions are bound to the parent context, `this` will not be the Vue instance as you'd expect, often resulting in errors such as `Uncaught TypeError: Cannot read property of undefined` or `Uncaught TypeError: this.myMethod is not a function`.
+Don't use [arrow functions](https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Functions/Arrow_functions) on an options property or callback, such as `created: () => console.log(this.a)` or `vm.$watch('a', newValue => this.myMethod())`. Since an arrow function doesn't have a `this`, `this` will be treated as any other variable and lexically looked up through parent scopes until found, often resulting in errors such as `Uncaught TypeError: Cannot read property of undefined` or `Uncaught TypeError: this.myMethod is not a function`.
## Lifecycle Diagram
diff --git a/src/v2/guide/join.md b/src/v2/guide/join.md
index 1c4dbbb008..c87118f707 100644
--- a/src/v2/guide/join.md
+++ b/src/v2/guide/join.md
@@ -8,12 +8,17 @@ Vue's community is growing incredibly fast and if you're reading this, there's a
Now we'll answer both what the community can do for you and what you can do for the community.
-## Resources You'll Enjoy
+## Resources
+
+### Code of Conduct
+
+Our [Code of Conduct](/coc) is a guide to make it easier to enrich all of us and the technical communities in which we participate.
### Get Support
- [Forum](https://forum.vuejs.org/): The best place to ask questions and get answers about Vue and its ecosystem.
- [Chat](https://chat.vuejs.org/): A place for Vue devs to meet and chat in real time.
+- [Meetups](https://events.vuejs.org/meetups): Want to find local Vue.js enthusiasts like yourself? Interested in becoming a community leader? We have the help and support you need right here!
- [GitHub](https://github.com/vuejs): If you have a bug to report or feature to request, that's what the GitHub issues are for. We also welcome pull requests!
### Explore the Ecosystem
@@ -44,8 +49,18 @@ Apart from answering questions and sharing resources in the forum and chat, ther
### Translate Docs
-Vue has already spread across the globe, with even the core team in at least half a dozen timezones. [The forum](https://forum.vuejs.org/) includes 7 languages and counting and many of our docs have [actively-maintained translations](https://github.com/vuejs?utf8=%E2%9C%93&query=vuejs.org). We're very proud of Vue's international reach, but we can do even better.
+Vue has already spread across the globe, with even the core team in at least half a dozen timezones. [The forum](https://forum.vuejs.org/) includes 7 languages and counting and many of our docs have [actively-maintained translations](https://github.com/vuejs?utf8=%E2%9C%93&q=vuejs.org). We're very proud of Vue's international reach, but we can do even better.
I hope that right now, you're reading this sentence in your preferred language. If not, would you like to help us get there?
-If so, please feel free to fork the repo for [these docs](https://github.com/vuejs/vuejs.org/) or for any other officially maintained documentation, then start translating. Once you've made some progress, open an issue or pull request in the main repo and we'll put out a call for more contributors to help you out.
+If so, please feel free to fork the repo for [these docs](https://github.com/vuejs/v2.vuejs.org/) or for any other officially maintained documentation, then start translating. Once you've made some progress, open an issue or pull request in the main repo and we'll put out a call for more contributors to help you out.
+
+### Become a Community Leader
+
+There's a lot you can do to help Vue grow in your community:
+
+- **Present at your local meetup.** Whether it's giving a talk or running a workshop, you can bring a lot of value to your community by helping both new and experienced Vue developers continue to grow.
+- **Start your own meetup.** If there's not already a Vue meetup in your area, you can start your own! Use the [resources at events.vuejs.org](https://events.vuejs.org/resources/#getting-started) to help you succeed!
+- **Help meetup organizers.** There can never be too much help when it comes to running an event, so offer a hand to help out local organizers to help make every event a success.
+
+If you have any questions on how you can get more involved with your local Vue community, reach out at [@Vuejs_Events](https://www.twitter.com/vuejs_events)!
diff --git a/src/v2/guide/list.md b/src/v2/guide/list.md
index 60acc81328..7701645894 100644
--- a/src/v2/guide/list.md
+++ b/src/v2/guide/list.md
@@ -4,13 +4,16 @@ type: guide
order: 8
---
+
+
+
## Mapping an Array to Elements with `v-for`
We can use the `v-for` directive to render a list of items based on an array. The `v-for` directive requires a special syntax in the form of `item in items`, where `items` is the source data array and `item` is an **alias** for the array element being iterated on:
``` html
@@ -32,7 +35,7 @@ Result:
{% raw %}
@@ -44,11 +47,6 @@ var example1 = new Vue({
{ message: 'Foo' },
{ message: 'Bar' }
]
- },
- watch: {
- items: function () {
- smoothScroll.animateScroll(document.querySelector('#example-1'))
- }
}
})
@@ -94,11 +92,6 @@ var example2 = new Vue({
{ message: 'Foo' },
{ message: 'Bar' }
]
- },
- watch: {
- items: function () {
- smoothScroll.animateScroll(document.querySelector('#example-2'))
- }
}
})
@@ -127,9 +120,9 @@ new Vue({
el: '#v-for-object',
data: {
object: {
- firstName: 'John',
- lastName: 'Doe',
- age: 30
+ title: 'How to do lists in Vue',
+ author: 'Jane Doe',
+ publishedAt: '2016-04-10'
}
}
})
@@ -148,37 +141,37 @@ new Vue({
el: '#v-for-object',
data: {
object: {
- firstName: 'John',
- lastName: 'Doe',
- age: 30
+ title: 'How to do lists in Vue',
+ author: 'Jane Doe',
+ publishedAt: '2016-04-10'
}
}
})
{% endraw %}
-You can also provide a second argument for the key:
+You can also provide a second argument for the property's name (a.k.a. key):
``` html
-
- {{ key }}: {{ value }}
+
+ {{ name }}: {{ value }}
```
{% raw %}
-
-
- {{ key }}: {{ value }}
+
+
+ {{ name }}: {{ value }}
{% endraw %}
-
When iterating over an object, the order is based on the key enumeration order of `Object.keys()`, which is **not** guaranteed to be consistent across JavaScript engine implementations.
+
When iterating over an object, the order is based on the enumeration order of `Object.keys()`, which is **not** guaranteed to be consistent across JavaScript engine implementations.
-## `key`
+## Maintaining State
When Vue is updating a list of elements rendered with `v-for`, by default it uses an "in-place patch" strategy. If the order of the data items has changed, instead of moving the DOM elements to match the order of the items, Vue will patch each element in-place and make sure it reflects what should be rendered at that particular index. This is similar to the behavior of `track-by="$index"` in Vue 1.x.
-This default mode is efficient, but only suitable **when your list render output does not rely on child component state or temporary DOM state (e.g. form input values)**.
+This default mode is efficient, but **only suitable when your list render output does not rely on child component state or temporary DOM state (e.g. form input values)**.
-To give Vue a hint so that it can track each node's identity, and thus reuse and reorder existing elements, you need to provide a unique `key` attribute for each item. An ideal value for `key` would be the unique id of each item. This special attribute is a rough equivalent to `track-by` in 1.x, but it works like an attribute, so you need to use `v-bind` to bind it to dynamic values (using shorthand here):
+To give Vue a hint so that it can track each node's identity, and thus reuse and reorder existing elements, you need to provide a unique `key` attribute for each item:
``` html
-
+
```
-It is recommended to provide a `key` with `v-for` whenever possible, unless the iterated DOM content is simple, or you are intentionally relying on the default behavior for performance gains.
+It is recommended to provide a `key` attribute with `v-for` whenever possible, unless the iterated DOM content is simple, or you are intentionally relying on the default behavior for performance gains.
Since it's a generic mechanism for Vue to identify nodes, the `key` also has other uses that are not specifically tied to `v-for`, as we will see later in the guide.
+
Don't use non-primitive values like objects and arrays as `v-for` keys. Use string or numeric values instead.
+
+For detailed usage of the `key` attribute, please see the [`key` API documentation](/v2/api/#key).
+
## Array Change Detection
### Mutation Methods
@@ -263,103 +260,7 @@ You might think this will cause Vue to throw away the existing DOM and re-render
### Caveats
-Due to limitations in JavaScript, Vue **cannot** detect the following changes to an array:
-
-1. When you directly set an item with the index, e.g. `vm.items[indexOfItem] = newValue`
-2. When you modify the length of the array, e.g. `vm.items.length = newLength`
-
-For example:
-
-``` js
-var vm = new Vue({
- data: {
- items: ['a', 'b', 'c']
- }
-})
-vm.items[1] = 'x' // is NOT reactive
-vm.items.length = 2 // is NOT reactive
-```
-
-To overcome caveat 1, both of the following will accomplish the same as `vm.items[indexOfItem] = newValue`, but will also trigger state updates in the reactivity system:
-
-``` js
-// Vue.set
-Vue.set(vm.items, indexOfItem, newValue)
-```
-``` js
-// Array.prototype.splice
-vm.items.splice(indexOfItem, 1, newValue)
-```
-
-You can also use the [`vm.$set`](https://vuejs.org/v2/api/#vm-set) instance method, which is an alias for the global `Vue.set`:
-
-``` js
-vm.$set(vm.items, indexOfItem, newValue)
-```
-
-To deal with caveat 2, you can use `splice`:
-
-``` js
-vm.items.splice(newLength)
-```
-
-## Object Change Detection Caveats
-
-Again due to limitations of modern JavaScript, **Vue cannot detect property addition or deletion**. For example:
-
-``` js
-var vm = new Vue({
- data: {
- a: 1
- }
-})
-// `vm.a` is now reactive
-
-vm.b = 2
-// `vm.b` is NOT reactive
-```
-
-Vue does not allow dynamically adding new root-level reactive properties to an already created instance. However, it's possible to add reactive properties to a nested object using the `Vue.set(object, key, value)` method. For example, given:
-
-``` js
-var vm = new Vue({
- data: {
- userProfile: {
- name: 'Anika'
- }
- }
-})
-```
-
-You could add a new `age` property to the nested `userProfile` object with:
-
-``` js
-Vue.set(vm.userProfile, 'age', 27)
-```
-
-You can also use the `vm.$set` instance method, which is an alias for the global `Vue.set`:
-
-``` js
-vm.$set(vm.userProfile, 'age', 27)
-```
-
-Sometimes you may want to assign a number of new properties to an existing object, for example using `Object.assign()` or `_.extend()`. In such cases, you should create a fresh object with properties from both objects. So instead of:
-
-``` js
-Object.assign(vm.userProfile, {
- age: 27,
- favoriteColor: 'Vue Green'
-})
-```
-
-You would add new, reactive properties with:
-
-``` js
-vm.userProfile = Object.assign({}, vm.userProfile, {
- age: 27,
- favoriteColor: 'Vue Green'
-})
-```
+Due to limitations in JavaScript, there are types of changes that Vue **cannot detect** with arrays and objects. These are discussed in the [reactivity](reactivity.html#Change-Detection-Caveats) section.
## Displaying Filtered/Sorted Results
@@ -386,13 +287,15 @@ computed: {
In situations where computed properties are not feasible (e.g. inside nested `v-for` loops), you can use a method:
-``` html
-
{{ n }}
+```html
+
```
-``` js
+```js
data: {
- numbers: [ 1, 2, 3, 4, 5 ]
+ sets: [[ 1, 2, 3, 4, 5 ], [6, 7, 8, 9, 10]]
},
methods: {
even: function (numbers) {
@@ -432,13 +335,15 @@ Similar to template `v-if`, you can also use a `
` tag with `v-for` to
```
## `v-for` with `v-if`
+Note that it's **not** recommended to use `v-if` and `v-for` together. Refer to [style guide](/v2/style-guide/#Avoid-v-if-with-v-for-essential) for details.
+
When they exist on the same node, `v-for` has a higher priority than `v-if`. That means the `v-if` will be run on each iteration of the loop separately. This can be useful when you want to render nodes for only _some_ items, like below:
``` html
@@ -489,11 +394,15 @@ Here's a complete example of a simple todo list:
``` html
-
+
\
{{ title }}\
- X \
+ Remove \
\
',
props: ['title']
@@ -553,11 +462,15 @@ new Vue({
{% raw %}
-
+
\
{{ title }}\
- X \
+ Remove \
\
',
props: ['title']
diff --git a/src/v2/guide/migration-vue-2-7.md b/src/v2/guide/migration-vue-2-7.md
new file mode 100644
index 0000000000..9ab267bd29
--- /dev/null
+++ b/src/v2/guide/migration-vue-2-7.md
@@ -0,0 +1,120 @@
+---
+title: Migration to Vue 2.7
+type: guide
+order: 704
+---
+
+Vue 2.7 is the latest minor version of Vue 2. It provides built-in support for the [Composition API](https://vuejs.org/guide/extras/composition-api-faq.html#composition-api-faq).
+
+Despite Vue 3 now being the default version, we understand that there are still many users who have to stay on Vue 2 due to dependency compatibility, browser support requirements, or simply not enough bandwidth to upgrade. In Vue 2.7, we have backported some of the most important features from Vue 3 so that Vue 2 users can benefit from them as well.
+
+## Backported Features
+
+- [Composition API](https://vuejs.org/guide/extras/composition-api-faq.html)
+- SFC [`
-
-{% endraw %}
+
diff --git a/src/v2/guide/security.md b/src/v2/guide/security.md
new file mode 100644
index 0000000000..f0877d106c
--- /dev/null
+++ b/src/v2/guide/security.md
@@ -0,0 +1,185 @@
+---
+title: Security
+type: guide
+order: 504
+---
+
+## Reporting Vulnerabilities
+
+When a vulnerability is reported, it immediately becomes our top concern, with a full-time contributor dropping everything to work on it. To report a vulnerability, please email [security@vuejs.org](mailto:security@vuejs.org).
+
+While the discovery of new vulnerabilities is rare, we also recommend always using the latest versions of Vue and its official companion libraries to ensure your application remains as secure as possible.
+
+## Rule No.1: Never Use Non-trusted Templates
+
+The most fundamental security rule when using Vue is **never use non-trusted content as your component template**. Doing so is equivalent to allowing arbitrary JavaScript execution in your application - and worse, could lead to server breaches if the code is executed during server-side rendering. An example of such usage:
+
+``` js
+new Vue({
+ el: '#app',
+ template: `` + userProvidedString + `
` // NEVER DO THIS
+})
+```
+
+Vue templates are compiled into JavaScript, and expressions inside templates will be executed as part of the rendering process. Although the expressions are evaluated against a specific rendering context, due to the complexity of potential global execution environments, it is impractical for a framework like Vue to completely shield you from potential malicious code execution without incurring unrealistic performance overhead. The most straightforward way to avoid this category of problems altogether is to make sure the contents of your Vue templates are always trusted and entirely controlled by you.
+
+## What Vue Does to Protect You
+
+### HTML content
+
+Whether using templates or render functions, content is automatically escaped. That means in this template:
+
+```html
+{{ userProvidedString }}
+```
+
+if `userProvidedString` contained:
+
+```js
+''
+```
+
+then it would be escaped to the following HTML:
+
+```html
+<script>alert("hi")</script>
+```
+
+thus preventing the script injection. This escaping is done using native browser APIs, like `textContent`, so a vulnerability can only exist if the browser itself is vulnerable.
+
+### Attribute bindings
+
+Similarly, dynamic attribute bindings are also automatically escaped. That means in this template:
+
+```html
+
+ hello
+
+```
+
+if `userProvidedString` contained:
+
+```js
+'" onclick="alert(\'hi\')'
+```
+
+then it would be escaped to the following HTML:
+
+```html
+" onclick="alert('hi')
+```
+
+thus preventing the close of the `title` attribute to inject new, arbitrary HTML. This escaping is done using native browser APIs, like `setAttribute`, so a vulnerability can only exist if the browser itself is vulnerable.
+
+## Potential Dangers
+
+In any web application, allowing unsanitized, user-provided content to be executed as HTML, CSS, or JavaScript is potentially dangerous, so should be avoided wherever possible. There are times when some risk be acceptable though.
+
+For example, services like CodePen and JSFiddle allow user-provided content to be executed, but it's in a context where this is expected and sandboxed to some extent inside iframes. In the cases when an important feature inherently requires some level of vulnerability, it's up to your team to weigh the importance of the feature against the worst-case scenarios the vulnerability enables.
+
+### Injecting HTML
+
+As you learned earlier, Vue automatically escapes HTML content, preventing you from accidentally injecting executable HTML into your application. However, in cases where you know the HTML is safe, you can explicitly render HTML content:
+
+- Using a template:
+ ```html
+
+ ```
+
+- Using a render function:
+ ```js
+ h('div', {
+ domProps: {
+ innerHTML: this.userProvidedHtml
+ }
+ })
+ ```
+
+- Using a render function with JSX:
+ ```jsx
+
+ ```
+
+Note that user-provided HTML can never be considered 100% safe unless it's in a sandboxed iframe or in a part of the app where only the user who wrote that HTML can ever be exposed to it. Additionally, allowing users to write their own Vue templates brings similar dangers.
+
+### Injecting URLs
+
+In a URL like this:
+
+```html
+
+ click me
+
+```
+
+There's a potential security issue if the URL has not been "sanitized" to prevent JavaScript execution using `javascript:`. There are libraries such as [sanitize-url](https://www.npmjs.com/package/@braintree/sanitize-url) to help with this, but note:
+
+If you're ever doing URL sanitization on the frontend, you already have a security issue. User-provided URLs should always be sanitized by your backend before even being saved to a database. Then the problem is avoided for _every_ client connecting to your API, including native mobile apps. Also note that even with sanitized URLs, Vue cannot help you guarantee that they lead to safe destinations.
+
+### Injecting Styles
+
+Looking at this example:
+
+```html
+
+ click me
+
+```
+
+let's assume that `sanitizedUrl` has been sanitized, so that it's definitely a real URL and not JavaScript. With the `userProvidedStyles`, malicious users could still provide CSS to "click jack", e.g. styling the link into a transparent box over the "Log in" button. Then if `https://user-controlled-website.com/` is built to resemble the login page of your application, they might have just captured a user's real login information.
+
+You may be able to imagine how allowing user-provided content for a `
+```
+
+To keep your users fully safe from click jacking, we recommend only allowing full control over CSS inside a sandboxed iframe. Alternatively, when providing user control through a style binding, we recommend using its [object syntax](class-and-style.html#Object-Syntax-1) and only allowing users to provide values for specific properties it's safe for them to control, like this:
+
+```html
+
+ click me
+
+```
+
+### Injecting JavaScript
+
+We strongly discourage ever rendering a `
@@ -60,13 +60,13 @@ The contents of the `span` will be replaced with the value of the `rawHtml` prop
### Attributes
-Mustaches cannot be used inside HTML attributes. Instead, use a [v-bind directive](../api/#v-bind):
+Mustaches cannot be used inside HTML attributes. Instead, use a [`v-bind` directive](../api/#v-bind):
``` html
```
-In the case of boolean attributes, where their mere existence implies `true`, `v-bind` works a little differently. In this example:
+In the case of boolean attributes, where their mere existence implies `true`, `v-bind` works a little differently. In this example:
``` html
Button
@@ -98,11 +98,11 @@ These expressions will be evaluated as JavaScript in the data scope of the owner
{{ if (ok) { return message } }}
```
-Template expressions are sandboxed and only have access to a whitelist of globals such as `Math` and `Date`. You should not attempt to access user defined globals in template expressions.
+Template expressions are sandboxed and only have access to a [whitelist of globals](https://github.com/vuejs/vue/blob/v2.6.10/src/core/instance/proxy.js#L9) such as `Math` and `Date`. You should not attempt to access user-defined globals in template expressions.
## Directives
-Directives are special attributes with the `v-` prefix. Directive attribute values are expected to be **a single JavaScript expression** (with the exception for `v-for`, which will be discussed later). A directive's job is to reactively apply side effects to the DOM when the value of its expression changes. Let's review the example we saw in the introduction:
+Directives are special attributes with the `v-` prefix. Directive attribute values are expected to be **a single JavaScript expression** (with the exception of `v-for`, which will be discussed later). A directive's job is to reactively apply side effects to the DOM when the value of its expression changes. Let's review the example we saw in the introduction:
``` html
Now you see me
@@ -128,6 +128,55 @@ Another example is the `v-on` directive, which listens to DOM events:
Here the argument is the event name to listen to. We will talk about event handling in more detail too.
+### Dynamic Arguments
+
+> New in 2.6.0+
+
+Starting in version 2.6.0, it is also possible to use a JavaScript expression in a directive argument by wrapping it with square brackets:
+
+``` html
+
+ ...
+```
+
+Here `attributeName` will be dynamically evaluated as a JavaScript expression, and its evaluated value will be used as the final value for the argument. For example, if your Vue instance has a data property, `attributeName`, whose value is `"href"`, then this binding will be equivalent to `v-bind:href`.
+
+Similarly, you can use dynamic arguments to bind a handler to a dynamic event name:
+
+``` html
+ ...
+```
+
+In this example, when `eventName`'s value is `"focus"`, `v-on:[eventName]` will be equivalent to `v-on:focus`.
+
+#### Dynamic Argument Value Constraints
+
+Dynamic arguments are expected to evaluate to a string, with the exception of `null`. The special value `null` can be used to explicitly remove the binding. Any other non-string value will trigger a warning.
+
+#### Dynamic Argument Expression Constraints
+
+Dynamic argument expressions have some syntax constraints because certain characters, such as spaces and quotes, are invalid inside HTML attribute names. For example, the following is invalid:
+
+``` html
+
+ ...
+```
+
+The workaround is to either use expressions without spaces or quotes, or replace the complex expression with a computed property.
+
+When using in-DOM templates (i.e., templates written directly in an HTML file), you should also avoid naming keys with uppercase characters, as browsers will coerce attribute names into lowercase:
+
+``` html
+
+ ...
+```
+
### Modifiers
Modifiers are special postfixes denoted by a dot, which indicate that a directive should be bound in some special way. For example, the `.prevent` modifier tells the `v-on` directive to call `event.preventDefault()` on the triggered event:
@@ -140,7 +189,7 @@ You'll see other examples of modifiers later, [for `v-on`](events.html#Event-Mod
## Shorthands
-The `v-` prefix serves as a visual cue for identifying Vue-specific attributes in your templates. This is useful when you are using Vue.js to apply dynamic behavior to some existing markup, but can feel verbose for some frequently used directives. At the same time, the need for the `v-` prefix becomes less important when you are building a [SPA](https://en.wikipedia.org/wiki/Single-page_application) where Vue.js manages every template. Therefore, Vue.js provides special shorthands for two of the most often used directives, `v-bind` and `v-on`:
+The `v-` prefix serves as a visual cue for identifying Vue-specific attributes in your templates. This is useful when you are using Vue.js to apply dynamic behavior to some existing markup, but can feel verbose for some frequently used directives. At the same time, the need for the `v-` prefix becomes less important when you are building a [SPA](https://en.wikipedia.org/wiki/Single-page_application), where Vue manages every template. Therefore, Vue provides special shorthands for two of the most often used directives, `v-bind` and `v-on`:
### `v-bind` Shorthand
@@ -150,6 +199,9 @@ The `v-` prefix serves as a visual cue for identifying Vue-specific attributes i
...
+
+
+ ...
```
### `v-on` Shorthand
@@ -160,6 +212,9 @@ The `v-` prefix serves as a visual cue for identifying Vue-specific attributes i
...
+
+
+ ...
```
-They may look a bit different from normal HTML, but `:` and `@` are valid chars for attribute names and all Vue.js supported browsers can parse it correctly. In addition, they do not appear in the final rendered markup. The shorthand syntax is totally optional, but you will likely appreciate it when you learn more about its usage later.
+They may look a bit different from normal HTML, but `:` and `@` are valid characters for attribute names and all Vue-supported browsers can parse it correctly. In addition, they do not appear in the final rendered markup. The shorthand syntax is totally optional, but you will likely appreciate it when you learn more about its usage later.
diff --git a/src/v2/guide/team.md b/src/v2/guide/team.md
index 13ea5faaf6..f866fd1b8b 100644
--- a/src/v2/guide/team.md
+++ b/src/v2/guide/team.md
@@ -5,12 +5,19 @@ order: 803
---
{% raw %}
+
+
{% endraw %}
diff --git a/src/v2/guide/testing.md b/src/v2/guide/testing.md
new file mode 100644
index 0000000000..bda896238f
--- /dev/null
+++ b/src/v2/guide/testing.md
@@ -0,0 +1,168 @@
+---
+title: Testing
+type: guide
+order: 402
+---
+
+## Introduction
+
+When it comes to building reliable applications, tests can play a critical role in an individual or team's ability to build new features, refactor code, fix bugs, etc. While there are many schools of thought with testing, there are three categories often discussed in the context of web applications:
+
+- Unit Testing
+- Component Testing
+- End-To-End (E2E) Testing
+
+This section aims to provide guidance to navigating the testing ecosystem and choosing the right tools for your Vue application or component library.
+
+## Unit Testing
+
+### Introduction
+
+Unit tests allow you to test individual units of code in isolation. The purpose of unit testing is to provide developers with confidence in their code. By writing thorough, meaningful tests, you achieve the confidence that as new features are built or your code is refactored your application will remain functional and stable.
+
+Unit testing a Vue application does not significantly differ from testing other types of applications.
+
+### Choosing Your Framework
+
+Since unit testing advice is often framework-agnostic, here are some basic guidelines to keep in mind when evaluating which unit testing tool is best for your application.
+
+#### First-class error reporting
+
+When tests fail, it is critical that your unit testing framework provides useful errors. This is the job of the assertion library. An assertion with high-quality error messages helps minimize the amount of time it takes to debug the problem. In addition to simply telling you what test is failing, assertion libraries provide context for why a test fails, e.g., what is expected vs what was received.
+
+Some unit testing frameworks, like Jest, include assertion libraries. Others, like Mocha, require you to install assertion libraries separately (usually Chai).
+
+#### Active community and team
+
+Since the majority of unit testing frameworks are open-source, having a community that is active can be critical to some teams that will be maintaining their tests for a long period of time and needs to ensure that a project will be actively maintained. In addition, having an active community has the benefit of providing more support whenever you run into issues.
+
+### Frameworks
+
+While there are many tools in the ecosystem, here are some common unit testing tools that are being used in the Vue.js ecosystem.
+
+#### Jest
+
+Jest is a JavaScript test framework that is focused on simplicity. One of its unique features is the ability to take snapshots of tests in order to provide an alternative means of verifying units of your application.
+
+**Resources:**
+
+- [Official Jest Website](https://jestjs.io)
+- [Official Vue 2 CLI Plugin - Jest](https://cli.vuejs.org/core-plugins/unit-jest.html)
+
+#### Mocha
+
+Mocha is a JavaScript test framework that is focused on being flexible. Because of this flexibility, it allows you to choose different libraries to fulfill other common features such as spying (e.g., Sinon) and assertions (e.g., Chai). Another unique feature of Mocha is that it can also execute tests in the browser in addition to Node.js.
+
+**Resources:**
+
+- [Official Mocha Website](https://mochajs.org)
+- [Official Vue CLI Plugin - Mocha](https://cli.vuejs.org/core-plugins/unit-mocha.html)
+
+## Component Testing
+
+### Introduction
+
+To test most Vue components, they must be mounted to the DOM (either virtual or real) in order to fully assert that they are working. This is another framework-agnostic concept. As a result, component testing frameworks were created to give users the ability to do this reliably while also providing Vue-specific conveniences such as integrations for Vuex, Vue Router, and other Vue plugins.
+
+### Choosing Your Framework
+
+The following section provides guidelines on things to keep in mind when evaluating which component testing framework is best for your application.
+
+#### Optimal compatibility with the Vue ecosystem
+
+It should be no surprise that one of the first criteria is that a component testing library should have is being as compatible with the Vue ecosystem as possible. While this may seem comprehensive, some key integration areas to keep in mind include single file components (SFCs), Vuex, Vue Router, and any other Vue specific plugins that your application relies on.
+
+#### First-class error reporting
+
+When tests fail, it is critical that your component testing framework provides useful error logs that help to minimize the amount of time it takes to debug the problem. In addition to simply telling you what test fails, they should also provide context for why a test fails, e.g., what is expected vs what was received.
+
+### Recommendations
+
+#### Vue Testing Library (@testing-library/vue)
+
+Vue Testing Library is a set of tools focused on testing components without relying on implementation details. Built with accessibility in mind, its approach also makes refactoring a breeze.
+
+Its guiding principle is that the more tests resemble the way software is used, the more confidence they can provide.
+
+**Resources:**
+
+- [Official Vue Testing Library Website](https://testing-library.com/docs/vue-testing-library/intro)
+
+#### Vue Test Utils
+
+Vue Test Utils is the official low-level component testing library that was written to provide users access to Vue specific APIs. If you are new to testing Vue applications, we would recommend using Vue Testing Library, which is an abstraction over Vue Test Utils.
+
+**Resources**
+
+- [Official Vue Test Utils Documentation](https://vue-test-utils.vuejs.org)
+- [Vue Testing Handbook](https://lmiller1990.github.io/vue-testing-handbook/#what-is-this-guide) by Lachlan Miller
+- [Cookbook: Unit Testing Vue Components](/v2/cookbook/unit-testing-vue-components.html)
+
+## End-to-End (E2E) Testing
+
+### Introduction
+
+While unit tests provide developers with some degree of confidence, unit and component tests are limited in their abilities to provide holistic coverage of an application when deployed to production. As a result, end-to-end (E2E) tests provide coverage on what is arguably the most important aspect of an application: what happens when users actually use your applications.
+
+In other words, E2E tests validate all of the layers in your application. This not only includes your frontend code, but all associated backend services and infrastructure that are more representative of the environment that your users will be in. By testing how user actions impact your application, E2E tests are often the key to higher confidence in whether an application is functioning properly or not.
+
+### Choosing Your Framework
+
+While end-to-end (E2E) testing on the web has gained a negative reputation for unreliable (flaky) tests and slowing down development processes, modern E2E tools have made strides forward to create more reliable, interactive, and useful tests. When choosing an E2E testing framework, the following sections provide some guidance on things to keep in mind when choosing a testing framework for your application.
+
+#### Cross-browser testing
+
+One of the primary benefits that end-to-end (E2E) testing is known for is its ability to test your application across multiple browsers. While it may seem desirable to have 100% cross-browser coverage, it is important to note that cross browser testing has diminishing returns on a team's resources due the additional time and machine power required to run them consistently. As a result, it is important to be mindful of this trade-off when choosing the amount of cross-browser testing your application needs.
+
+A recent development in E2E for catching browser-specific issues is using application monitoring and error reporting tools (e.g., Sentry, LogRocket, etc.) for browsers that are not as commonly used (e.g., < IE11, older Safari versions, etc.).
+
+#### Faster feedback loops
+
+One of the primary problems with end-to-end (E2E) tests and development is that running the entire suite takes a long time. Typically, this is only done in continuous integration and deployment (CI/CD) pipelines. Modern E2E testing frameworks have helped to solve this by adding features like parallelization, which allows for CI/CD pipelines to often run magnitudes faster than before. In addition, when developing locally, the ability to selectively run a single test for the page you are working on while also providing hot reloading of tests can help to boost a developer's workflow and productivity.
+
+#### First class debugging experience
+
+While developers have traditionally relied on scanning logs in a terminal window to help determine what went wrong in a test, modern end-to-end (E2E) test frameworks allow developers to leverage tools that they are already familiar with, e.g. browser developer tools.
+
+#### Visibility in headless mode
+
+When end-to-end (E2E) tests are run in continuous integration / deployment pipelines, they are often run in headless browsers (i.e., no visible browser is opened for the user to watch). As a result, when errors occur, a critical feature that modern E2E testing frameworks provide 1st class support for is the ability to see snapshots and/or videos of your applications during various testing stages in order to provide insight into why errors are happening. Historically, it was tedious to maintain these integrations.
+
+### Recommendations
+
+While there are many tools in the ecosystem, here are some common end-to-end (E2E) testing frameworks that are being used in the Vue.js ecosystem.
+
+#### Cypress.io
+
+Cypress.io is a testing framework that aims to enhance developer productivity by enabling developers to reliably test their applications while providing a first class developer experience.
+
+**Resources**
+
+- [Cypress' Official Website](https://www.cypress.io)
+- [Official Vue CLI Cypress Plugin](https://cli.vuejs.org/core-plugins/e2e-cypress.html)
+- [Cypress Testing Library](https://github.com/testing-library/cypress-testing-library)
+
+#### Nightwatch.js
+
+Nightwatch.js is an end-to-end testing framework that can be used to test web applications and websites, as well as Node.js unit and integration testing.
+
+**Resources:**
+
+- [Nightwatch's Official Website](https://nightwatchjs.org)
+- [Official Vue CLI Nightwatch Plugin](https://cli.vuejs.org/core-plugins/e2e-nightwatch.html)
+
+#### Puppeteer
+
+Puppeteer is a Node library that provides a high-level API to control the browser and can pair with other test runners (e.g., Jest) to test your application.
+
+**Resources:**
+
+- [Puppeteer's Official Website](https://pptr.dev)
+
+#### TestCafe
+
+TestCafe is a Node.js based end-to-end framework that aims to provide easy setup so that developers can focus on creating tests that are easy to write and reliable.
+
+**Resources:**
+
+- [TestCafe's Official Website](https://devexpress.github.io/testcafe/)
diff --git a/src/v2/guide/transitioning-state.md b/src/v2/guide/transitioning-state.md
index cbc3348ba7..dd0bf5a50b 100644
--- a/src/v2/guide/transitioning-state.md
+++ b/src/v2/guide/transitioning-state.md
@@ -18,7 +18,7 @@ All of these are either already stored as raw numbers or can be converted into n
Watchers allow us to animate changes of any numerical property into another property. That may sound complicated in the abstract, so let's dive into an example using [GreenSock](https://greensock.com/):
``` html
-
+
@@ -40,14 +40,14 @@ new Vue({
},
watch: {
number: function(newValue) {
- TweenLite.to(this.$data, 0.5, { tweenedNumber: newValue });
+ gsap.to(this.$data, { duration: 0.5, tweenedNumber: newValue });
}
}
})
```
{% raw %}
-
+
{{ animatedNumber }}
@@ -66,7 +66,7 @@ new Vue({
},
watch: {
number: function(newValue) {
- TweenLite.to(this.$data, 0.5, { tweenedNumber: newValue });
+ gsap.to(this.$data, { duration: 0.5, tweenedNumber: newValue });
}
}
})
@@ -366,7 +366,7 @@ function generatePoints (stats) {
{% endraw %}
-See [this fiddle](https://jsfiddle.net/chrisvfritz/65gLu2b6/) for the complete code behind the above demo.
+See [this example](https://codesandbox.io/s/github/vuejs/v2.vuejs.org/tree/master/src/v2/examples/vue-20-dynamic-state-transitions) for the complete code behind the above demo.
## Organizing Transitions into Components
@@ -425,8 +425,8 @@ Vue.component('animated-integer', {
new TWEEN.Tween({ tweeningValue: startValue })
.to({ tweeningValue: endValue }, 500)
- .onUpdate(function (object) {
- vm.tweeningValue = object.tweeningValue.toFixed(0)
+ .onUpdate(function () {
+ vm.tweeningValue = this.tweeningValue.toFixed(0)
})
.start()
diff --git a/src/v2/guide/transitions.md b/src/v2/guide/transitions.md
index 5ac1bcd10a..7f0637d78e 100644
--- a/src/v2/guide/transitions.md
+++ b/src/v2/guide/transitions.md
@@ -4,6 +4,12 @@ type: guide
order: 201
---
+
+
## Overview
Vue provides a variety of ways to apply transition effects when items are inserted, updated, or removed from the DOM. This includes tools to:
@@ -479,6 +485,7 @@ new Vue({
methods: {
beforeEnter: function (el) {
el.style.opacity = 0
+ el.style.transformOrigin = 'left'
},
enter: function (el, done) {
Velocity(el, { opacity: 1, fontSize: '1.4em' }, { duration: 300 })
@@ -581,6 +588,8 @@ and custom JavaScript hooks:
```
+In the example above, either `appear` attribute or `v-on:appear` hook will cause an appear transition.
+
## Transitioning Between Elements
We discuss [transitioning between components](#Transitioning-Between-Components) later, but you can also transition between raw elements using `v-if`/`v-else`. One of the most common two-element transitions is between a list container and a message describing an empty list:
@@ -955,7 +964,9 @@ So far, we've managed transitions for:
So what about for when we have a whole list of items we want to render simultaneously, for example with `v-for`? In this case, we'll use the `
` component. Before we dive into an example though, there are a few things that are important to know about this component:
- Unlike ``, it renders an actual element: a `` by default. You can change the element that's rendered with the `tag` attribute.
-- Elements inside are **always required** to have a unique `key` attribute
+- [Transition modes](#Transition-Modes) are not available, because we are no longer alternating between mutually exclusive elements.
+- Elements inside are **always required** to have a unique `key` attribute.
+- CSS transition classes will be applied to inner elements and not to the group/container itself.
### List Entering/Leaving Transitions
@@ -1240,7 +1251,7 @@ new Vue({
One important note is that these FLIP transitions do not work with elements set to `display: inline`. As an alternative, you can use `display: inline-block` or place elements in a flex context.
-These FLIP animations are also not limited to a single axis. Items in a multidimensional grid can be [transitioned too](https://jsfiddle.net/chrisvfritz/sLrhk1bc/):
+These FLIP animations are also not limited to a single axis. Items in a multidimensional grid can be [transitioned too](https://codesandbox.io/s/github/vuejs/v2.vuejs.org/tree/master/src/v2/examples/vue-20-list-move-transitions):
{% raw %}
@@ -1478,7 +1489,7 @@ Vue.component('my-special-transition', {
})
```
-And functional components are especially well-suited to this task:
+And [functional components](render-function.html#Functional-Components) are especially well-suited to this task:
``` js
Vue.component('my-special-transition', {
diff --git a/src/v2/guide/typescript.md b/src/v2/guide/typescript.md
index d65676dfc0..19d01a87d0 100644
--- a/src/v2/guide/typescript.md
+++ b/src/v2/guide/typescript.md
@@ -1,18 +1,16 @@
---
title: TypeScript Support
type: guide
-order: 404
+order: 403
---
-> In Vue 2.5.0+ we have greatly improved our type declarations to work with the default object-based API. At the same time it introduces a few changes that require upgrade actions. Read [this blog post](https://medium.com/the-vue-point/upcoming-typescript-changes-in-vue-2-5-e9bd7e2ecf08) for more details.
+> [Vue CLI](https://cli.vuejs.org) provides built-in TypeScript tooling support.
## Official Declaration in NPM Packages
A static type system can help prevent many potential runtime errors, especially as applications grow. That's why Vue ships with [official type declarations](https://github.com/vuejs/vue/tree/dev/types) for [TypeScript](https://www.typescriptlang.org/) - not only in Vue core, but also for [vue-router](https://github.com/vuejs/vue-router/tree/dev/types) and [vuex](https://github.com/vuejs/vuex/tree/dev/types) as well.
-Since these are [published on NPM](https://cdn.jsdelivr.net/npm/vue/types/), and the latest TypeScript knows how to resolve type declarations in NPM packages, this means when installed via NPM, you don't need any additional tooling to use TypeScript with Vue.
-
-We also plan to provide an option to scaffold a ready-to-go Vue + TypeScript project in `vue-cli` in the near future.
+Since these are [published on NPM](https://cdn.jsdelivr.net/npm/vue@2/types/), and the latest TypeScript knows how to resolve type declarations in NPM packages, this means when installed via NPM, you don't need any additional tooling to use TypeScript with Vue.
## Recommended Configuration
@@ -37,11 +35,23 @@ See [TypeScript compiler options docs](https://www.typescriptlang.org/docs/handb
## Development Tooling
-For developing Vue applications with TypeScript, we strongly recommend using [Visual Studio Code](https://code.visualstudio.com/), which provides great out-of-the-box support for TypeScript.
+### Project Creation
+
+[Vue CLI 3](https://github.com/vuejs/vue-cli) can generate new projects that use TypeScript. To get started:
+
+```bash
+# 1. Install Vue CLI, if it's not already installed
+npm install --global @vue/cli
+
+# 2. Create a new project, then choose the "Manually select features" option
+vue create my-project-name
+```
-If you are using [single-file components](./single-file-components.html) (SFCs), get the awesome [Vetur extension](https://github.com/vuejs/vetur), which provides TypeScript inference inside SFCs and many other great features.
+### Editor Support
-[WebStorm](https://www.jetbrains.com/webstorm/) also provides out-of-the-box support for both TypeScript and Vue.js.
+For developing Vue applications with TypeScript, we strongly recommend using [Visual Studio Code](https://code.visualstudio.com/), which provides great out-of-the-box support for TypeScript. If you are using [single-file components](./single-file-components.html) (SFCs), get the awesome [Vetur extension](https://github.com/vuejs/vetur), which provides TypeScript inference inside SFCs and many other great features.
+
+[WebStorm](https://www.jetbrains.com/webstorm/) also provides out-of-the-box support for both TypeScript and Vue.
## Basic Usage
@@ -177,3 +187,34 @@ const Component = Vue.extend({
```
If you find type inference or member completion isn't working, annotating certain methods may help address these problems. Using the `--noImplicitAny` option will help find many of these unannotated methods.
+
+
+
+## Annotating Props
+
+```ts
+import Vue, { PropType } from 'vue'
+
+interface ComplexMessage {
+ title: string,
+ okMessage: string,
+ cancelMessage: string
+}
+const Component = Vue.extend({
+ props: {
+ name: String,
+ success: { type: String },
+ callback: {
+ type: Function as PropType<() => void>
+ },
+ message: {
+ type: Object as PropType
,
+ required: true,
+ validator (message: ComplexMessage) {
+ return !!message.title;
+ }
+ }
+ }
+})
+```
+If you find validator not getting type inference or member completion isn't working, annotating the argument with the expected type may help address these problems.
diff --git a/src/v2/guide/unit-testing.md b/src/v2/guide/unit-testing.md
deleted file mode 100644
index f6190dffb7..0000000000
--- a/src/v2/guide/unit-testing.md
+++ /dev/null
@@ -1,134 +0,0 @@
----
-title: Unit Testing
-type: guide
-order: 403
----
-
-## Setup and Tooling
-
-Anything compatible with a module-based build system will work, but if you're looking for a specific recommendation try the [Karma](http://karma-runner.github.io) test runner. It has a lot of community plugins, including support for [Webpack](https://github.com/webpack/karma-webpack) and [Browserify](https://github.com/Nikku/karma-browserify). For detailed setup please refer to each project's respective documentation. These example Karma configurations for [Webpack](https://github.com/vuejs-templates/webpack/blob/master/template/test/unit/karma.conf.js) and [Browserify](https://github.com/vuejs-templates/browserify/blob/master/template/karma.conf.js) can help you get started.
-
-## Simple Assertions
-
-You don't have to do anything special in your components to make them testable. Export the raw options:
-
-``` html
-
- {{ message }}
-
-
-
-```
-
-Then import the component options along with Vue, and you can make many common assertions:
-
-``` js
-// Import Vue and the component being tested
-import Vue from 'vue'
-import MyComponent from 'path/to/MyComponent.vue'
-
-// Here are some Jasmine 2.0 tests, though you can
-// use any test runner / assertion library combo you prefer
-describe('MyComponent', () => {
- // Inspect the raw component options
- it('has a created hook', () => {
- expect(typeof MyComponent.created).toBe('function')
- })
-
- // Evaluate the results of functions in
- // the raw component options
- it('sets the correct default data', () => {
- expect(typeof MyComponent.data).toBe('function')
- const defaultData = MyComponent.data()
- expect(defaultData.message).toBe('hello!')
- })
-
- // Inspect the component instance on mount
- it('correctly sets the message when created', () => {
- const vm = new Vue(MyComponent).$mount()
- expect(vm.message).toBe('bye!')
- })
-
- // Mount an instance and inspect the render output
- it('renders the correct message', () => {
- const Constructor = Vue.extend(MyComponent)
- const vm = new Constructor().$mount()
- expect(vm.$el.textContent).toBe('bye!')
- })
-})
-```
-
-## Writing Testable Components
-
-A component's render output is primarily determined by the props they receive. If a component's render output solely depends on its props it becomes straightforward to test, similar to asserting the return value of a pure function with different arguments. Take a simplified example:
-
-``` html
-
- {{ msg }}
-
-
-
-```
-
-You can assert its render output with different props using the `propsData` option:
-
-``` js
-import Vue from 'vue'
-import MyComponent from './MyComponent.vue'
-
-// helper function that mounts and returns the rendered text
-function getRenderedText (Component, propsData) {
- const Constructor = Vue.extend(Component)
- const vm = new Constructor({ propsData: propsData }).$mount()
- return vm.$el.textContent
-}
-
-describe('MyComponent', () => {
- it('renders correctly with different props', () => {
- expect(getRenderedText(MyComponent, {
- msg: 'Hello'
- })).toBe('Hello')
-
- expect(getRenderedText(MyComponent, {
- msg: 'Bye'
- })).toBe('Bye')
- })
-})
-```
-
-## Asserting Asynchronous Updates
-
-Since Vue [performs DOM updates asynchronously](reactivity.html#Async-Update-Queue), assertions on DOM updates resulting from state change will have to be made in a `Vue.nextTick` callback:
-
-``` js
-// Inspect the generated HTML after a state update
-it('updates the rendered message when vm.message updates', done => {
- const vm = new Vue(MyComponent).$mount()
- vm.message = 'foo'
-
- // wait a "tick" after state change before asserting DOM updates
- Vue.nextTick(() => {
- expect(vm.$el.textContent).toBe('foo')
- done()
- })
-})
-```
-
-We are planning to work on a collection of common test helpers to make it easier to render components with different constraints (e.g. shallow rendering that ignores child components) and assert their output.
-
-For more in-depth information on unit testing in Vue, check out [vue-test-utils](https://vue-test-utils.vuejs.org/en/) and our cookbook entry about [unit testing vue components](https://vuejs.org/v2/cookbook/unit-testing-vue-components.html).
diff --git a/src/v2/search/index.md b/src/v2/search/index.md
new file mode 100644
index 0000000000..556fe68671
--- /dev/null
+++ b/src/v2/search/index.md
@@ -0,0 +1,5 @@
+---
+title: Search Vue.js
+type: search
+search: true
+---
\ No newline at end of file
diff --git a/src/v2/style-guide/index.md b/src/v2/style-guide/index.md
index 0eea3d3f73..8567e99b66 100644
--- a/src/v2/style-guide/index.md
+++ b/src/v2/style-guide/index.md
@@ -43,9 +43,9 @@ Some features of Vue exist to accommodate rare edge cases or smoother migrations
### Multi-word component names essential
-**Component names should always be multi-word, except for root `App` components.**
+**Component names should always be multi-word, except for root `App` components, and built-in components provided by Vue, such as `` or ``.**
-This [prevents conflicts](http://w3c.github.io/webcomponents/spec/custom/#valid-custom-element-name) with existing and future HTML elements, since all HTML elements are a single word.
+This [prevents conflicts](https://html.spec.whatwg.org/multipage/custom-elements.html#valid-custom-element-name) with existing and future HTML elements, since all HTML elements are a single word.
{% raw %}{% endraw %}
#### Bad
@@ -189,7 +189,7 @@ In committed code, prop definitions should always be as detailed as possible, sp
{% endraw %}
-Detailed [prop definitions](https://vuejs.org/v2/guide/components.html#Prop-Validation) have two advantages:
+Detailed [prop definitions](/v2/guide/components.html#Prop-Validation) have two advantages:
- They document the API of the component, so that it's easy to see how the component is meant to be used.
- In development, Vue will warn you if a component is ever provided incorrectly formatted props, helping you catch potential sources of error.
@@ -331,7 +331,7 @@ When Vue processes directives, `v-for` has a higher priority than `v-if`, so tha
:key="user.id"
>
{{ user.name }}
-
+
```
@@ -366,7 +366,7 @@ computed: {
:key="user.id"
>
{{ user.name }}
-
+
```
@@ -386,7 +386,7 @@ We get similar benefits from updating:
:key="user.id"
>
{{ user.name }}
-
+
```
@@ -399,7 +399,7 @@ to:
:key="user.id"
>
{{ user.name }}
-
+
```
@@ -418,7 +418,7 @@ By moving the `v-if` to a container element, we're no longer checking `shouldSho
:key="user.id"
>
{{ user.name }}
-
+
```
@@ -430,7 +430,7 @@ By moving the `v-if` to a container element, we're no longer checking `shouldSho
:key="user.id"
>
{{ user.name }}
-
+
```
{% raw %}{% endraw %}
@@ -445,7 +445,7 @@ By moving the `v-if` to a container element, we're no longer checking `shouldSho
:key="user.id"
>
{{ user.name }}
-
+
```
@@ -456,7 +456,7 @@ By moving the `v-if` to a container element, we're no longer checking `shouldSho
:key="user.id"
>
{{ user.name }}
-
+
```
{% raw %} {% endraw %}
@@ -564,7 +564,7 @@ Beyond the `scoped` attribute, using unique class names can help ensure that 3rd
### Private property names essential
-**Always use the `$_` prefix for custom private properties in a plugin, mixin, etc. Then to avoid conflicts with code by other authors, also include a named scope (e.g. `$_yourPluginName_`).**
+**Use module scoping to keep private functions inaccessible from the outside. If that's not possible, always use the `$_` prefix for custom private properties in a plugin, mixin, etc that should not be considered public API. Then to avoid conflicts with code by other authors, also include a named scope (e.g. `$_yourPluginName_`).**
{% raw %}
@@ -575,7 +575,7 @@ Beyond the `scoped` attribute, using unique class names can help ensure that 3rd
Vue uses the `_` prefix to define its own private properties, so using the same prefix (e.g. `_update`) risks overwriting an instance property. Even if you check and Vue is not currently using a particular property name, there is no guarantee a conflict won't arise in a later version.
-As for the `$` prefix, it's purpose within the Vue ecosystem is special instance properties that are exposed to the user, so using it for _private_ properties would not be appropriate.
+As for the `$` prefix, its purpose within the Vue ecosystem is special instance properties that are exposed to the user, so using it for _private_ properties would not be appropriate.
Instead, we recommend combining the two prefixes into `$_`, as a convention for user-defined private properties that guarantee no conflicts with Vue.
@@ -643,6 +643,25 @@ var myGreatMixin = {
}
}
```
+
+``` js
+// Even better!
+var myGreatMixin = {
+ // ...
+ methods: {
+ publicMethod() {
+ // ...
+ myPrivateFunction()
+ }
+ }
+}
+
+function myPrivateFunction() {
+ // ...
+}
+
+export default myGreatMixin
+```
{% raw %} {% endraw %}
@@ -739,7 +758,7 @@ components/
These components lay the foundation for consistent styling and behavior in your application. They may **only** contain:
- HTML elements,
-- other `Base`-prefixed components, and
+- other base components, and
- 3rd-party UI components.
But they'll **never** contain global state (e.g. from a Vuex store).
@@ -752,22 +771,6 @@ Some advantages of this convention:
- Since component names should always be multi-word, this convention prevents you from having to choose an arbitrary prefix for simple component wrappers (e.g. `MyButton`, `VueButton`).
-- Since these components are so frequently used, you may want to simply make them global instead of importing them everywhere. A prefix makes this possible with Webpack:
-
- ``` js
- var requireComponent = require.context("./src", true, /^Base[A-Z]/)
- requireComponent.keys().forEach(function (fileName) {
- var baseComponentConfig = requireComponent(fileName)
- baseComponentConfig = baseComponentConfig.default || baseComponentConfig
- var baseComponentName = baseComponentConfig.name || (
- fileName
- .replace(/^.+\//, '')
- .replace(/\.\w+$/, '')
- )
- Vue.component(baseComponentName, baseComponentConfig)
- })
- ```
-
{% raw %}{% endraw %}
{% raw %}
{% endraw %}
@@ -1215,9 +1218,9 @@ props: {
}
```
-``` html
+{% codeblock lang:html %}
-```
+{% endcodeblock %}
{% raw %}
{% endraw %}
{% raw %}
{% endraw %}
@@ -1229,9 +1232,9 @@ props: {
}
```
-``` html
+{% codeblock lang:html %}
-```
+{% endcodeblock %}
{% raw %}
{% endraw %}
@@ -1334,7 +1337,7 @@ Simpler, well-named computed properties are:
- __Easier to read__
- Simplifying computed properties forces you to give each value a descriptive name, even if it's not reused. This makes it much easier for other developers (and future you) to focus in on the code they care about and figure out what's going on.
+ Simplifying computed properties forces you to give each value a descriptive name, even if it's not reused. This makes it much easier for other developers (and future you) to focus on the code they care about and figure out what's going on.
- __More adaptable to changing requirements__
@@ -1414,7 +1417,7 @@ While attribute values without any spaces are not required to have quotes in HTM
### Directive shorthands
strongly recommended
-**Directive shorthands (`:` for `v-bind:` and `@` for `v-on:`) should be used always or never.**
+**Directive shorthands (`:` for `v-bind:`, `@` for `v-on:` and `#` for `v-slot`) should be used always or never.**
{% raw %}
{% endraw %}
#### Bad
@@ -1432,6 +1435,16 @@ While attribute values without any spaces are not required to have quotes in HTM
@focus="onFocus"
>
```
+
+``` html
+
+ Here might be a page title
+
+
+
+ Here's some contact info
+
+```
{% raw %}
{% endraw %}
{% raw %}
{% endraw %}
@@ -1464,6 +1477,26 @@ While attribute values without any spaces are not required to have quotes in HTM
v-on:focus="onFocus"
>
```
+
+``` html
+
+ Here might be a page title
+
+
+
+ Here's some contact info
+
+```
+
+``` html
+
+ Here might be a page title
+
+
+
+ Here's some contact info
+
+```
{% raw %}
{% endraw %}
@@ -1514,6 +1547,16 @@ This is the default order we recommend for component options. They're split into
9. **Events** (callbacks triggered by reactive events)
- `watch`
- Lifecycle Events (in the order they are called)
+ - `beforeCreate`
+ - `created`
+ - `beforeMount`
+ - `mounted`
+ - `beforeUpdate`
+ - `updated`
+ - `activated`
+ - `deactivated`
+ - `beforeDestroy`
+ - `destroyed`
10. **Non-Reactive Properties** (instance properties independent of the reactivity system)
- `methods`
@@ -1553,7 +1596,6 @@ This is the default order we recommend for component options. They're split into
6. **Unique Attributes** (attributes that require unique values)
- `ref`
- `key`
- - `slot`
7. **Two-Way Binding** (combining binding and events)
- `v-model`
@@ -1693,11 +1735,11 @@ computed: {
-### `v-if`/`v-if-else`/`v-else` without `key`
use with caution
+### `v-if`/`v-else-if`/`v-else` without `key`
use with caution
**It's usually best to use `key` with `v-if` + `v-else`, if they are the same element type (e.g. both `
` elements).**
-By default, Vue updates the DOM as efficiently as possible. That means when switching between elements of the same type, it simply patches the existing element, rather than removing it and adding a new one in its place. This can have [unintended side effects](https://jsfiddle.net/chrisvfritz/bh8fLeds/) if these elements should not actually be considered the same.
+By default, Vue updates the DOM as efficiently as possible. That means when switching between elements of the same type, it simply patches the existing element, rather than removing it and adding a new one in its place. This can have [unintended consequences](https://codesandbox.io/s/github/vuejs/v2.vuejs.org/tree/master/src/v2/examples/vue-20-priority-d-rules-unintended-consequences) if these elements should not actually be considered the same.
{% raw %}
{% endraw %}
#### Bad
@@ -1729,15 +1771,6 @@ By default, Vue updates the DOM as efficiently as possible. That means when swit
{{ results }}
```
-
-``` html
-
- Error: {{ error }}
-
-
- {{ results }}
-
-```
{% raw %}
{% endraw %}
@@ -1757,7 +1790,7 @@ Prefer class selectors over element selectors in `scoped` styles, because large
To scope styles, Vue adds a unique attribute to component elements, such as `data-v-f3f3eg9`. Then selectors are modified so that only matching elements with this attribute are selected (e.g. `button[data-v-f3f3eg9]`).
-The problem is that large numbers of [element-attribute selectors](http://stevesouders.com/efws/css-selectors/csscreate.php?n=1000&sel=a%5Bhref%5D&body=background%3A+%23CFD&ne=1000) (e.g. `button[data-v-f3f3eg9]`) will be considerably slower than [class-attribute selectors](http://stevesouders.com/efws/css-selectors/csscreate.php?n=1000&sel=.class%5Bhref%5D&body=background%3A+%23CFD&ne=1000) (e.g. `.btn-close[data-v-f3f3eg9]`), so class selectors should be preferred whenever possible.
+The problem is that large numbers of element-attribute selectors (e.g. `button[data-v-f3f3eg9]`) will be considerably slower than class-attribute selectors (e.g. `.btn-close[data-v-f3f3eg9]`), so class selectors should be preferred whenever possible.
{% raw %}{% endraw %}
@@ -1892,7 +1925,9 @@ Vue.component('TodoItem', {
**[Vuex](https://github.com/vuejs/vuex) should be preferred for global state management, instead of `this.$root` or a global event bus.**
-Managing state on `this.$root` and/or using a [global event bus](https://vuejs.org/v2/guide/migration.html#dispatch-and-broadcast-replaced) can be convenient for very simple cases, but are not appropriate for most applications. Vuex offers not only a central place to manage state, but also tools for organizing, tracking, and debugging state changes.
+Managing state on `this.$root` and/or using a [global event bus](/v2/guide/migration.html#dispatch-and-broadcast-replaced) can be convenient for very simple cases, but it is not appropriate for most applications.
+
+Vuex is the [official flux-like implementation](/v2/guide/state-management.html#Official-Flux-Like-Implementation) for Vue, and offers not only a central place to manage state, but also tools for organizing, tracking, and debugging state changes. It integrates well in the Vue ecosystem (including full [Vue DevTools](/v2/guide/installation.html#Vue-Devtools) support).
{% raw %}{% endraw %}
@@ -1977,7 +2012,7 @@ export default {
var enforcementTypes = {
none: '
self-discipline ',
runtime: 'runtime error',
- linter: '
plugin:vue/recommended '
+ linter: '
plugin:vue/recommended '
}
Vue.component('sg-enforcement', {
template: '\
diff --git a/themes/vue/_config.yml b/themes/vue/_config.yml
index b18a30e354..ae2c91815a 100644
--- a/themes/vue/_config.yml
+++ b/themes/vue/_config.yml
@@ -1,63 +1,246 @@
-site_description: "Vue.js - The Progressive JavaScript Framework"
+site_description: Vue.js - The Progressive JavaScript Framework
google_analytics: UA-46852172-1
root_domain: vuejs.org
-vue_version: 2.5.13
-
-special_sponsors:
- - url: https://stdlib.com
- img: stdlib.png
- - url: https://www.bitsrc.io/?utm_source=vue&utm_medium=vue&utm_campaign=vue&utm_term=vue&utm_content=vue
- img: bit.png
- wide_img: bit-wide.png
- big_width: 120px
- big_height: 120px
-
-platinum_sponsors:
- - url: http://tooltwist.com/
- img: tooltwist.png
- - url: https://vueschool.io/?utm_source=Vuejs.org&utm_medium=Banner&utm_campaign=Sponsored%20Banner&utm_content=V1
+vue_version: 2.7.14
+# START SPONSORS
+special:
+ - name: appwrite
+ url: https://appwrite.io
+ img: appwrite.svg
+ description: Open-source backend cloud platform
+ priority: true
+platinum:
+ - name: Bit
+ url: https://bit.dev
+ img: bit.svg?v2
+ priority: true
+ - name: VueMastery
+ url: https://www.vuemastery.com/
+ img: vuemastery.png
+ - name: VueSchool
+ url: >-
+ https://vueschool.io/?utm_source=Vuejs.org&utm_medium=Banner&utm_campaign=Sponsored%20Banner&utm_content=V1
img: vueschool.png
- - url: https://www.datacamp.com/careers?utm_source=vuejs&utm_medium=sidebar
- img: datacamp.png
-
-gold_sponsors:
- - url: https://laravel.com
+ - name: Vehikl
+ url: https://vehikl.com/
+ img: vehikl.png
+ - name: Passionate People
+ url: https://passionatepeople.io/
+ img: passionate_people.png
+ - name: Storyblok
+ url: https://www.storyblok.com
+ img: storyblok.png
+ - name: Ionic
+ url: >-
+ https://ionicframework.com/vue?utm_source=partner&utm_medium=referral&utm_campaign=vuesponsorship&utm_content=vuedocs
+ img: ionic.png?v2
+ - name: Skilled
+ url: https://skilled.yashio-corp.com
+ img: skilled.svg
+ - name: Chrome Frameworks Fund
+ url: https://opencollective.com/2021-frameworks-fund
+ img: chrome_frameworks_fund.png
+ - name: HeroDevs
+ url: https://www.herodevs.com/support/vue
+ img: herodevs.png
+gold:
+ - name: Laravel
+ url: https://laravel.com
img: laravel.png
- - url: https://htmlburger.com
- img: htmlburger.png
- - url: https://chaitin.cn/en/
- img: chaitin.png
- - url: https://anymod.com
- img: anymod.png
- - url: https://www.frontenddeveloperlove.com/
- img: frontend-love.png
- - url: https://onsen.io/vue/
- img: onsen-ui.png
- - url: https://vuetifyjs.com
- img: vuetify.png
- - url: https://neds.com.au/
- img: neds.png
- - url: https://hackr.io/tutorials/learn-vue-js
- img: hackr-io.png
- - url: https://icons8.com/
- img: icons8.png
- - url: https://vuejobs.com/?ref=vuejs
- img: vuejobs.png
- - url: https://leanpub.com/vuejs2
- img: tmvuejs2.png
- - url: https://www.bmqb.com/jobs
- img: bmqb.png
- - url: https://codepilot.ai
- img: codepilot.png
- - url: https://teamextension.io/
- img: teamextension.png
-
-bronze_sponsors:
- - url: http://tighten.co/
- img: http://i.imgur.com/T7fQYLT.png
- - url: https://alligator.io
- img: https://alligator.io/images/alligator-logo.svg
- - url: https://www.accelebrate.com/
- img: https://www.accelebrate.com/assets/images/accelebrate_logo@2x.png
- - url: https://pullstring.com
- img: https://i.imgur.com/hQHW6TB.png
+ - name: Tidelift
+ url: https://tidelift.com/subscription/npm/vue
+ img: tidelift.png
+ - name: Intygrate
+ url: https://intygrate.com/
+ img: intygrate.png
+ - name: Y8
+ url: https://www.y8.com/
+ img: y8.png
+ - name: DevExpress
+ url: https://js.devexpress.com/
+ img: devexpress.png
+ - name: FASTCODING Inc
+ url: 'https://fastcoding.jp/javascript/'
+ img: fastcoding_inc.svg
+ - name: LY Corporation
+ url: https://www.lycorp.co.jp/en/
+ img: ly_corporation.png?v2
+ - name: Fenêtre Online Solutions
+ url: https://www.fenetre.nl/
+ img: fen_tre_online_solutions.svg
+ - name: Ant Design Vue
+ url: https://antdv.com
+ img: ant_design_vue.png
+ - name: Crisp
+ url: https://crisp.chat/en/
+ img: crisp.png
+ - name: Localazy
+ url: >-
+ https://localazy.com/blog/how-to-localize-vuejs-app-with-vue-i18n-and-localazy?utm_source=vuejs&utm_medium=banner&utm_campaign=sponsorships_vuejs&utm_content=logo
+ img: localazy.svg
+ - name: Casinoburst.com
+ url: https://casinoburst.com/casino-utan-licens/
+ img: casinoburst_com.png
+ - name: 'Enkrypt: Ethereum and Polkadot Web3 Wallet'
+ url: https://www.enkrypt.com
+ img: enkrypt__ethereum_and_polkadot_web3_wallet.svg
+ - name: uudetkasinot.com
+ url: https://www.uudetkasinot.com
+ img: uudetkasinot_com.png
+ - name: Fathom Analytics
+ url: https://usefathom.com/
+ img: fathom_analytics.svg
+ - name: Goread.io
+ url: https://goread.io/buy-instagram-followers
+ img: goread_io.png
+ - name: Sentry
+ url: https://sentry.io/for/vue?utm_source=vuejs.org&utm_medium=paid-community
+ img: sentry.png
+ - name: Poprey.com
+ url: https://poprey.com/
+ img: poprey_com.png
+ - name: Ilmaiset Pitkävetovihjeet
+ url: https://www.vedonlyontibonukset.com/pitkavetovihjeet
+ img: ilmaiset_pitk_vetovihjeet.png
+ - name: Famoid
+ url: https://famoid.com/
+ img: famoid.png
+ - name: Certible
+ url: https://www.certible.com
+ img: certible.svg
+ - name: FORTUNE GAMES
+ url: https://www.fortunegames.com
+ img: fortune_games.png
+ - name: TBDC - Agro Software
+ url: http://tbdc.com.br/
+ img: tbdc___agro_software.svg
+ - name: FineProxy
+ url: https://fineproxy.org/
+ img: fineproxy.svg
+ - name: Daniel
+ url: >-
+ https://rxdb.info/?utm_source=sponsor&utm_medium=opencollective&utm_campaign=opencollective-vuejs
+ img: daniel.png
+ - name: SurveyJS
+ url: https://surveyjs.io/
+ img: surveyjs.png?v2
+ - name: Stormlikes
+ url: https://www.stormlikes.net/buy-instagram-followers
+ img: stormlikes.png
+silver:
+ - name: Draxlr
+ url: https://www.draxlr.com
+ img: draxlr.svg
+ - name: Team Extension North America Inc
+ url: https://teamextension.io
+ img: team_extension_north_america_inc.png
+ - name: Free Bets US
+ url: https://freebets.us
+ img: free_bets_us.png
+ - name: Doximity
+ url: https://technology.doximity.com/
+ img: doximity.png
+ - name: Interflora Group
+ url: https://www.interflora.fr
+ img: interflora_group.png
+ - name: Codesmith
+ url: https://codesmith.io
+ img: codesmith.png
+ - name: Optimizers
+ url: https://www.optimizers.nl
+ img: optimizers.png
+ - name: FORTUNE GAMES
+ url: https://www.fortunegames.com
+ img: fortune_games.png
+ - name: Indy
+ url: https://www.indy.fr/
+ img: indy.png
+ - name: Buy Instagram Followers from SocialWick
+ url: https://www.socialwick.com/instagram/followers
+ img: buy_instagram_followers_from_socialwick.png
+ - name: Social Followers
+ url: https://www.socialfollowers.uk/buy-tiktok-followers/
+ img: social_followers.png
+ - name: Nettcasino
+ url: https://www.nettcasino.com/
+ img: nettcasino.png
+ - name: Spelpressen
+ url: https://spelpressen.se/
+ img: spelpressen.png
+ - name: Casino Utan Svensk Licens
+ url: https://casino-utan-svensk-licens.com/
+ img: casino_utan_svensk_licens.png
+ - name: Outlook India
+ url: >-
+ https://www.outlookindia.com/outlook-spotlight/casinos-not-on-gamstop-uk-news-302214/
+ img: outlook_india.png
+bronze:
+ - name: Derek Pollard
+ url: https://polyglotengineer.com/derek.pollard
+ img: derek_pollard.png
+ - name: BGASoft
+ url: https://www.bgasoft.com
+ img: bgasoft.png
+ - name: RStudio
+ url: https://rstudio.com
+ img: rstudio.png
+ - name: Darkhorse Analytics
+ url: https://www.darkhorseanalytics.com/
+ img: darkhorse_analytics.png
+ - name: vuejs.de - German Vue Community
+ url: https://vuejs.de
+ img: vuejs_de___german_vue_community.svg
+ - name: Liip AG
+ url: https://www.liip.ch/en
+ img: liip_ag.png
+ - name: Bürkert Werke GmbH & Co KG
+ url: https://www.burkert.com
+ img: b_rkert_werke_gmbh___co_kg.png
+ - name: codefortynine
+ url: https://codefortynine.com
+ img: codefortynine.png
+ - name: Arcanite
+ url: https://arcanite.ch
+ img: arcanite.png
+platinum_china:
+ - name: CRMEB
+ url: http://github.crmeb.net/u/vue
+ img: crmeb.svg?v2
+ description: 开源电商系统
+ - name: MISBoot
+ url: https://vue.misboot.com/#/user/Login?from=vuejs
+ img: misboot.png?v3
+ description: 低代码开发平台
+# END SPONSORS
+redirects:
+ '/v2/api/index.html': '/api/'
+ '/v2/guide/index.html': '/guide/introduction.html'
+ '/v2/guide/installation.html': '/guide/quick-start.html'
+ '/v2/guide/instance.html': '/guide/essentials/application.html' # has page redirects
+ '/v2/guide/syntax.html': '/guide/essentials/template-syntax.html'
+ '/v2/guide/computed.html': '/guide/essentials/computed.html' # has page redirects
+ '/v2/guide/class-and-style.html': '/guide/essentials/class-and-style.html'
+ '/v2/guide/conditional.html': '/guide/essentials/conditional.html'
+ '/v2/guide/list.html': '/guide/essentials/list.html'
+ '/v2/guide/events.html': '/guide/essentials/event-handling.html'
+ '/v2/guide/forms.html': '/guide/essentials/forms.html'
+ '/v2/guide/components.html': '/guide/essentials/component-basics.html'
+ '/v2/guide/components-registration.html': '/guide/components/registration.html'
+ '/v2/guide/components-props.html': '/guide/components/props.html' # has page redirects
+ '/v2/guide/components-custom-events.html': '/guide/components/events.html'
+ '/v2/guide/components-slots.html': '/guide/components/slots.html'
+ '/v2/guide/components-dynamic-async.html': '/guide/built-ins/keep-alive.html' # has page redirects
+ '/v2/guide/transitions.html': '/guide/built-ins/transition.html' # has page redirects
+ '/v2/guide/transitioning-state.html': '/guide/extras/animation.html'
+ '/v2/guide/custom-directive.html': '/guide/reusability/custom-directives.html'
+ '/v2/guide/render-function.html': '/guide/extras/render-function.html'
+ '/v2/guide/plugins.html': '/guide/reusability/plugins.html'
+ '/v2/guide/single-file-components.html': '/guide/scaling-up/sfc.html'
+ '/v2/guide/testing.html': '/guide/scaling-up/testing.html'
+ '/v2/guide/typescript.html': '/guide/typescript/overview.html'
+ '/v2/guide/deployment.html': '/guide/best-practices/production-deployment.html'
+ '/v2/guide/routing.html': '/guide/scaling-up/routing.html'
+ '/v2/guide/state-management.html': '/guide/scaling-up/state-management.html'
+ '/v2/guide/ssr.html': '/guide/scaling-up/ssr.html'
+ '/v2/guide/security.html': '/guide/best-practices/security.html'
+ '/v2/guide/reactivity.html': '/guide/extras/reactivity-in-depth.html'
diff --git a/themes/vue/layout/icons/github-dark.ejs b/themes/vue/layout/icons/github-dark.ejs
index eb71a11da5..296fede1ec 100644
--- a/themes/vue/layout/icons/github-dark.ejs
+++ b/themes/vue/layout/icons/github-dark.ejs
@@ -1 +1 @@
-
GitHub Dark icon
+
GitHub Dark icon
diff --git a/themes/vue/layout/index.ejs b/themes/vue/layout/index.ejs
index aa01560739..efb5587336 100644
--- a/themes/vue/layout/index.ejs
+++ b/themes/vue/layout/index.ejs
@@ -1,94 +1,158 @@
-