mirror of
https://gitee.com/vuejs/vue.git
synced 2024-12-02 03:57:36 +08:00
Merge branch 'dev' into move_to_typescript
# Conflicts: # dist/vue.common.dev.js # dist/vue.common.prod.js # dist/vue.esm.browser.js # dist/vue.esm.browser.min.js # dist/vue.esm.js # dist/vue.js # dist/vue.min.js # dist/vue.runtime.common.dev.js # dist/vue.runtime.common.prod.js # dist/vue.runtime.esm.js # dist/vue.runtime.js # dist/vue.runtime.min.js # packages/vue-server-renderer/basic.js # packages/vue-server-renderer/build.dev.js # packages/vue-server-renderer/build.prod.js # packages/vue-server-renderer/client-plugin.js # packages/vue-server-renderer/server-plugin.js # packages/vue-template-compiler/browser.js # packages/vue-template-compiler/build.js # packages/weex-template-compiler/build.js # packages/weex-vue-framework/index.js # src/compiler/codegen/index.ts # src/core/components/keep-alive.ts # src/core/instance/lifecycle.js # src/core/instance/render-helpers/render-slot.ts # src/core/instance/state.ts # src/core/observer/watcher.ts # src/core/vdom/helpers/normalize-scoped-slots.ts # src/core/vdom/patch.ts # src/platforms/web/runtime/modules/events.ts # src/platforms/weex/entry-framework.ts # src/server/webpack-plugin/client.js # src/server/webpack-plugin/server.ts # src/server/webpack-plugin/util.ts # yarn.lock
This commit is contained in:
commit
da64b4a41f
10
.github/CONTRIBUTING.md
vendored
10
.github/CONTRIBUTING.md
vendored
@ -124,15 +124,7 @@ The default test script will do the following: lint with ESLint -> type check wi
|
||||
|
||||
## Financial Contribution
|
||||
|
||||
As a pure community-driven project without major corporate backing, we also welcome financial contributions via Patreon and OpenCollective.
|
||||
|
||||
- [Become a backer or sponsor on Patreon](https://www.patreon.com/evanyou)
|
||||
- [Become a backer or sponsor on OpenCollective](https://opencollective.com/vuejs)
|
||||
- [One-time donation via PayPal or crypto-currencies](https://vuejs.org/support-vuejs/#One-time-Donations)
|
||||
|
||||
### What's the difference between Patreon and OpenCollective funding?
|
||||
|
||||
Funds donated via Patreon go directly to support Evan You's full-time work on Vue.js. Funds donated via OpenCollective are managed with transparent expenses and will be used for compensating work and expenses for core team members or sponsoring community events. Your name/logo will receive proper recognition and exposure by donating on either platform.
|
||||
As a pure community-driven project without major corporate backing, we also welcome financial contributions via GitHub Sponsors and OpenCollective. Please consult the [Sponsor Page](https://vuejs.org/sponsor/) for more details.
|
||||
|
||||
## Credits
|
||||
|
||||
|
485
BACKERS.md
485
BACKERS.md
@ -1,488 +1,9 @@
|
||||
<h1 align="center">Sponsors & Backers</h1>
|
||||
|
||||
Vue.js is an MIT-licensed open source project. It's an independent project with its ongoing development made possible entirely thanks to the support by these awesome [backers](https://github.com/vuejs/vue/blob/dev/BACKERS.md). If you'd like to join them, please consider:
|
||||
|
||||
- [Become a backer or sponsor on Patreon](https://www.patreon.com/evanyou).
|
||||
- [Become a backer or sponsor on OpenCollective](https://opencollective.com/vuejs).
|
||||
- [One-time donation via PayPal or crypto-currencies.](https://vuejs.org/support-vuejs/#One-time-Donations)
|
||||
|
||||
#### What's the difference between Patreon and OpenCollective?
|
||||
|
||||
Funds donated via Patreon go directly to support Evan You's full-time work on Vue.js. Funds donated via OpenCollective are managed with transparent expenses and will be used for compensating work and expenses for core team members or sponsoring community events. Your name/logo will receive proper recognition and exposure by donating on either platform.
|
||||
|
||||
<br><br>
|
||||
|
||||
<h2 align="center">Special Sponsors</h2>
|
||||
|
||||
<!--special start-->
|
||||
Vue.js is an MIT-licensed open source project with its ongoing development made possible entirely by the support of the awesome sponsors and backers listed in this file. If you'd like to join them, please consider [ sponsor Vue's development](https://vuejs.org/sponsor/).
|
||||
|
||||
<p align="center">
|
||||
<a href="https://autocode.com/" target="_blank">
|
||||
<img width="260px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/autocode.svg?sanitize=true">
|
||||
<a target="_blank" href="https://sponsors.vuejs.org/backers.svg">
|
||||
<img alt="sponsors" src="https://sponsors.vuejs.org/backers.svg">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<!--special end-->
|
||||
|
||||
<h2 align="center">Platinum via Patreon</h2>
|
||||
|
||||
<!--platinum start-->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://vueschool.io/?utm_source=Vuejs.org&utm_medium=Banner&utm_campaign=Sponsored%20Banner&utm_content=V1" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vueschool.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://vehikl.com/" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vehikl.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://retool.com/?utm_source=sponsor&utm_campaign=vue" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/retool.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://passionatepeople.io/" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/passionate_people.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.storyblok.com" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/storyblok.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://ionicframework.com/vue?utm_source=partner&utm_medium=referral&utm_campaign=vuesponsorship&utm_content=vuedocs" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/ionic.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://nuxtjs.org/" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/nuxt.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--platinum end-->
|
||||
|
||||
<!--special-china start-->
|
||||
<h3 align="center">Platinum Sponsors (China)</h3>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="http://www.dcloud.io/?hmsr=vuejsorg&hmpl=&hmcu=&hmkw=&hmci=" target="_blank">
|
||||
<img width="177px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/dcloud.gif">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--special-china end-->
|
||||
|
||||
<h2 align="center">Platinum via OpenCollective</h2>
|
||||
|
||||
<a href="https://opencollective.com/vuejs/tiers/platinum-sponsors/0/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/platinum-sponsors/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/platinum-sponsors/1/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/platinum-sponsors/1/avatar.svg"></a>
|
||||
|
||||
<h2 align="center">Gold via Patreon</h2>
|
||||
|
||||
<!--gold start-->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.vuemastery.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vuemastery.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://laravel.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/laravel.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://htmlburger.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/html_burger.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.frontenddeveloperlove.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/frontendlove.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://neds.com.au/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/neds.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://icons8.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/icons_8.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://vuejobs.com/?ref=vuejs" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vuejobs.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://tidelift.com/subscription/npm/vue" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/tidelift.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.firesticktricks.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/firestick_tricks.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://intygrate.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/intygrate.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="http://en.shopware.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/shopware_ag.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.vpnranks.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vpnranks.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.bacancytechnology.com/hire-vuejs-developer" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/bacancy_technology.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.bestvpn.co/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/bestvpn_co.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.y8.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/y8.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://js.devexpress.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/devexpress.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://fastcoding.jp/javascript/ " target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/fastcoding_inc.svg?sanitize=true">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://usave.co.uk/utilities/broadband" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/usave.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.foo.software" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/foo.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://flatlogic.com/templates" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/flatlogic_templates.svg?sanitize=true">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="http://moovweb.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/moovweb.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://vpn-review.com/netflix-vpn" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vpn_review.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://cosmos.network/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/tendermint.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.okayhq.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/okay.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.vpsserver.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vpsserver_com.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://aussiecasinohex.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/aussiecasinohex.svg?sanitize=true">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://litslink.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/litslink.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://newicon.net" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/newicon.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://lowdefy.com?k=w432" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/lowdefy.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://quickbookstoolhub.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/quickbooks_tool_hub.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--gold end-->
|
||||
|
||||
<h2 align="center">Gold via OpenCollective</h2>
|
||||
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/0/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/0/avatar.svg" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/1/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/1/avatar.svg" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/2/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/2/avatar.svg" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/3/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/3/avatar.svg" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/4/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/4/avatar.svg" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/5/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/5/avatar.svg" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/6/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/6/avatar.svg" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/7/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/7/avatar.svg" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/8/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/8/avatar.svg" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/9/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/9/avatar.svg" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/10/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/10/avatar.svg" height="60px"></a>
|
||||
|
||||
<h2 align="center">Silver via Patreon</h2>
|
||||
|
||||
- Matt Mullenweg
|
||||
|
||||
<!--silver start-->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://roadster.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/roadster.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.inkoop.io" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/inkoop.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.thecasinodb.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/isolutions_uk_limited.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://teamextension.io" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/team_extension_north_america_inc.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://freebets.us" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/free_bets_us.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://betting.bet" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/betting_bet.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--silver end-->
|
||||
|
||||
<h4 align="center">Silver via OpenCollective</h4>
|
||||
|
||||
<a href="https://opencollective.com/vuejs/tiers/silver-sponsors/0/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/silver-sponsors/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/silver-sponsors/1/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/silver-sponsors/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/silver-sponsors/2/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/silver-sponsors/2/avatar.svg"></a>
|
||||
|
||||
<h2 align="center">Bronze via Patreon</h2>
|
||||
|
||||
<!--bronze start-->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.accelebrate.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/accelebrate.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://polyglotengineer.com/derek.pollard" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/derek_pollard.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.earthlink.ro" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/earthlink.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.webucator.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/webucator.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://memberful.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/memberful.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--bronze end-->
|
||||
|
||||
<h2 align="center">Bronze via OpenCollective</h2>
|
||||
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/0/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/0/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/1/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/1/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/2/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/2/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/3/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/3/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/4/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/4/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/5/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/5/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/6/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/6/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/7/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/7/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/8/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/8/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/9/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/9/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/10/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/10/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/11/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/11/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/12/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/12/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/13/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/13/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/14/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/14/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/15/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/15/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/16/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/16/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/17/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/17/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/18/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/18/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/19/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/19/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/20/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/20/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/21/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/21/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/22/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/22/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/23/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/23/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/24/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/24/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/25/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/25/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/26/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/26/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/27/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/27/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/28/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/28/avatar.svg"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/bronze-sponsors/29/website" target="_blank"><img src="https://opencollective.com/vuejs/tiers/bronze-sponsors/29/avatar.svg"></a>
|
||||
|
||||
<h2 align="center">Generous Backers via Patreon ($50+)</h2>
|
||||
|
||||
<!--50 start-->
|
||||
- Yoshitaka M
|
||||
- Peter Imburg
|
||||
- Sean Ferguson
|
||||
- Johnny Ray Austin
|
||||
- errorrik
|
||||
- Wasim Khamlichi
|
||||
<!--50 end-->
|
||||
|
||||
<h2 align="center">Backers via Patreon</h2>
|
||||
|
||||
<!--10 start-->
|
||||
- Sara McVey
|
||||
- Keisuke Kita
|
||||
- Alex Riviere
|
||||
- Thomas Sittig
|
||||
- WhereJuly
|
||||
- Fontis
|
||||
- Jack
|
||||
- Nick Carr
|
||||
- Artur Bańka
|
||||
- Traversy Media
|
||||
- Pierre Baron
|
||||
- Donghai Gai
|
||||
- Aleksander Figiel
|
||||
- Faizal Andyka
|
||||
- wickedwei
|
||||
- Sunny Yuen
|
||||
- Jules
|
||||
- Zeth Odderskov
|
||||
- Santi Sanchez Canals
|
||||
- Thomas Wiedemann
|
||||
- Nobuhide Esaki
|
||||
- Roy Segall
|
||||
- Allan McKernan
|
||||
- 琚致远
|
||||
- Diana Bergholz
|
||||
- Riki Fridrich
|
||||
- Alfonso Herrera
|
||||
- Bichinger Software & Consulting
|
||||
- username
|
||||
- Pierre Lebrun
|
||||
- Peter Matkovsky
|
||||
- 龙腾道
|
||||
- Nick Dandakis
|
||||
- Yusuke Kawabata
|
||||
- Shawn Wildermuth
|
||||
- Andrew Willis
|
||||
- Elon Hung
|
||||
- Роман Латкин
|
||||
- Juan Bermudez
|
||||
- Hannes Kochniß
|
||||
- Daniel Mattingley
|
||||
- Matt Sencenbaugh
|
||||
- Jaeyoung Lee
|
||||
- David Kaplan
|
||||
- David Ang
|
||||
- Wakana Seki
|
||||
- Jere Sjöroos
|
||||
- Donald Fischer
|
||||
- Eric
|
||||
- tyler madsen
|
||||
- Joe Gregory
|
||||
- Masahiro Tanaka
|
||||
- Tyler
|
||||
- IMGNRY
|
||||
- Jim Raden
|
||||
- Haim Yulzari
|
||||
- Anthony Estebe
|
||||
- Asaf Yishai
|
||||
- Jon Hobbs-Smith
|
||||
- Pierre Vanhulst
|
||||
- Zoran Knezevic
|
||||
- Luiz
|
||||
- Bernhard E. Reiter
|
||||
- Guy Gavergun
|
||||
- Matt Jones
|
||||
- Niannian Modisette
|
||||
- Matsumoto Takamasa
|
||||
- Barbara Liau
|
||||
- Wen-Tien Chang
|
||||
- Stephen Michael Hartley
|
||||
- Victor Tolbert
|
||||
- Lars Andreas Ness
|
||||
- Benjamin Listwon
|
||||
- Chris Calo
|
||||
<!--10 end-->
|
||||
|
||||
<h2 align="center">Backers via OpenCollective</h2>
|
||||
|
||||
<a href="https://opencollective.com/vuejs#backers" target="_blank"><img src="https://opencollective.com/vuejs/backers.svg?width=890"></a>
|
||||
|
295
README.md
295
README.md
@ -7,279 +7,21 @@
|
||||
<a href="https://www.npmjs.com/package/vue"><img src="https://img.shields.io/npm/v/vue.svg?sanitize=true" alt="Version"></a>
|
||||
<a href="https://www.npmjs.com/package/vue"><img src="https://img.shields.io/npm/l/vue.svg?sanitize=true" alt="License"></a>
|
||||
<a href="https://chat.vuejs.org/"><img src="https://img.shields.io/badge/chat-on%20discord-7289da.svg?sanitize=true" alt="Chat"></a>
|
||||
<br>
|
||||
<a href="https://app.saucelabs.com/builds/50f8372d79f743a3b25fb6ca4851ca4c"><img src="https://app.saucelabs.com/buildstatus/vuejs" alt="Build Status"></a>
|
||||
</p>
|
||||
|
||||
<h2 align="center">Supporting Vue.js</h2>
|
||||
## This repo is for Vue 2
|
||||
|
||||
Vue.js is an MIT-licensed open source project with its ongoing development made possible entirely by the support of these awesome [backers](https://github.com/vuejs/vue/blob/dev/BACKERS.md). If you'd like to join them, please consider:
|
||||
You are looking at the repository for Vue 2. The repo for Vue 3 is [vuejs/core](https://github.com/vuejs/core).
|
||||
|
||||
- [Become a backer or sponsor on Patreon](https://www.patreon.com/evanyou).
|
||||
- [Become a backer or sponsor on Open Collective](https://opencollective.com/vuejs).
|
||||
- [One-time donation via PayPal or crypto-currencies.](https://vuejs.org/support-vuejs/#One-time-Donations)
|
||||
## Sponsors
|
||||
|
||||
#### What's the difference between Patreon and OpenCollective?
|
||||
|
||||
Funds donated via Patreon go directly to support Evan You's full-time work on Vue.js. Funds donated via OpenCollective are managed with transparent expenses and will be used for compensating work and expenses for core team members or sponsoring community events. Your name/logo will receive proper recognition and exposure by donating on either platform.
|
||||
|
||||
<h3 align="center">Special Sponsors</h3>
|
||||
<!--special start-->
|
||||
Vue.js is an MIT-licensed open source project with its ongoing development made possible entirely by the support of these awesome [backers](https://github.com/vuejs/core/blob/main/BACKERS.md). If you'd like to join them, please consider [ sponsor Vue's development](https://vuejs.org/sponsor/).
|
||||
|
||||
<p align="center">
|
||||
<a href="https://autocode.com/" target="_blank">
|
||||
<img width="260px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/autocode.svg?sanitize=true">
|
||||
<a target="_blank" href="https://vuejs.org/sponsor/">
|
||||
<img alt="sponsors" src="https://sponsors.vuejs.org/sponsors.svg">
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<!--special end-->
|
||||
|
||||
<h3 align="center">Platinum Sponsors</h3>
|
||||
|
||||
<!--platinum start-->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://vueschool.io/?utm_source=Vuejs.org&utm_medium=Banner&utm_campaign=Sponsored%20Banner&utm_content=V1" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vueschool.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://vehikl.com/" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vehikl.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://retool.com/?utm_source=sponsor&utm_campaign=vue" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/retool.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://passionatepeople.io/" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/passionate_people.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.storyblok.com" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/storyblok.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://ionicframework.com/vue?utm_source=partner&utm_medium=referral&utm_campaign=vuesponsorship&utm_content=vuedocs" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/ionic.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://nuxtjs.org/" target="_blank">
|
||||
<img width="222px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/nuxt.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--platinum end-->
|
||||
|
||||
<!--special-china start-->
|
||||
<h3 align="center">Platinum Sponsors (China)</h3>
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="http://www.dcloud.io/?hmsr=vuejsorg&hmpl=&hmcu=&hmkw=&hmci=" target="_blank">
|
||||
<img width="177px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/dcloud.gif">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--special-china end-->
|
||||
|
||||
<h3 align="center">Gold Sponsors</h3>
|
||||
|
||||
<!--gold start-->
|
||||
<table>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.vuemastery.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vuemastery.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://laravel.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/laravel.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://htmlburger.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/html_burger.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.frontenddeveloperlove.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/frontendlove.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://neds.com.au/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/neds.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://icons8.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/icons_8.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://vuejobs.com/?ref=vuejs" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vuejobs.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://tidelift.com/subscription/npm/vue" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/tidelift.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.firesticktricks.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/firestick_tricks.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://intygrate.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/intygrate.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="http://en.shopware.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/shopware_ag.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.vpnranks.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vpnranks.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.bacancytechnology.com/hire-vuejs-developer" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/bacancy_technology.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.bestvpn.co/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/bestvpn_co.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.y8.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/y8.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://js.devexpress.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/devexpress.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://fastcoding.jp/javascript/ " target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/fastcoding_inc.svg?sanitize=true">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://usave.co.uk/utilities/broadband" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/usave.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.foo.software" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/foo.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://flatlogic.com/templates" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/flatlogic_templates.svg?sanitize=true">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="http://moovweb.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/moovweb.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://vpn-review.com/netflix-vpn" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vpn_review.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://cosmos.network/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/tendermint.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.okayhq.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/okay.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
<tr>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://www.vpsserver.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/vpsserver_com.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://aussiecasinohex.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/aussiecasinohex.svg?sanitize=true">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://litslink.com" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/litslink.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://newicon.net" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/newicon.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://lowdefy.com?k=w432" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/lowdefy.png">
|
||||
</a>
|
||||
</td>
|
||||
<td align="center" valign="middle">
|
||||
<a href="https://quickbookstoolhub.com/" target="_blank">
|
||||
<img width="148px" src="https://raw.githubusercontent.com/vuejs/vuejs.org/master/themes/vue/source/images/quickbooks_tool_hub.png">
|
||||
</a>
|
||||
</td>
|
||||
</tr><tr></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<!--gold end-->
|
||||
|
||||
<h3 align="center">Sponsors via <a href="https://opencollective.com/vuejs">Open Collective</a></h3>
|
||||
|
||||
<h4 align="center">Platinum</h4>
|
||||
|
||||
<a href="https://opencollective.com/vuejs/tiers/platinum-sponsors/0/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/platinum-sponsors/0/avatar.svg?sanitize=true"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/platinum-sponsors/1/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/platinum-sponsors/1/avatar.svg?sanitize=true"></a>
|
||||
|
||||
<h4 align="center">Gold</h4>
|
||||
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/0/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/0/avatar.svg?sanitize=true" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/1/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/1/avatar.svg?sanitize=true" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/2/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/2/avatar.svg?sanitize=true" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/3/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/3/avatar.svg?sanitize=true" height="60px"></a>
|
||||
<a href="https://opencollective.com/vuejs/tiers/gold-sponsors/4/website" target="_blank" rel="noopener noreferrer"><img src="https://opencollective.com/vuejs/tiers/gold-sponsors/4/avatar.svg?sanitize=true" height="60px"></a>
|
||||
|
||||
---
|
||||
|
||||
@ -293,16 +35,16 @@ Vue.js supports all browsers that are [ES5-compliant](https://kangax.github.io/c
|
||||
|
||||
## Ecosystem
|
||||
|
||||
| Project | Status | Description |
|
||||
|---------|--------|-------------|
|
||||
| [vue-router] | [![vue-router-status]][vue-router-package] | Single-page application routing |
|
||||
| [vuex] | [![vuex-status]][vuex-package] | Large-scale state management |
|
||||
| [vue-cli] | [![vue-cli-status]][vue-cli-package] | Project scaffolding |
|
||||
| [vue-loader] | [![vue-loader-status]][vue-loader-package] | Single File Component (`*.vue` file) loader for webpack |
|
||||
| [vue-server-renderer] | [![vue-server-renderer-status]][vue-server-renderer-package] | Server-side rendering support |
|
||||
| [vue-class-component] | [![vue-class-component-status]][vue-class-component-package] | TypeScript decorator for a class-based API |
|
||||
| [vue-rx] | [![vue-rx-status]][vue-rx-package] | RxJS integration |
|
||||
| [vue-devtools] | [![vue-devtools-status]][vue-devtools-package] | Browser DevTools extension |
|
||||
| Project | Status | Description |
|
||||
| --------------------- | ------------------------------------------------------------ | ------------------------------------------------------- |
|
||||
| [vue-router] | [![vue-router-status]][vue-router-package] | Single-page application routing |
|
||||
| [vuex] | [![vuex-status]][vuex-package] | Large-scale state management |
|
||||
| [vue-cli] | [![vue-cli-status]][vue-cli-package] | Project scaffolding |
|
||||
| [vue-loader] | [![vue-loader-status]][vue-loader-package] | Single File Component (`*.vue` file) loader for webpack |
|
||||
| [vue-server-renderer] | [![vue-server-renderer-status]][vue-server-renderer-package] | Server-side rendering support |
|
||||
| [vue-class-component] | [![vue-class-component-status]][vue-class-component-package] | TypeScript decorator for a class-based API |
|
||||
| [vue-rx] | [![vue-rx-status]][vue-rx-package] | RxJS integration |
|
||||
| [vue-devtools] | [![vue-devtools-status]][vue-devtools-package] | Browser DevTools extension |
|
||||
|
||||
[vue-router]: https://github.com/vuejs/vue-router
|
||||
[vuex]: https://github.com/vuejs/vuex
|
||||
@ -311,8 +53,7 @@ Vue.js supports all browsers that are [ES5-compliant](https://kangax.github.io/c
|
||||
[vue-server-renderer]: https://github.com/vuejs/vue/tree/dev/packages/vue-server-renderer
|
||||
[vue-class-component]: https://github.com/vuejs/vue-class-component
|
||||
[vue-rx]: https://github.com/vuejs/vue-rx
|
||||
[vue-devtools]: https://github.com/vuejs/vue-devtools
|
||||
|
||||
[vue-devtools]: https://github.com/vuejs/vue-devtools
|
||||
[vue-router-status]: https://img.shields.io/npm/v/vue-router.svg
|
||||
[vuex-status]: https://img.shields.io/npm/v/vuex.svg
|
||||
[vue-cli-status]: https://img.shields.io/npm/v/@vue/cli.svg
|
||||
@ -321,7 +62,6 @@ Vue.js supports all browsers that are [ES5-compliant](https://kangax.github.io/c
|
||||
[vue-class-component-status]: https://img.shields.io/npm/v/vue-class-component.svg
|
||||
[vue-rx-status]: https://img.shields.io/npm/v/vue-rx.svg
|
||||
[vue-devtools-status]: https://img.shields.io/chrome-web-store/v/nhdogjmejiglipccpnnnanhbledajbpd.svg
|
||||
|
||||
[vue-router-package]: https://npmjs.com/package/vue-router
|
||||
[vuex-package]: https://npmjs.com/package/vuex
|
||||
[vue-cli-package]: https://npmjs.com/package/@vue/cli
|
||||
@ -361,7 +101,6 @@ Thank you to all the people who already contributed to Vue!
|
||||
|
||||
<a href="https://github.com/vuejs/vue/graphs/contributors"><img src="https://opencollective.com/vuejs/contributors.svg?width=890" /></a>
|
||||
|
||||
|
||||
## License
|
||||
|
||||
[MIT](https://opensource.org/licenses/MIT)
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vue",
|
||||
"version": "2.6.12",
|
||||
"version": "2.6.14",
|
||||
"description": "Reactive, component-oriented view layer for modern web interfaces.",
|
||||
"main": "dist/vue.runtime.common.js",
|
||||
"module": "dist/vue.runtime.esm.js",
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because one or more lines are too long
@ -1,85 +1,124 @@
|
||||
'use strict';
|
||||
|
||||
var isJS = function (file) { return /\.js(\?[^.]+)?$/.test(file); };
|
||||
|
||||
var isCSS = function (file) { return /\.css(\?[^.]+)?$/.test(file); };
|
||||
|
||||
var ref = require('chalk');
|
||||
var red = ref.red;
|
||||
var yellow = ref.yellow;
|
||||
var webpack = require('webpack');
|
||||
|
||||
var prefix = "[vue-server-renderer-webpack-plugin]";
|
||||
(exports.warn = function (msg) { return console.error(red((prefix + " " + msg + "\n"))); });
|
||||
(exports.tip = function (msg) { return console.log(yellow((prefix + " " + msg + "\n"))); });
|
||||
var onEmit = function (compiler, name, hook) {
|
||||
if (compiler.hooks) {
|
||||
// Webpack >= 4.0.0
|
||||
compiler.hooks.emit.tapAsync(name, hook);
|
||||
}
|
||||
else {
|
||||
// Webpack < 4.0.0
|
||||
compiler.plugin('emit', hook);
|
||||
}
|
||||
var warn = exports.warn = function (msg) { return console.error(red((prefix + " " + msg + "\n"))); };
|
||||
var tip = exports.tip = function (msg) { return console.log(yellow((prefix + " " + msg + "\n"))); };
|
||||
|
||||
var isWebpack5 = !!(webpack.version && webpack.version[0] > 4);
|
||||
|
||||
var onEmit = function (compiler, name, stageName, hook) {
|
||||
if (isWebpack5) {
|
||||
// Webpack >= 5.0.0
|
||||
compiler.hooks.compilation.tap(name, function (compilation) {
|
||||
if (compilation.compiler !== compiler) {
|
||||
// Ignore child compilers
|
||||
return
|
||||
}
|
||||
var stage = webpack.Compilation[stageName];
|
||||
compilation.hooks.processAssets.tapAsync({ name: name, stage: stage }, function (assets, cb) {
|
||||
hook(compilation, cb);
|
||||
});
|
||||
});
|
||||
} else if (compiler.hooks) {
|
||||
// Webpack >= 4.0.0
|
||||
compiler.hooks.emit.tapAsync(name, hook);
|
||||
} else {
|
||||
// Webpack < 4.0.0
|
||||
compiler.plugin('emit', hook);
|
||||
}
|
||||
};
|
||||
|
||||
var stripModuleIdHash = function (id) {
|
||||
if (isWebpack5) {
|
||||
// Webpack >= 5.0.0
|
||||
return id.replace(/\|\w+$/, '')
|
||||
}
|
||||
// Webpack < 5.0.0
|
||||
return id.replace(/\s\w+$/, '')
|
||||
};
|
||||
|
||||
var getAssetName = function (asset) {
|
||||
if (typeof asset === 'string') {
|
||||
return asset
|
||||
}
|
||||
return asset.name
|
||||
};
|
||||
|
||||
var hash = require('hash-sum');
|
||||
var uniq = require('lodash.uniq');
|
||||
var VueSSRClientPlugin = function VueSSRClientPlugin(options) {
|
||||
if ( options === void 0 ) options = {};
|
||||
|
||||
//@ts-expect-error
|
||||
this.options = Object.assign({
|
||||
filename: 'vue-ssr-client-manifest.json',
|
||||
}, options);
|
||||
var VueSSRClientPlugin = function VueSSRClientPlugin (options) {
|
||||
if ( options === void 0 ) options = {};
|
||||
|
||||
this.options = Object.assign({
|
||||
filename: 'vue-ssr-client-manifest.json'
|
||||
}, options);
|
||||
};
|
||||
|
||||
VueSSRClientPlugin.prototype.apply = function apply (compiler) {
|
||||
var this$1 = this;
|
||||
var this$1 = this;
|
||||
|
||||
onEmit(compiler, 'vue-client-plugin', function (compilation, cb) {
|
||||
var stats = compilation.getStats().toJson();
|
||||
var allFiles = uniq(stats.assets.map(function (a) { return a.name; }));
|
||||
var initialFiles = uniq(Object.keys(stats.entrypoints)
|
||||
.map(function (name) { return stats.entrypoints[name].assets; })
|
||||
.reduce(function (assets, all) { return all.concat(assets); }, [])
|
||||
.filter(function (file) { return isJS(file) || isCSS(file); }));
|
||||
var asyncFiles = allFiles
|
||||
.filter(function (file) { return isJS(file) || isCSS(file); })
|
||||
.filter(function (file) { return initialFiles.indexOf(file) < 0; });
|
||||
var manifest = {
|
||||
publicPath: stats.publicPath,
|
||||
all: allFiles,
|
||||
initial: initialFiles,
|
||||
async: asyncFiles,
|
||||
modules: {
|
||||
/* [identifier: string]: Array<index: number> */
|
||||
},
|
||||
};
|
||||
var assetModules = stats.modules.filter(function (m) { return m.assets.length; });
|
||||
var fileToIndex = function (file) { return manifest.all.indexOf(file); };
|
||||
stats.modules.forEach(function (m) {
|
||||
// ignore modules duplicated in multiple chunks
|
||||
if (m.chunks.length === 1) {
|
||||
var cid = m.chunks[0];
|
||||
var chunk = stats.chunks.find(function (c) { return c.id === cid; });
|
||||
if (!chunk || !chunk.files) {
|
||||
return;
|
||||
}
|
||||
var id = m.identifier.replace(/\s\w+$/, ''); // remove appended hash
|
||||
var files = (manifest.modules[hash(id)] = chunk.files.map(fileToIndex));
|
||||
// find all asset modules associated with the same chunk
|
||||
assetModules.forEach(function (m) {
|
||||
if (m.chunks.some(function (id) { return id === cid; })) {
|
||||
files.push.apply(files, m.assets.map(fileToIndex));
|
||||
}
|
||||
});
|
||||
}
|
||||
var stage = 'PROCESS_ASSETS_STAGE_ADDITIONAL';
|
||||
onEmit(compiler, 'vue-client-plugin', stage, function (compilation, cb) {
|
||||
var stats = compilation.getStats().toJson();
|
||||
|
||||
var allFiles = uniq(stats.assets
|
||||
.map(function (a) { return a.name; }));
|
||||
|
||||
var initialFiles = uniq(Object.keys(stats.entrypoints)
|
||||
.map(function (name) { return stats.entrypoints[name].assets; })
|
||||
.reduce(function (assets, all) { return all.concat(assets); }, [])
|
||||
.map(getAssetName)
|
||||
.filter(function (file) { return isJS(file) || isCSS(file); }));
|
||||
|
||||
var asyncFiles = allFiles
|
||||
.filter(function (file) { return isJS(file) || isCSS(file); })
|
||||
.filter(function (file) { return initialFiles.indexOf(file) < 0; });
|
||||
|
||||
var manifest = {
|
||||
publicPath: stats.publicPath,
|
||||
all: allFiles,
|
||||
initial: initialFiles,
|
||||
async: asyncFiles,
|
||||
modules: { /* [identifier: string]: Array<index: number> */ }
|
||||
};
|
||||
|
||||
var assetModules = stats.modules.filter(function (m) { return m.assets.length; });
|
||||
var fileToIndex = function (asset) { return manifest.all.indexOf(getAssetName(asset)); };
|
||||
stats.modules.forEach(function (m) {
|
||||
// ignore modules duplicated in multiple chunks
|
||||
if (m.chunks.length === 1) {
|
||||
var cid = m.chunks[0];
|
||||
var chunk = stats.chunks.find(function (c) { return c.id === cid; });
|
||||
if (!chunk || !chunk.files) {
|
||||
return
|
||||
}
|
||||
var id = stripModuleIdHash(m.identifier);
|
||||
var files = manifest.modules[hash(id)] = chunk.files.map(fileToIndex);
|
||||
// find all asset modules associated with the same chunk
|
||||
assetModules.forEach(function (m) {
|
||||
if (m.chunks.some(function (id) { return id === cid; })) {
|
||||
files.push.apply(files, m.assets.map(fileToIndex));
|
||||
}
|
||||
});
|
||||
var json = JSON.stringify(manifest, null, 2);
|
||||
//@ts-expect-error
|
||||
compilation.assets[this$1.options.filename] = {
|
||||
source: function () { return json; },
|
||||
size: function () { return json.length; },
|
||||
};
|
||||
cb();
|
||||
}
|
||||
});
|
||||
|
||||
var json = JSON.stringify(manifest, null, 2);
|
||||
compilation.assets[this$1.options.filename] = {
|
||||
source: function () { return json; },
|
||||
size: function () { return json.length; }
|
||||
};
|
||||
cb();
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = VueSSRClientPlugin;
|
||||
module.exports = VueSSRClientPlugin;
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vue-server-renderer",
|
||||
"version": "2.6.12",
|
||||
"version": "2.6.14",
|
||||
"description": "server renderer for Vue 2.0",
|
||||
"main": "index.js",
|
||||
"types": "types/index.d.ts",
|
||||
|
@ -1,90 +1,142 @@
|
||||
'use strict';
|
||||
|
||||
/* */
|
||||
|
||||
var isJS = function (file) { return /\.js(\?[^.]+)?$/.test(file); };
|
||||
|
||||
var ref = require('chalk');
|
||||
var red = ref.red;
|
||||
var yellow = ref.yellow;
|
||||
var webpack = require('webpack');
|
||||
|
||||
var prefix = "[vue-server-renderer-webpack-plugin]";
|
||||
var warn = (exports.warn = function (msg) { return console.error(red((prefix + " " + msg + "\n"))); });
|
||||
var tip = (exports.tip = function (msg) { return console.log(yellow((prefix + " " + msg + "\n"))); });
|
||||
var warn = exports.warn = function (msg) { return console.error(red((prefix + " " + msg + "\n"))); };
|
||||
var tip = exports.tip = function (msg) { return console.log(yellow((prefix + " " + msg + "\n"))); };
|
||||
|
||||
var isWebpack5 = !!(webpack.version && webpack.version[0] > 4);
|
||||
|
||||
var validate = function (compiler) {
|
||||
if (compiler.options.target !== 'node') {
|
||||
warn('webpack config `target` should be "node".');
|
||||
}
|
||||
if (compiler.options.output &&
|
||||
compiler.options.output.libraryTarget !== 'commonjs2') {
|
||||
warn('webpack config `output.libraryTarget` should be "commonjs2".');
|
||||
}
|
||||
if (!compiler.options.externals) {
|
||||
tip('It is recommended to externalize dependencies in the server build for ' +
|
||||
'better build performance.');
|
||||
}
|
||||
};
|
||||
var onEmit = function (compiler, name, hook) {
|
||||
if (compiler.hooks) {
|
||||
// Webpack >= 4.0.0
|
||||
compiler.hooks.emit.tapAsync(name, hook);
|
||||
}
|
||||
else {
|
||||
// Webpack < 4.0.0
|
||||
compiler.plugin('emit', hook);
|
||||
if (compiler.options.target !== 'node') {
|
||||
warn('webpack config `target` should be "node".');
|
||||
}
|
||||
|
||||
if (compiler.options.output) {
|
||||
if (compiler.options.output.library) {
|
||||
// Webpack >= 5.0.0
|
||||
if (compiler.options.output.library.type !== 'commonjs2') {
|
||||
warn('webpack config `output.library.type` should be "commonjs2".');
|
||||
}
|
||||
} else if (compiler.options.output.libraryTarget !== 'commonjs2') {
|
||||
// Webpack < 5.0.0
|
||||
warn('webpack config `output.libraryTarget` should be "commonjs2".');
|
||||
}
|
||||
}
|
||||
|
||||
if (!compiler.options.externals) {
|
||||
tip(
|
||||
'It is recommended to externalize dependencies in the server build for ' +
|
||||
'better build performance.'
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
var VueSSRServerPlugin = function VueSSRServerPlugin(options) {
|
||||
if ( options === void 0 ) options = {};
|
||||
|
||||
//@ts-expect-error
|
||||
this.options = Object.assign({
|
||||
filename: 'vue-ssr-server-bundle.json',
|
||||
}, options);
|
||||
};
|
||||
VueSSRServerPlugin.prototype.apply = function apply (compiler) {
|
||||
var this$1 = this;
|
||||
|
||||
validate(compiler);
|
||||
onEmit(compiler, 'vue-server-plugin', function (compilation, cb) {
|
||||
var stats = compilation.getStats().toJson();
|
||||
var entryName = Object.keys(stats.entrypoints)[0];
|
||||
var entryInfo = stats.entrypoints[entryName];
|
||||
if (!entryInfo) {
|
||||
// #5553
|
||||
return cb();
|
||||
}
|
||||
var entryAssets = entryInfo.assets.filter(isJS);
|
||||
if (entryAssets.length > 1) {
|
||||
throw new Error("Server-side bundle should have one single entry file. " +
|
||||
"Avoid using CommonsChunkPlugin in the server config.");
|
||||
}
|
||||
var entry = entryAssets[0];
|
||||
if (!entry || typeof entry !== 'string') {
|
||||
throw new Error(("Entry \"" + entryName + "\" not found. Did you specify the correct entry option?"));
|
||||
}
|
||||
var bundle = {
|
||||
entry: entry,
|
||||
files: {},
|
||||
maps: {},
|
||||
};
|
||||
stats.assets.forEach(function (asset) {
|
||||
if (isJS(asset.name)) {
|
||||
bundle.files[asset.name] = compilation.assets[asset.name].source();
|
||||
}
|
||||
else if (asset.name.match(/\.js\.map$/)) {
|
||||
bundle.maps[asset.name.replace(/\.map$/, '')] = JSON.parse(compilation.assets[asset.name].source());
|
||||
}
|
||||
// do not emit anything else for server
|
||||
delete compilation.assets[asset.name];
|
||||
});
|
||||
var json = JSON.stringify(bundle, null, 2);
|
||||
//@ts-expect-error
|
||||
var filename = this$1.options.filename;
|
||||
compilation.assets[filename] = {
|
||||
source: function () { return json; },
|
||||
size: function () { return json.length; },
|
||||
};
|
||||
cb();
|
||||
var onEmit = function (compiler, name, stageName, hook) {
|
||||
if (isWebpack5) {
|
||||
// Webpack >= 5.0.0
|
||||
compiler.hooks.compilation.tap(name, function (compilation) {
|
||||
if (compilation.compiler !== compiler) {
|
||||
// Ignore child compilers
|
||||
return
|
||||
}
|
||||
var stage = webpack.Compilation[stageName];
|
||||
compilation.hooks.processAssets.tapAsync({ name: name, stage: stage }, function (assets, cb) {
|
||||
hook(compilation, cb);
|
||||
});
|
||||
});
|
||||
} else if (compiler.hooks) {
|
||||
// Webpack >= 4.0.0
|
||||
compiler.hooks.emit.tapAsync(name, hook);
|
||||
} else {
|
||||
// Webpack < 4.0.0
|
||||
compiler.plugin('emit', hook);
|
||||
}
|
||||
};
|
||||
|
||||
var getAssetName = function (asset) {
|
||||
if (typeof asset === 'string') {
|
||||
return asset
|
||||
}
|
||||
return asset.name
|
||||
};
|
||||
|
||||
var VueSSRServerPlugin = function VueSSRServerPlugin (options) {
|
||||
if ( options === void 0 ) options = {};
|
||||
|
||||
this.options = Object.assign({
|
||||
filename: 'vue-ssr-server-bundle.json'
|
||||
}, options);
|
||||
};
|
||||
|
||||
VueSSRServerPlugin.prototype.apply = function apply (compiler) {
|
||||
var this$1 = this;
|
||||
|
||||
validate(compiler);
|
||||
|
||||
var stage = 'PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER';
|
||||
onEmit(compiler, 'vue-server-plugin', stage, function (compilation, cb) {
|
||||
var stats = compilation.getStats().toJson();
|
||||
var entryName = Object.keys(stats.entrypoints)[0];
|
||||
var entryInfo = stats.entrypoints[entryName];
|
||||
|
||||
if (!entryInfo) {
|
||||
// #5553
|
||||
return cb()
|
||||
}
|
||||
|
||||
var entryAssets = entryInfo.assets
|
||||
.map(getAssetName)
|
||||
.filter(isJS);
|
||||
|
||||
if (entryAssets.length > 1) {
|
||||
throw new Error(
|
||||
"Server-side bundle should have one single entry file. " +
|
||||
"Avoid using CommonsChunkPlugin in the server config."
|
||||
)
|
||||
}
|
||||
|
||||
var entry = entryAssets[0];
|
||||
if (!entry || typeof entry !== 'string') {
|
||||
throw new Error(
|
||||
("Entry \"" + entryName + "\" not found. Did you specify the correct entry option?")
|
||||
)
|
||||
}
|
||||
|
||||
var bundle = {
|
||||
entry: entry,
|
||||
files: {},
|
||||
maps: {}
|
||||
};
|
||||
|
||||
Object.keys(compilation.assets).forEach(function (name) {
|
||||
if (isJS(name)) {
|
||||
bundle.files[name] = compilation.assets[name].source();
|
||||
} else if (name.match(/\.js\.map$/)) {
|
||||
bundle.maps[name.replace(/\.map$/, '')] = JSON.parse(compilation.assets[name].source());
|
||||
}
|
||||
// do not emit anything else for server
|
||||
delete compilation.assets[name];
|
||||
});
|
||||
|
||||
var json = JSON.stringify(bundle, null, 2);
|
||||
var filename = this$1.options.filename;
|
||||
|
||||
compilation.assets[filename] = {
|
||||
source: function () { return json; },
|
||||
size: function () { return json.length; }
|
||||
};
|
||||
|
||||
cb();
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = VueSSRServerPlugin;
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "vue-template-compiler",
|
||||
"version": "2.6.12",
|
||||
"version": "2.6.14",
|
||||
"description": "template compiler for Vue 2.0",
|
||||
"main": "index.js",
|
||||
"unpkg": "browser.js",
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -2,133 +2,156 @@
|
||||
|
||||
Object.defineProperty(exports, '__esModule', { value: true });
|
||||
|
||||
/* */
|
||||
|
||||
// this will be preserved during build
|
||||
// $flow-disable-line
|
||||
var VueFactory = require('./factory');
|
||||
|
||||
var instanceOptions = {};
|
||||
|
||||
/**
|
||||
* Create instance context.
|
||||
*/
|
||||
function createInstanceContext(instanceId, runtimeContext, data) {
|
||||
if (data === void 0) { data = {}; }
|
||||
var weex = runtimeContext.weex;
|
||||
var instance = (instanceOptions[instanceId] = {
|
||||
instanceId: instanceId,
|
||||
config: weex.config,
|
||||
document: weex.document,
|
||||
data: data,
|
||||
});
|
||||
// Each instance has a independent `Vue` module instance
|
||||
var Vue = (instance.Vue = createVueModuleInstance(instanceId, weex));
|
||||
// DEPRECATED
|
||||
var timerAPIs = getInstanceTimer(instanceId, weex.requireModule);
|
||||
var instanceContext = Object.assign({ Vue: Vue }, timerAPIs);
|
||||
Object.freeze(instanceContext);
|
||||
return instanceContext;
|
||||
function createInstanceContext (
|
||||
instanceId,
|
||||
runtimeContext,
|
||||
data
|
||||
) {
|
||||
if ( data === void 0 ) data = {};
|
||||
|
||||
var weex = runtimeContext.weex;
|
||||
var instance = instanceOptions[instanceId] = {
|
||||
instanceId: instanceId,
|
||||
config: weex.config,
|
||||
document: weex.document,
|
||||
data: data
|
||||
};
|
||||
|
||||
// Each instance has an independent `Vue` module instance
|
||||
var Vue = instance.Vue = createVueModuleInstance(instanceId, weex);
|
||||
|
||||
// DEPRECATED
|
||||
var timerAPIs = getInstanceTimer(instanceId, weex.requireModule);
|
||||
|
||||
var instanceContext = Object.assign({ Vue: Vue }, timerAPIs);
|
||||
Object.freeze(instanceContext);
|
||||
return instanceContext
|
||||
}
|
||||
|
||||
/**
|
||||
* Destroy an instance with id. It will make sure all memory of
|
||||
* this instance released and no more leaks.
|
||||
*/
|
||||
function destroyInstance(instanceId) {
|
||||
var instance = instanceOptions[instanceId];
|
||||
//@ts-expect-error
|
||||
if (instance && instance.app instanceof instance.Vue) {
|
||||
try {
|
||||
instance.app.$destroy();
|
||||
instance.document.destroy();
|
||||
}
|
||||
catch (e) { }
|
||||
//@ts-expect-error
|
||||
delete instance.document;
|
||||
delete instance.app;
|
||||
}
|
||||
delete instanceOptions[instanceId];
|
||||
function destroyInstance (instanceId) {
|
||||
var instance = instanceOptions[instanceId];
|
||||
if (instance && instance.app instanceof instance.Vue) {
|
||||
try {
|
||||
instance.app.$destroy();
|
||||
instance.document.destroy();
|
||||
} catch (e) {}
|
||||
delete instance.document;
|
||||
delete instance.app;
|
||||
}
|
||||
delete instanceOptions[instanceId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Refresh an instance with id and new top-level component data.
|
||||
* It will use `Vue.set` on all keys of the new data. So it's better
|
||||
* define all possible meaningful keys when instance created.
|
||||
*/
|
||||
function refreshInstance(instanceId, data) {
|
||||
var instance = instanceOptions[instanceId];
|
||||
//@ts-expect-error
|
||||
if (!instance || !(instance.app instanceof instance.Vue)) {
|
||||
return new Error("refreshInstance: instance " + instanceId + " not found!");
|
||||
function refreshInstance (
|
||||
instanceId,
|
||||
data
|
||||
) {
|
||||
var instance = instanceOptions[instanceId];
|
||||
if (!instance || !(instance.app instanceof instance.Vue)) {
|
||||
return new Error(("refreshInstance: instance " + instanceId + " not found!"))
|
||||
}
|
||||
if (instance.Vue && instance.Vue.set) {
|
||||
for (var key in data) {
|
||||
instance.Vue.set(instance.app, key, data[key]);
|
||||
}
|
||||
if (instance.Vue && instance.Vue.set) {
|
||||
for (var key in data) {
|
||||
instance.Vue.set(instance.app, key, data[key]);
|
||||
}
|
||||
}
|
||||
// Finally `refreshFinish` signal needed.
|
||||
instance.document.taskCenter.send('dom', { action: 'refreshFinish' }, []);
|
||||
}
|
||||
// Finally `refreshFinish` signal needed.
|
||||
instance.document.taskCenter.send('dom', { action: 'refreshFinish' }, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a fresh instance of Vue for each Weex instance.
|
||||
*/
|
||||
function createVueModuleInstance(instanceId, weex) {
|
||||
var exports = {};
|
||||
VueFactory(exports, weex.document);
|
||||
//@ts-expect-error
|
||||
var Vue = exports.Vue;
|
||||
var instance = instanceOptions[instanceId];
|
||||
// patch reserved tag detection to account for dynamically registered
|
||||
// components
|
||||
var weexRegex = /^weex:/i;
|
||||
var isReservedTag = Vue.config.isReservedTag || (function () { return false; });
|
||||
var isRuntimeComponent = Vue.config.isRuntimeComponent || (function () { return false; });
|
||||
Vue.config.isReservedTag = function (name) {
|
||||
return ((!isRuntimeComponent(name) && weex.supports("@component/" + name)) ||
|
||||
isReservedTag(name) ||
|
||||
weexRegex.test(name));
|
||||
};
|
||||
Vue.config.parsePlatformTagName = function (name) { return name.replace(weexRegex, ''); };
|
||||
// expose weex-specific info
|
||||
Vue.prototype.$instanceId = instanceId;
|
||||
Vue.prototype.$document = instance.document;
|
||||
// expose weex native module getter on subVue prototype so that
|
||||
// vdom runtime modules can access native modules via vnode.context
|
||||
Vue.prototype.$requireWeexModule = weex.requireModule;
|
||||
// Hack `Vue` behavior to handle instance information and data
|
||||
// before root component created.
|
||||
Vue.mixin({
|
||||
beforeCreate: function () {
|
||||
var options = this.$options;
|
||||
// root component (vm)
|
||||
if (options.el) {
|
||||
// set external data of instance
|
||||
var dataOption = options.data;
|
||||
var internalData = (typeof dataOption === 'function' ? dataOption() : dataOption) || {};
|
||||
options.data = Object.assign(internalData, instance.data);
|
||||
// record instance by id
|
||||
instance.app = this;
|
||||
}
|
||||
},
|
||||
mounted: function () {
|
||||
var options = this.$options;
|
||||
// root component (vm)
|
||||
if (options.el && weex.document && instance.app === this) {
|
||||
try {
|
||||
// Send "createFinish" signal to native.
|
||||
weex.document.taskCenter.send('dom', { action: 'createFinish' }, []);
|
||||
}
|
||||
catch (e) { }
|
||||
}
|
||||
},
|
||||
});
|
||||
/**
|
||||
* @deprecated Just instance variable `weex.config`
|
||||
* Get instance config.
|
||||
* @return {object}
|
||||
*/
|
||||
Vue.prototype.$getConfig = function () {
|
||||
if (instance.app instanceof Vue) {
|
||||
return instance.config;
|
||||
}
|
||||
};
|
||||
return Vue;
|
||||
function createVueModuleInstance (
|
||||
instanceId,
|
||||
weex
|
||||
) {
|
||||
var exports = {};
|
||||
VueFactory(exports, weex.document);
|
||||
var Vue = exports.Vue;
|
||||
|
||||
var instance = instanceOptions[instanceId];
|
||||
|
||||
// patch reserved tag detection to account for dynamically registered
|
||||
// components
|
||||
var weexRegex = /^weex:/i;
|
||||
var isReservedTag = Vue.config.isReservedTag || (function () { return false; });
|
||||
var isRuntimeComponent = Vue.config.isRuntimeComponent || (function () { return false; });
|
||||
Vue.config.isReservedTag = function (name) {
|
||||
return (!isRuntimeComponent(name) && weex.supports(("@component/" + name))) ||
|
||||
isReservedTag(name) ||
|
||||
weexRegex.test(name)
|
||||
};
|
||||
Vue.config.parsePlatformTagName = function (name) { return name.replace(weexRegex, ''); };
|
||||
|
||||
// expose weex-specific info
|
||||
Vue.prototype.$instanceId = instanceId;
|
||||
Vue.prototype.$document = instance.document;
|
||||
|
||||
// expose weex native module getter on subVue prototype so that
|
||||
// vdom runtime modules can access native modules via vnode.context
|
||||
Vue.prototype.$requireWeexModule = weex.requireModule;
|
||||
|
||||
// Hack `Vue` behavior to handle instance information and data
|
||||
// before root component created.
|
||||
Vue.mixin({
|
||||
beforeCreate: function beforeCreate () {
|
||||
var options = this.$options;
|
||||
// root component (vm)
|
||||
if (options.el) {
|
||||
// set external data of instance
|
||||
var dataOption = options.data;
|
||||
var internalData = (typeof dataOption === 'function' ? dataOption() : dataOption) || {};
|
||||
options.data = Object.assign(internalData, instance.data);
|
||||
// record instance by id
|
||||
instance.app = this;
|
||||
}
|
||||
},
|
||||
mounted: function mounted () {
|
||||
var options = this.$options;
|
||||
// root component (vm)
|
||||
if (options.el && weex.document && instance.app === this) {
|
||||
try {
|
||||
// Send "createFinish" signal to native.
|
||||
weex.document.taskCenter.send('dom', { action: 'createFinish' }, []);
|
||||
} catch (e) {}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* @deprecated Just instance variable `weex.config`
|
||||
* Get instance config.
|
||||
* @return {object}
|
||||
*/
|
||||
Vue.prototype.$getConfig = function () {
|
||||
if (instance.app instanceof Vue) {
|
||||
return instance.config
|
||||
}
|
||||
};
|
||||
|
||||
return Vue
|
||||
}
|
||||
|
||||
/**
|
||||
* DEPRECATED
|
||||
* Generate HTML5 Timer APIs. An important point is that the callback
|
||||
@ -136,46 +159,43 @@ function createVueModuleInstance(instanceId, weex) {
|
||||
* framework can make sure no side effect of the callback happened after
|
||||
* an instance destroyed.
|
||||
*/
|
||||
function getInstanceTimer(instanceId, moduleGetter) {
|
||||
var instance = instanceOptions[instanceId];
|
||||
var timer = moduleGetter('timer');
|
||||
var timerAPIs = {
|
||||
setTimeout: function () {
|
||||
var arguments$1 = arguments;
|
||||
function getInstanceTimer (
|
||||
instanceId,
|
||||
moduleGetter
|
||||
) {
|
||||
var instance = instanceOptions[instanceId];
|
||||
var timer = moduleGetter('timer');
|
||||
var timerAPIs = {
|
||||
setTimeout: function () {
|
||||
var args = [], len = arguments.length;
|
||||
while ( len-- ) args[ len ] = arguments[ len ];
|
||||
|
||||
var args = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
args[_i] = arguments$1[_i];
|
||||
}
|
||||
var handler = function () {
|
||||
args[0].apply(args, args.slice(2));
|
||||
};
|
||||
timer.setTimeout(handler, args[1]);
|
||||
//@ts-expect-error
|
||||
return instance.document.taskCenter.callbackManager.lastCallbackId.toString();
|
||||
},
|
||||
setInterval: function () {
|
||||
var arguments$1 = arguments;
|
||||
var handler = function () {
|
||||
args[0].apply(args, args.slice(2));
|
||||
};
|
||||
|
||||
var args = [];
|
||||
for (var _i = 0; _i < arguments.length; _i++) {
|
||||
args[_i] = arguments$1[_i];
|
||||
}
|
||||
var handler = function () {
|
||||
args[0].apply(args, args.slice(2));
|
||||
};
|
||||
timer.setInterval(handler, args[1]);
|
||||
//@ts-expect-error
|
||||
return instance.document.taskCenter.callbackManager.lastCallbackId.toString();
|
||||
},
|
||||
clearTimeout: function (n) {
|
||||
timer.clearTimeout(n);
|
||||
},
|
||||
clearInterval: function (n) {
|
||||
timer.clearInterval(n);
|
||||
},
|
||||
};
|
||||
return timerAPIs;
|
||||
timer.setTimeout(handler, args[1]);
|
||||
return instance.document.taskCenter.callbackManager.lastCallbackId.toString()
|
||||
},
|
||||
setInterval: function () {
|
||||
var args = [], len = arguments.length;
|
||||
while ( len-- ) args[ len ] = arguments[ len ];
|
||||
|
||||
var handler = function () {
|
||||
args[0].apply(args, args.slice(2));
|
||||
};
|
||||
|
||||
timer.setInterval(handler, args[1]);
|
||||
return instance.document.taskCenter.callbackManager.lastCallbackId.toString()
|
||||
},
|
||||
clearTimeout: function (n) {
|
||||
timer.clearTimeout(n);
|
||||
},
|
||||
clearInterval: function (n) {
|
||||
timer.clearInterval(n);
|
||||
}
|
||||
};
|
||||
return timerAPIs
|
||||
}
|
||||
|
||||
exports.createInstanceContext = createInstanceContext;
|
||||
|
@ -560,18 +560,15 @@ export function genComment(comment: ASTText): string {
|
||||
function genSlot(el: ASTElement, state: CodegenState): string {
|
||||
const slotName = el.slotName || '"default"'
|
||||
const children = genChildren(el, state)
|
||||
let res = `_t(${slotName}${children ? `,${children}` : ''}`
|
||||
const attrs =
|
||||
el.attrs || el.dynamicAttrs
|
||||
? genProps(
|
||||
(el.attrs || []).concat(el.dynamicAttrs || []).map((attr) => ({
|
||||
// slot props are camelized
|
||||
name: camelize(attr.name),
|
||||
value: attr.value,
|
||||
dynamic: attr.dynamic,
|
||||
}))
|
||||
)
|
||||
: null
|
||||
let res = `_t(${slotName}${children ? `,function(){return ${children}}` : ''}`
|
||||
const attrs = el.attrs || el.dynamicAttrs
|
||||
? genProps((el.attrs || []).concat(el.dynamicAttrs || []).map(attr => ({
|
||||
// slot props are camelized
|
||||
name: camelize(attr.name),
|
||||
value: attr.value,
|
||||
dynamic: attr.dynamic
|
||||
})))
|
||||
: null
|
||||
const bind = el.attrsMap['v-bind']
|
||||
if ((attrs || bind) && !children) {
|
||||
res += `,null`
|
||||
|
@ -1,12 +1,21 @@
|
||||
import { isRegExp, remove } from 'shared/util'
|
||||
import { getFirstComponentChild } from 'core/vdom/helpers/index'
|
||||
import VNode from 'core/vdom/vnode'
|
||||
import type { VNodeComponentOptions } from 'typescript/vnode'
|
||||
/* @flow */
|
||||
|
||||
type VNodeCache = { [key: string]: VNode | null }
|
||||
import { isRegExp, remove } from "shared/util";
|
||||
import { getFirstComponentChild } from "core/vdom/helpers/index";
|
||||
import type VNode from "core/vdom/vnode";
|
||||
import type { VNodeComponentOptions } from "typescript/vnode";
|
||||
import type { Component } from "typescript/component";
|
||||
|
||||
type CacheEntry = {
|
||||
name?: string;
|
||||
tag?: string;
|
||||
componentInstance?: Component;
|
||||
};
|
||||
|
||||
type CacheEntryMap = Record<string, CacheEntry | null>;
|
||||
|
||||
function getComponentName(opts?: VNodeComponentOptions): string | null {
|
||||
return opts && (opts.Ctor.options.name || opts.tag)
|
||||
return opts && (opts.Ctor.options.name || opts.tag);
|
||||
}
|
||||
|
||||
function matches(
|
||||
@ -14,49 +23,52 @@ function matches(
|
||||
name: string
|
||||
): boolean {
|
||||
if (Array.isArray(pattern)) {
|
||||
return pattern.indexOf(name) > -1
|
||||
} else if (typeof pattern === 'string') {
|
||||
return pattern.split(',').indexOf(name) > -1
|
||||
return pattern.indexOf(name) > -1;
|
||||
} else if (typeof pattern === "string") {
|
||||
return pattern.split(",").indexOf(name) > -1;
|
||||
} else if (isRegExp(pattern)) {
|
||||
return pattern.test(name)
|
||||
return pattern.test(name);
|
||||
}
|
||||
/* istanbul ignore next */
|
||||
return false
|
||||
return false;
|
||||
}
|
||||
|
||||
function pruneCache(keepAliveInstance: any, filter: Function) {
|
||||
const { cache, keys, _vnode } = keepAliveInstance
|
||||
function pruneCache(
|
||||
keepAliveInstance: { cache: CacheEntryMap; keys: string[]; _vnode: VNode },
|
||||
filter: Function
|
||||
) {
|
||||
const { cache, keys, _vnode } = keepAliveInstance;
|
||||
for (const key in cache) {
|
||||
const cachedNode: VNode | null = cache[key]
|
||||
if (cachedNode) {
|
||||
const name = getComponentName(cachedNode.componentOptions)
|
||||
const entry = cache[key];
|
||||
if (entry) {
|
||||
const name = entry.name;
|
||||
if (name && !filter(name)) {
|
||||
pruneCacheEntry(cache, key, keys, _vnode)
|
||||
pruneCacheEntry(cache, key, keys, _vnode);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function pruneCacheEntry(
|
||||
cache: VNodeCache,
|
||||
cache: CacheEntryMap,
|
||||
key: string,
|
||||
keys: Array<string>,
|
||||
current?: VNode
|
||||
) {
|
||||
const cached = cache[key]
|
||||
if (cached && (!current || cached.tag !== current.tag)) {
|
||||
//@ts-expect-error has void type
|
||||
cached.componentInstance.$destroy()
|
||||
const entry = cache[key];
|
||||
if (entry && (!current || entry.tag !== current.tag)) {
|
||||
// @ts-expect-error can be undefined
|
||||
entry.componentInstance.$destroy();
|
||||
}
|
||||
cache[key] = null
|
||||
remove(keys, key)
|
||||
cache[key] = null;
|
||||
remove(keys, key);
|
||||
}
|
||||
|
||||
const patternTypes: Array<Function> = [String, RegExp, Array]
|
||||
const patternTypes: Array<Function> = [String, RegExp, Array];
|
||||
|
||||
// TODO use defineComponent
|
||||
// TODO defineComponent
|
||||
export default {
|
||||
name: 'keep-alive',
|
||||
name: "keep-alive",
|
||||
abstract: true,
|
||||
|
||||
props: {
|
||||
@ -65,68 +77,90 @@ export default {
|
||||
max: [String, Number],
|
||||
},
|
||||
|
||||
methods: {
|
||||
cacheVNode() {
|
||||
const { cache, keys, vnodeToCache, keyToCache } = this;
|
||||
if (vnodeToCache) {
|
||||
const { tag, componentInstance, componentOptions } = vnodeToCache;
|
||||
cache[keyToCache] = {
|
||||
name: getComponentName(componentOptions),
|
||||
tag,
|
||||
componentInstance,
|
||||
};
|
||||
keys.push(keyToCache);
|
||||
// prune oldest entry
|
||||
if (this.max && keys.length > parseInt(this.max)) {
|
||||
pruneCacheEntry(cache, keys[0], keys, this._vnode);
|
||||
}
|
||||
this.vnodeToCache = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
|
||||
created() {
|
||||
this.cache = Object.create(null)
|
||||
this.keys = []
|
||||
this.cache = Object.create(null);
|
||||
this.keys = [];
|
||||
},
|
||||
|
||||
destroyed() {
|
||||
for (const key in this.cache) {
|
||||
pruneCacheEntry(this.cache, key, this.keys)
|
||||
pruneCacheEntry(this.cache, key, this.keys);
|
||||
}
|
||||
},
|
||||
|
||||
mounted() {
|
||||
this.$watch('include', (val) => {
|
||||
pruneCache(this, (name) => matches(val, name))
|
||||
})
|
||||
this.$watch('exclude', (val) => {
|
||||
pruneCache(this, (name) => !matches(val, name))
|
||||
})
|
||||
this.cacheVNode();
|
||||
this.$watch("include", (val) => {
|
||||
pruneCache(this, (name) => matches(val, name));
|
||||
});
|
||||
this.$watch("exclude", (val) => {
|
||||
pruneCache(this, (name) => !matches(val, name));
|
||||
});
|
||||
},
|
||||
|
||||
updated() {
|
||||
this.cacheVNode();
|
||||
},
|
||||
|
||||
render() {
|
||||
const slot = this.$slots.default
|
||||
const vnode = getFirstComponentChild(slot)
|
||||
const componentOptions =
|
||||
vnode && vnode.componentOptions
|
||||
const slot = this.$slots.default;
|
||||
const vnode = getFirstComponentChild(slot);
|
||||
const componentOptions = vnode && vnode.componentOptions;
|
||||
if (componentOptions) {
|
||||
// check pattern
|
||||
const name = getComponentName(componentOptions)
|
||||
const { include, exclude } = this
|
||||
const name = getComponentName(componentOptions);
|
||||
const { include, exclude } = this;
|
||||
if (
|
||||
// not included
|
||||
(include && (!name || !matches(include, name))) ||
|
||||
// excluded
|
||||
(exclude && name && matches(exclude, name))
|
||||
) {
|
||||
return vnode
|
||||
return vnode;
|
||||
}
|
||||
|
||||
const { cache, keys } = this
|
||||
const { cache, keys } = this;
|
||||
const key =
|
||||
vnode!.key == null
|
||||
vnode.key == null
|
||||
? // same constructor may get registered as different local components
|
||||
// so cid alone is not enough (#3269)
|
||||
componentOptions.Ctor.cid +
|
||||
(componentOptions.tag ? `::${componentOptions.tag}` : '')
|
||||
: vnode!.key
|
||||
(componentOptions.tag ? `::${componentOptions.tag}` : "")
|
||||
: vnode.key;
|
||||
if (cache[key]) {
|
||||
vnode!.componentInstance = cache[key].componentInstance
|
||||
vnode.componentInstance = cache[key].componentInstance;
|
||||
// make current key freshest
|
||||
remove(keys, key)
|
||||
keys.push(key)
|
||||
remove(keys, key);
|
||||
keys.push(key);
|
||||
} else {
|
||||
cache[key] = vnode
|
||||
keys.push(key)
|
||||
// prune oldest entry
|
||||
if (this.max && keys.length > parseInt(this.max)) {
|
||||
pruneCacheEntry(cache, keys[0], keys, this._vnode)
|
||||
}
|
||||
// delay setting the cache until update
|
||||
this.vnodeToCache = vnode;
|
||||
this.keyToCache = key;
|
||||
}
|
||||
|
||||
vnode!.data!.keepAlive = true
|
||||
// @ts-expect-error can vnode.data can be undefined
|
||||
vnode.data.keepAlive = true;
|
||||
}
|
||||
return vnode || (slot && slot[0])
|
||||
return vnode || (slot && slot[0]);
|
||||
},
|
||||
}
|
||||
};
|
||||
|
@ -6,6 +6,8 @@ import { updateComponentListeners } from "./events";
|
||||
import { resolveSlots } from "./render-helpers/resolve-slots";
|
||||
import { toggleObserving } from "../observer/index";
|
||||
import { pushTarget, popTarget } from "../observer/dep";
|
||||
import type { Component } from "../../../typescript/component";
|
||||
import type { MountedComponentVNode } from "../../../typescript/vnode";
|
||||
|
||||
import {
|
||||
warn,
|
||||
@ -15,8 +17,6 @@ import {
|
||||
validateProp,
|
||||
invokeWithErrorHandling,
|
||||
} from "../util/index";
|
||||
import type { Component } from "typescript/component";
|
||||
import type { MountedComponentVNode } from "typescript/vnode";
|
||||
|
||||
export let activeInstance: any = null;
|
||||
export let isUpdatingChildComponent: boolean = false;
|
||||
@ -30,7 +30,7 @@ export function setActiveInstance(vm: Component) {
|
||||
}
|
||||
|
||||
export function initLifecycle(vm: Component) {
|
||||
const options: any = vm.$options;
|
||||
const options = vm.$options;
|
||||
|
||||
// locate first non-abstract parent
|
||||
let parent = options.parent;
|
||||
@ -122,7 +122,7 @@ export function lifecycleMixin(Vue: Component) {
|
||||
// call the last hook...
|
||||
vm._isDestroyed = true;
|
||||
// invoke destroy hooks on current rendered tree
|
||||
vm.__patch__(vm._vnode!, null);
|
||||
vm.__patch__(vm._vnode, null);
|
||||
// fire destroyed hook
|
||||
callHook(vm, "destroyed");
|
||||
// turn off all instance listeners.
|
||||
@ -133,7 +133,6 @@ export function lifecycleMixin(Vue: Component) {
|
||||
}
|
||||
// release circular reference (#6759)
|
||||
if (vm.$vnode) {
|
||||
// @ts-expect-error null is not undefined
|
||||
vm.$vnode.parent = null;
|
||||
}
|
||||
};
|
||||
@ -240,12 +239,13 @@ export function updateChildComponent(
|
||||
// check if there are dynamic scopedSlots (hand-written or compiled but with
|
||||
// dynamic slot names). Static scoped slots compiled from template has the
|
||||
// "$stable" marker.
|
||||
const newScopedSlots = parentVnode!.data.scopedSlots;
|
||||
const newScopedSlots = parentVnode.data.scopedSlots;
|
||||
const oldScopedSlots = vm.$scopedSlots;
|
||||
const hasDynamicScopedSlot = !!(
|
||||
(newScopedSlots && !newScopedSlots.$stable) ||
|
||||
(oldScopedSlots !== emptyObject && !oldScopedSlots.$stable) ||
|
||||
(newScopedSlots && vm.$scopedSlots.$key !== newScopedSlots.$key)
|
||||
(newScopedSlots && vm.$scopedSlots.$key !== newScopedSlots.$key) ||
|
||||
(!newScopedSlots && vm.$scopedSlots.$key)
|
||||
);
|
||||
|
||||
// Any static slot children from the parent may have changed during parent's
|
||||
@ -258,7 +258,6 @@ export function updateChildComponent(
|
||||
);
|
||||
|
||||
vm.$options._parentVnode = parentVnode;
|
||||
|
||||
vm.$vnode = parentVnode; // update vm's placeholder node without re-render
|
||||
|
||||
if (vm._vnode) {
|
||||
@ -270,7 +269,7 @@ export function updateChildComponent(
|
||||
// update $attrs and $listeners hash
|
||||
// these are also reactive so they may trigger child update if the child
|
||||
// used them during render
|
||||
vm.$attrs = parentVnode!.data.attrs || emptyObject;
|
||||
vm.$attrs = parentVnode.data.attrs || emptyObject;
|
||||
vm.$listeners = listeners || emptyObject;
|
||||
|
||||
// update props
|
||||
@ -296,7 +295,7 @@ export function updateChildComponent(
|
||||
|
||||
// resolve slots + force update if has children
|
||||
if (needsForceUpdate) {
|
||||
vm.$slots = resolveSlots(renderChildren, parentVnode!.context);
|
||||
vm.$slots = resolveSlots(renderChildren, parentVnode.context);
|
||||
vm.$forceUpdate();
|
||||
}
|
||||
|
||||
|
@ -30,4 +30,5 @@ export function checkKeyCodes(
|
||||
} else if (eventKeyName) {
|
||||
return hyphenate(eventKeyName) !== key
|
||||
}
|
||||
return eventKeyCode === undefined
|
||||
}
|
||||
|
@ -1,35 +1,43 @@
|
||||
import { extend, warn, isObject } from 'core/util/index'
|
||||
import VNode from 'core/vdom/vnode'
|
||||
import { extend, warn, isObject } from "core/util/index";
|
||||
import VNode from "core/vdom/vnode";
|
||||
|
||||
/**
|
||||
* Runtime helper for rendering <slot>
|
||||
*/
|
||||
export function renderSlot(
|
||||
name: string,
|
||||
fallback: Array<VNode> | null,
|
||||
fallbackRender: ((() => Array<VNode>) | Array<VNode>) | null,
|
||||
props: Record<string, any> | null,
|
||||
bindObject: object | null
|
||||
): Array<VNode> | null {
|
||||
const scopedSlotFn = this.$scopedSlots[name]
|
||||
let nodes
|
||||
const scopedSlotFn = this.$scopedSlots[name];
|
||||
let nodes;
|
||||
if (scopedSlotFn) {
|
||||
// scoped slot
|
||||
props = props || {}
|
||||
props = props || {};
|
||||
if (bindObject) {
|
||||
if (process.env.NODE_ENV !== 'production' && !isObject(bindObject)) {
|
||||
warn('slot v-bind without argument expects an Object', this)
|
||||
if (process.env.NODE_ENV !== "production" && !isObject(bindObject)) {
|
||||
warn("slot v-bind without argument expects an Object", this);
|
||||
}
|
||||
props = extend(extend({}, bindObject), props)
|
||||
props = extend(extend({}, bindObject), props);
|
||||
}
|
||||
nodes = scopedSlotFn(props) || fallback
|
||||
nodes =
|
||||
scopedSlotFn(props) ||
|
||||
(typeof fallbackRender === "function"
|
||||
? fallbackRender()
|
||||
: fallbackRender);
|
||||
} else {
|
||||
nodes = this.$slots[name] || fallback
|
||||
nodes =
|
||||
this.$slots[name] ||
|
||||
(typeof fallbackRender === "function"
|
||||
? fallbackRender()
|
||||
: fallbackRender);
|
||||
}
|
||||
|
||||
const target = props && props.slot
|
||||
const target = props && props.slot;
|
||||
if (target) {
|
||||
return this.$createElement('template', { slot: target }, nodes)
|
||||
return this.$createElement("template", { slot: target }, nodes);
|
||||
} else {
|
||||
return nodes
|
||||
return nodes;
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,7 @@
|
||||
|
||||
import config from '../config'
|
||||
import Watcher from '../observer/watcher'
|
||||
import Dep, { pushTarget, popTarget } from '../observer/dep'
|
||||
import { isUpdatingChildComponent } from './lifecycle'
|
||||
import config from "../config";
|
||||
import Watcher from "../observer/watcher";
|
||||
import Dep, { pushTarget, popTarget } from "../observer/dep";
|
||||
import { isUpdatingChildComponent } from "./lifecycle";
|
||||
|
||||
import {
|
||||
set,
|
||||
@ -10,7 +9,7 @@ import {
|
||||
observe,
|
||||
defineReactive,
|
||||
toggleObserving,
|
||||
} from '../observer/index'
|
||||
} from "../observer/index";
|
||||
|
||||
import {
|
||||
warn,
|
||||
@ -25,59 +24,60 @@ import {
|
||||
isPlainObject,
|
||||
isServerRendering,
|
||||
isReservedAttribute,
|
||||
} from '../util/index'
|
||||
import type { Component } from 'typescript/component'
|
||||
invokeWithErrorHandling,
|
||||
} from "../util/index";
|
||||
import type { Component } from "../../../typescript/component";
|
||||
|
||||
const sharedPropertyDefinition = {
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
get: noop,
|
||||
set: noop,
|
||||
}
|
||||
};
|
||||
|
||||
export function proxy(target: Object, sourceKey: string, key: string) {
|
||||
sharedPropertyDefinition.get = function proxyGetter() {
|
||||
return this[sourceKey][key]
|
||||
}
|
||||
return this[sourceKey][key];
|
||||
};
|
||||
sharedPropertyDefinition.set = function proxySetter(val) {
|
||||
this[sourceKey][key] = val
|
||||
}
|
||||
Object.defineProperty(target, key, sharedPropertyDefinition)
|
||||
this[sourceKey][key] = val;
|
||||
};
|
||||
Object.defineProperty(target, key, sharedPropertyDefinition);
|
||||
}
|
||||
|
||||
export function initState(vm: Component) {
|
||||
vm._watchers = []
|
||||
const opts = vm.$options
|
||||
if (opts.props) initProps(vm, opts.props)
|
||||
if (opts.methods) initMethods(vm, opts.methods)
|
||||
vm._watchers = [];
|
||||
const opts = vm.$options;
|
||||
if (opts.props) initProps(vm, opts.props);
|
||||
if (opts.methods) initMethods(vm, opts.methods);
|
||||
if (opts.data) {
|
||||
initData(vm)
|
||||
initData(vm);
|
||||
} else {
|
||||
observe((vm._data = {}), true /* asRootData */)
|
||||
observe((vm._data = {}), true /* asRootData */);
|
||||
}
|
||||
if (opts.computed) initComputed(vm, opts.computed)
|
||||
if (opts.computed) initComputed(vm, opts.computed);
|
||||
if (opts.watch && opts.watch !== nativeWatch) {
|
||||
initWatch(vm, opts.watch)
|
||||
initWatch(vm, opts.watch);
|
||||
}
|
||||
}
|
||||
|
||||
function initProps(vm: Component, propsOptions: Object) {
|
||||
const propsData = vm.$options.propsData || {}
|
||||
const props = (vm._props = {})
|
||||
const propsData = vm.$options.propsData || {};
|
||||
const props = (vm._props = {});
|
||||
// cache prop keys so that future props updates can iterate using Array
|
||||
// instead of dynamic object key enumeration.
|
||||
const keys: string[] = (vm.$options._propKeys = [])
|
||||
const isRoot = !vm.$parent
|
||||
const keys: string[] = (vm.$options._propKeys = []);
|
||||
const isRoot = !vm.$parent;
|
||||
// root instance props should be converted
|
||||
if (!isRoot) {
|
||||
toggleObserving(false)
|
||||
toggleObserving(false);
|
||||
}
|
||||
for (const key in propsOptions) {
|
||||
keys.push(key)
|
||||
const value = validateProp(key, propsOptions, propsData, vm)
|
||||
keys.push(key);
|
||||
const value = validateProp(key, propsOptions, propsData, vm);
|
||||
/* istanbul ignore else */
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const hyphenatedKey = hyphenate(key)
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
const hyphenatedKey = hyphenate(key);
|
||||
if (
|
||||
isReservedAttribute(hyphenatedKey) ||
|
||||
config.isReservedAttr(hyphenatedKey)
|
||||
@ -85,7 +85,7 @@ function initProps(vm: Component, propsOptions: Object) {
|
||||
warn(
|
||||
`"${hyphenatedKey}" is a reserved attribute and cannot be used as component prop.`,
|
||||
vm
|
||||
)
|
||||
);
|
||||
}
|
||||
defineReactive(props, key, value, () => {
|
||||
if (!isRoot && !isUpdatingChildComponent) {
|
||||
@ -95,87 +95,90 @@ function initProps(vm: Component, propsOptions: Object) {
|
||||
`Instead, use a data or computed property based on the prop's ` +
|
||||
`value. Prop being mutated: "${key}"`,
|
||||
vm
|
||||
)
|
||||
);
|
||||
}
|
||||
})
|
||||
});
|
||||
} else {
|
||||
defineReactive(props, key, value)
|
||||
defineReactive(props, key, value);
|
||||
}
|
||||
// static props are already proxied on the component's prototype
|
||||
// during Vue.extend(). We only need to proxy props defined at
|
||||
// instantiation here.
|
||||
if (!(key in vm)) {
|
||||
proxy(vm, `_props`, key)
|
||||
proxy(vm, `_props`, key);
|
||||
}
|
||||
}
|
||||
toggleObserving(true)
|
||||
toggleObserving(true);
|
||||
}
|
||||
|
||||
function initData(vm: Component) {
|
||||
let data: any = vm.$options.data
|
||||
data = vm._data = typeof data === 'function' ? getData(data, vm) : data || {}
|
||||
let data: any = vm.$options.data;
|
||||
data = vm._data = typeof data === "function" ? getData(data, vm) : data || {};
|
||||
if (!isPlainObject(data)) {
|
||||
data = {}
|
||||
process.env.NODE_ENV !== 'production' &&
|
||||
data = {};
|
||||
process.env.NODE_ENV !== "production" &&
|
||||
warn(
|
||||
'data functions should return an object:\n' +
|
||||
'https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function',
|
||||
"data functions should return an object:\n" +
|
||||
"https://vuejs.org/v2/guide/components.html#data-Must-Be-a-Function",
|
||||
vm
|
||||
)
|
||||
);
|
||||
}
|
||||
// proxy data on instance
|
||||
const keys = Object.keys(data)
|
||||
const props = vm.$options.props
|
||||
const methods = vm.$options.methods
|
||||
let i = keys.length
|
||||
const keys = Object.keys(data);
|
||||
const props = vm.$options.props;
|
||||
const methods = vm.$options.methods;
|
||||
let i = keys.length;
|
||||
while (i--) {
|
||||
const key = keys[i]
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
const key = keys[i];
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
if (methods && hasOwn(methods, key)) {
|
||||
warn(`Method "${key}" has already been defined as a data property.`, vm)
|
||||
warn(
|
||||
`Method "${key}" has already been defined as a data property.`,
|
||||
vm
|
||||
);
|
||||
}
|
||||
}
|
||||
if (props && hasOwn(props, key)) {
|
||||
process.env.NODE_ENV !== 'production' &&
|
||||
process.env.NODE_ENV !== "production" &&
|
||||
warn(
|
||||
`The data property "${key}" is already declared as a prop. ` +
|
||||
`Use prop default value instead.`,
|
||||
vm
|
||||
)
|
||||
);
|
||||
} else if (!isReserved(key)) {
|
||||
proxy(vm, `_data`, key)
|
||||
proxy(vm, `_data`, key);
|
||||
}
|
||||
}
|
||||
// observe data
|
||||
observe(data, true /* asRootData */)
|
||||
observe(data, true /* asRootData */);
|
||||
}
|
||||
|
||||
export function getData(data: Function, vm: Component): any {
|
||||
// #7573 disable dep collection when invoking data getters
|
||||
pushTarget()
|
||||
pushTarget();
|
||||
try {
|
||||
return data.call(vm, vm)
|
||||
} catch (e) {
|
||||
handleError(e, vm, `data()`)
|
||||
return {}
|
||||
return data.call(vm, vm);
|
||||
} catch (e: any) {
|
||||
handleError(e, vm, `data()`);
|
||||
return {};
|
||||
} finally {
|
||||
popTarget()
|
||||
popTarget();
|
||||
}
|
||||
}
|
||||
|
||||
const computedWatcherOptions = { lazy: true }
|
||||
const computedWatcherOptions = { lazy: true };
|
||||
|
||||
function initComputed(vm: Component, computed: Object) {
|
||||
// $flow-disable-line
|
||||
const watchers = (vm._computedWatchers = Object.create(null))
|
||||
const watchers = (vm._computedWatchers = Object.create(null));
|
||||
// computed properties are just getters during SSR
|
||||
const isSSR = isServerRendering()
|
||||
const isSSR = isServerRendering();
|
||||
|
||||
for (const key in computed) {
|
||||
const userDef = computed[key]
|
||||
const getter = typeof userDef === 'function' ? userDef : userDef.get
|
||||
if (process.env.NODE_ENV !== 'production' && getter == null) {
|
||||
warn(`Getter is missing for computed property "${key}".`, vm)
|
||||
const userDef = computed[key];
|
||||
const getter = typeof userDef === "function" ? userDef : userDef.get;
|
||||
if (process.env.NODE_ENV !== "production" && getter == null) {
|
||||
warn(`Getter is missing for computed property "${key}".`, vm);
|
||||
}
|
||||
|
||||
if (!isSSR) {
|
||||
@ -185,19 +188,27 @@ function initComputed(vm: Component, computed: Object) {
|
||||
getter || noop,
|
||||
noop,
|
||||
computedWatcherOptions
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// component-defined computed properties are already defined on the
|
||||
// component prototype. We only need to define computed properties defined
|
||||
// at instantiation here.
|
||||
if (!(key in vm)) {
|
||||
defineComputed(vm, key, userDef)
|
||||
} else if (process.env.NODE_ENV !== 'production') {
|
||||
defineComputed(vm, key, userDef);
|
||||
} else if (process.env.NODE_ENV !== "production") {
|
||||
if (key in vm.$data) {
|
||||
warn(`The computed property "${key}" is already defined in data.`, vm)
|
||||
warn(`The computed property "${key}" is already defined in data.`, vm);
|
||||
} else if (vm.$options.props && key in vm.$options.props) {
|
||||
warn(`The computed property "${key}" is already defined as a prop.`, vm)
|
||||
warn(
|
||||
`The computed property "${key}" is already defined as a prop.`,
|
||||
vm
|
||||
);
|
||||
} else if (vm.$options.methods && key in vm.$options.methods) {
|
||||
warn(
|
||||
`The computed property "${key}" is already defined as a method.`,
|
||||
vm
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -208,91 +219,92 @@ export function defineComputed(
|
||||
key: string,
|
||||
userDef: Record<string, any> | Function
|
||||
) {
|
||||
const shouldCache = !isServerRendering()
|
||||
if (typeof userDef === 'function') {
|
||||
const shouldCache = !isServerRendering();
|
||||
if (typeof userDef === "function") {
|
||||
sharedPropertyDefinition.get = shouldCache
|
||||
? createComputedGetter(key)
|
||||
: createGetterInvoker(userDef)
|
||||
sharedPropertyDefinition.set = noop
|
||||
: createGetterInvoker(userDef);
|
||||
sharedPropertyDefinition.set = noop;
|
||||
} else {
|
||||
sharedPropertyDefinition.get = userDef.get
|
||||
? shouldCache && userDef.cache !== false
|
||||
? createComputedGetter(key)
|
||||
: createGetterInvoker(userDef.get)
|
||||
: noop
|
||||
sharedPropertyDefinition.set = userDef.set || noop
|
||||
: noop;
|
||||
sharedPropertyDefinition.set = userDef.set || noop;
|
||||
}
|
||||
if (
|
||||
process.env.NODE_ENV !== 'production' &&
|
||||
process.env.NODE_ENV !== "production" &&
|
||||
sharedPropertyDefinition.set === noop
|
||||
) {
|
||||
sharedPropertyDefinition.set = function () {
|
||||
warn(
|
||||
`Computed property "${key}" was assigned to but it has no setter.`,
|
||||
this
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
}
|
||||
Object.defineProperty(target, key, sharedPropertyDefinition)
|
||||
Object.defineProperty(target, key, sharedPropertyDefinition);
|
||||
}
|
||||
|
||||
function createComputedGetter(key) {
|
||||
return function computedGetter() {
|
||||
const watcher = this._computedWatchers && this._computedWatchers[key]
|
||||
const watcher = this._computedWatchers && this._computedWatchers[key];
|
||||
if (watcher) {
|
||||
if (watcher.dirty) {
|
||||
watcher.evaluate()
|
||||
watcher.evaluate();
|
||||
}
|
||||
if (Dep.target) {
|
||||
watcher.depend()
|
||||
watcher.depend();
|
||||
}
|
||||
return watcher.value
|
||||
return watcher.value;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function createGetterInvoker(fn) {
|
||||
return function computedGetter() {
|
||||
return fn.call(this, this)
|
||||
}
|
||||
return fn.call(this, this);
|
||||
};
|
||||
}
|
||||
|
||||
function initMethods(vm: Component, methods: Object) {
|
||||
const props = vm.$options.props
|
||||
const props = vm.$options.props;
|
||||
for (const key in methods) {
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
if (typeof methods[key] !== 'function') {
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
if (typeof methods[key] !== "function") {
|
||||
warn(
|
||||
`Method "${key}" has type "${typeof methods[
|
||||
key
|
||||
]}" in the component definition. ` +
|
||||
`Did you reference the function correctly?`,
|
||||
vm
|
||||
)
|
||||
);
|
||||
}
|
||||
if (props && hasOwn(props, key)) {
|
||||
warn(`Method "${key}" has already been defined as a prop.`, vm)
|
||||
warn(`Method "${key}" has already been defined as a prop.`, vm);
|
||||
}
|
||||
if (key in vm && isReserved(key)) {
|
||||
warn(
|
||||
`Method "${key}" conflicts with an existing Vue instance method. ` +
|
||||
`Avoid defining component methods that start with _ or $.`
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
vm[key] = typeof methods[key] !== 'function' ? noop : bind(methods[key], vm)
|
||||
vm[key] =
|
||||
typeof methods[key] !== "function" ? noop : bind(methods[key], vm);
|
||||
}
|
||||
}
|
||||
|
||||
function initWatch(vm: Component, watch: Object) {
|
||||
for (const key in watch) {
|
||||
const handler = watch[key]
|
||||
const handler = watch[key];
|
||||
if (Array.isArray(handler)) {
|
||||
for (let i = 0; i < handler.length; i++) {
|
||||
createWatcher(vm, key, handler[i])
|
||||
createWatcher(vm, key, handler[i]);
|
||||
}
|
||||
} else {
|
||||
createWatcher(vm, key, handler)
|
||||
createWatcher(vm, key, handler);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -304,72 +316,65 @@ function createWatcher(
|
||||
options?: Object
|
||||
) {
|
||||
if (isPlainObject(handler)) {
|
||||
options = handler
|
||||
handler = handler.handler
|
||||
options = handler;
|
||||
handler = handler.handler;
|
||||
}
|
||||
if (typeof handler === 'string') {
|
||||
handler = vm[handler]
|
||||
if (typeof handler === "string") {
|
||||
handler = vm[handler];
|
||||
}
|
||||
return vm.$watch(expOrFn, handler, options)
|
||||
return vm.$watch(expOrFn, handler, options);
|
||||
}
|
||||
|
||||
export function stateMixin(Vue: Component) {
|
||||
// flow somehow has problems with directly declared definition object
|
||||
// when using Object.defineProperty, so we have to procedurally build up
|
||||
// the object here.
|
||||
const dataDef:any = {}
|
||||
const dataDef: any = {};
|
||||
dataDef.get = function () {
|
||||
return this._data
|
||||
}
|
||||
const propsDef: any = {}
|
||||
return this._data;
|
||||
};
|
||||
const propsDef: any = {};
|
||||
propsDef.get = function () {
|
||||
return this._props
|
||||
}
|
||||
if (process.env.NODE_ENV !== 'production') {
|
||||
return this._props;
|
||||
};
|
||||
if (process.env.NODE_ENV !== "production") {
|
||||
dataDef.set = function () {
|
||||
warn(
|
||||
'Avoid replacing instance root $data. ' +
|
||||
'Use nested data properties instead.',
|
||||
"Avoid replacing instance root $data. " +
|
||||
"Use nested data properties instead.",
|
||||
this
|
||||
)
|
||||
}
|
||||
);
|
||||
};
|
||||
propsDef.set = function () {
|
||||
warn(`$props is readonly.`, this)
|
||||
}
|
||||
warn(`$props is readonly.`, this);
|
||||
};
|
||||
}
|
||||
Object.defineProperty(Vue.prototype, '$data', dataDef)
|
||||
Object.defineProperty(Vue.prototype, '$props', propsDef)
|
||||
Object.defineProperty(Vue.prototype, "$data", dataDef);
|
||||
Object.defineProperty(Vue.prototype, "$props", propsDef);
|
||||
|
||||
Vue.prototype.$set = set
|
||||
Vue.prototype.$delete = del
|
||||
Vue.prototype.$set = set;
|
||||
Vue.prototype.$delete = del;
|
||||
|
||||
Vue.prototype.$watch = function (
|
||||
expOrFn: string | Function,
|
||||
cb: any,
|
||||
options?: Record<string,any>
|
||||
options?: Record<string, any>
|
||||
): Function {
|
||||
const vm: Component = this
|
||||
const vm: Component = this;
|
||||
if (isPlainObject(cb)) {
|
||||
return createWatcher(vm, expOrFn, cb, options)
|
||||
return createWatcher(vm, expOrFn, cb, options);
|
||||
}
|
||||
options = options || {}
|
||||
options.user = true
|
||||
const watcher = new Watcher(vm, expOrFn, cb, options)
|
||||
options = options || {};
|
||||
options.user = true;
|
||||
const watcher = new Watcher(vm, expOrFn, cb, options);
|
||||
if (options.immediate) {
|
||||
pushTarget()
|
||||
try {
|
||||
cb.call(vm, watcher.value)
|
||||
} catch (error) {
|
||||
handleError(
|
||||
error,
|
||||
vm,
|
||||
`callback for immediate watcher "${watcher.expression}"`
|
||||
)
|
||||
}
|
||||
popTarget()
|
||||
const info = `callback for immediate watcher "${watcher.expression}"`;
|
||||
pushTarget();
|
||||
invokeWithErrorHandling(cb, vm, [watcher.value], vm, info);
|
||||
popTarget();
|
||||
}
|
||||
return function unwatchFn() {
|
||||
watcher.teardown()
|
||||
}
|
||||
}
|
||||
watcher.teardown();
|
||||
};
|
||||
};
|
||||
}
|
||||
|
@ -6,7 +6,8 @@ import {
|
||||
parsePath,
|
||||
_Set as Set,
|
||||
handleError,
|
||||
noop,
|
||||
invokeWithErrorHandling,
|
||||
noop
|
||||
} from '../util/index'
|
||||
|
||||
import { traverse } from './traverse'
|
||||
@ -78,8 +79,9 @@ export default class Watcher {
|
||||
this.newDeps = []
|
||||
this.depIds = new Set()
|
||||
this.newDepIds = new Set()
|
||||
this.expression =
|
||||
process.env.NODE_ENV !== 'production' ? expOrFn.toString() : ''
|
||||
this.expression = process.env.NODE_ENV !== 'production'
|
||||
? expOrFn.toString()
|
||||
: ''
|
||||
// parse expression for getter
|
||||
if (typeof expOrFn === 'function') {
|
||||
this.getter = expOrFn
|
||||
@ -87,16 +89,17 @@ export default class Watcher {
|
||||
this.getter = parsePath(expOrFn)
|
||||
if (!this.getter) {
|
||||
this.getter = noop
|
||||
process.env.NODE_ENV !== 'production' &&
|
||||
warn(
|
||||
`Failed watching path: "${expOrFn}" ` +
|
||||
'Watcher only accepts simple dot-delimited paths. ' +
|
||||
'For full control, use a function instead.',
|
||||
vm
|
||||
)
|
||||
process.env.NODE_ENV !== 'production' && warn(
|
||||
`Failed watching path: "${expOrFn}" ` +
|
||||
'Watcher only accepts simple dot-delimited paths. ' +
|
||||
'For full control, use a function instead.',
|
||||
vm
|
||||
)
|
||||
}
|
||||
}
|
||||
this.value = this.lazy ? undefined : this.get()
|
||||
this.value = this.lazy
|
||||
? undefined
|
||||
: this.get()
|
||||
}
|
||||
|
||||
/**
|
||||
@ -195,11 +198,8 @@ export default class Watcher {
|
||||
const oldValue = this.value
|
||||
this.value = value
|
||||
if (this.user) {
|
||||
try {
|
||||
this.cb.call(this.vm, value, oldValue)
|
||||
} catch (e) {
|
||||
handleError(e, this.vm, `callback for watcher "${this.expression}"`)
|
||||
}
|
||||
const info = `callback for watcher "${this.expression}"`
|
||||
invokeWithErrorHandling(this.cb, this.vm, [value, oldValue], this.vm, info)
|
||||
} else {
|
||||
this.cb.call(this.vm, value, oldValue)
|
||||
}
|
||||
|
@ -1,23 +1,23 @@
|
||||
|
||||
import { def } from 'core/util/lang'
|
||||
import { normalizeChildren } from 'core/vdom/helpers/normalize-children'
|
||||
import { emptyObject } from 'shared/util'
|
||||
import VNode from '../vnode'
|
||||
import { def } from "core/util/lang";
|
||||
import { normalizeChildren } from "core/vdom/helpers/normalize-children";
|
||||
import { emptyObject } from "shared/util";
|
||||
import { isAsyncPlaceholder } from "./is-async-placeholder";
|
||||
import type VNode from "../vnode";
|
||||
|
||||
export function normalizeScopedSlots(
|
||||
slots: { [key: string]: Function } | void,
|
||||
normalSlots: { [key: string]: Array<VNode> },
|
||||
prevSlots?: { [key: string]: Function } | void
|
||||
): any {
|
||||
let res
|
||||
const hasNormalSlots = Object.keys(normalSlots).length > 0
|
||||
const isStable = slots ? !!slots.$stable : !hasNormalSlots
|
||||
const key = slots && slots.$key
|
||||
let res;
|
||||
const hasNormalSlots = Object.keys(normalSlots).length > 0;
|
||||
const isStable = slots ? !!slots.$stable : !hasNormalSlots;
|
||||
const key = slots && slots.$key;
|
||||
if (!slots) {
|
||||
res = {}
|
||||
res = {};
|
||||
} else if (slots._normalized) {
|
||||
// fast path 1: child component re-render only, parent did not change
|
||||
return slots._normalized
|
||||
return slots._normalized;
|
||||
} else if (
|
||||
isStable &&
|
||||
prevSlots &&
|
||||
@ -28,43 +28,46 @@ export function normalizeScopedSlots(
|
||||
) {
|
||||
// fast path 2: stable scoped slots w/ no normal slots to proxy,
|
||||
// only need to normalize once
|
||||
return prevSlots
|
||||
return prevSlots;
|
||||
} else {
|
||||
res = {}
|
||||
res = {};
|
||||
for (const key in slots) {
|
||||
if (slots[key] && key[0] !== '$') {
|
||||
res[key] = normalizeScopedSlot(normalSlots, key, slots[key])
|
||||
if (slots[key] && key[0] !== "$") {
|
||||
res[key] = normalizeScopedSlot(normalSlots, key, slots[key]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// expose normal slots on scopedSlots
|
||||
for (const key in normalSlots) {
|
||||
if (!(key in res)) {
|
||||
res[key] = proxyNormalSlot(normalSlots, key)
|
||||
res[key] = proxyNormalSlot(normalSlots, key);
|
||||
}
|
||||
}
|
||||
// avoriaz seems to mock a non-extensible $scopedSlots object
|
||||
// and when that is passed down this would cause an error
|
||||
if (slots && Object.isExtensible(slots)) {
|
||||
slots._normalized = res
|
||||
slots._normalized = res;
|
||||
}
|
||||
def(res, '$stable', isStable)
|
||||
def(res, '$key', key)
|
||||
def(res, '$hasNormal', hasNormalSlots)
|
||||
return res
|
||||
def(res, "$stable", isStable);
|
||||
def(res, "$key", key);
|
||||
def(res, "$hasNormal", hasNormalSlots);
|
||||
return res;
|
||||
}
|
||||
|
||||
function normalizeScopedSlot(normalSlots, key, fn) {
|
||||
const normalized = function () {
|
||||
let res = arguments.length ? fn.apply(null, arguments) : fn({})
|
||||
let res = arguments.length ? fn.apply(null, arguments) : fn({});
|
||||
res =
|
||||
res && typeof res === 'object' && !Array.isArray(res)
|
||||
res && typeof res === "object" && !Array.isArray(res)
|
||||
? [res] // single vnode
|
||||
: normalizeChildren(res)
|
||||
return res && (res.length === 0 || (res.length === 1 && res[0].isComment)) // #9658
|
||||
: normalizeChildren(res);
|
||||
let vnode: VNode | null = res && res[0];
|
||||
return res &&
|
||||
(!vnode ||
|
||||
(res.length === 1 && vnode.isComment && !isAsyncPlaceholder(vnode))) // #9658, #10391
|
||||
? undefined
|
||||
: res
|
||||
}
|
||||
: res;
|
||||
};
|
||||
// this is a slot using the new v-slot syntax without scope. although it is
|
||||
// compiled as a scoped slot, render fn users would expect it to be present
|
||||
// on this.$slots because the usage is semantically a normal slot.
|
||||
@ -73,11 +76,11 @@ function normalizeScopedSlot(normalSlots, key, fn) {
|
||||
get: normalized,
|
||||
enumerable: true,
|
||||
configurable: true,
|
||||
})
|
||||
});
|
||||
}
|
||||
return normalized
|
||||
return normalized;
|
||||
}
|
||||
|
||||
function proxyNormalSlot(slots, key) {
|
||||
return () => slots[key]
|
||||
return () => slots[key];
|
||||
}
|
||||
|
@ -35,13 +35,17 @@ const hooks = ['create', 'activate', 'update', 'remove', 'destroy']
|
||||
function sameVnode(a, b) {
|
||||
return (
|
||||
a.key === b.key &&
|
||||
((a.tag === b.tag &&
|
||||
a.isComment === b.isComment &&
|
||||
isDef(a.data) === isDef(b.data) &&
|
||||
sameInputType(a, b)) ||
|
||||
(isTrue(a.isAsyncPlaceholder) &&
|
||||
a.asyncFactory === b.asyncFactory &&
|
||||
isUndef(b.asyncFactory.error)))
|
||||
a.asyncFactory === b.asyncFactory && (
|
||||
(
|
||||
a.tag === b.tag &&
|
||||
a.isComment === b.isComment &&
|
||||
isDef(a.data) === isDef(b.data) &&
|
||||
sameInputType(a, b)
|
||||
) || (
|
||||
isTrue(a.isAsyncPlaceholder) &&
|
||||
isUndef(b.asyncFactory.error)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -13,7 +13,7 @@ export default class VNode {
|
||||
key: string | number | undefined;
|
||||
componentOptions?: VNodeComponentOptions;
|
||||
componentInstance?: Component; // component instance
|
||||
parent: VNode | undefined; // component placeholder node
|
||||
parent: VNode | undefined | null; // component placeholder node
|
||||
|
||||
// strictly internal
|
||||
raw: boolean; // contains raw HTML? (server only)
|
||||
|
@ -18,7 +18,7 @@ function transformNode(el: ASTElement, options: CompilerOptions) {
|
||||
}
|
||||
}
|
||||
if (staticClass) {
|
||||
el.staticClass = JSON.stringify(staticClass)
|
||||
el.staticClass = JSON.stringify(staticClass.replace(/\s+/g, ' ').trim())
|
||||
}
|
||||
const classBinding = getBindingAttr(el, 'class', false /* getStatic */)
|
||||
if (classBinding) {
|
||||
|
@ -7,6 +7,7 @@ import {
|
||||
CHECKBOX_RADIO_TOKEN,
|
||||
} from 'web/compiler/directives/model'
|
||||
import { currentFlushTimestamp } from 'core/observer/scheduler'
|
||||
import { emptyNode } from 'core/vdom/patch'
|
||||
import type { VNodeWithData } from 'typescript/vnode'
|
||||
|
||||
// normalize v-model event tokens that can only be determined at runtime.
|
||||
@ -62,7 +63,7 @@ function add(
|
||||
if (useMicrotaskFix) {
|
||||
const attachedTimestamp = currentFlushTimestamp
|
||||
const original = handler
|
||||
//@ts-expect-error
|
||||
//@ts-expect-error
|
||||
handler = original._wrapper = function (e) {
|
||||
if (
|
||||
// no bubbling, should always fire.
|
||||
@ -111,7 +112,9 @@ function updateDOMListeners(oldVnode: VNodeWithData, vnode: VNodeWithData) {
|
||||
}
|
||||
const on = vnode.data.on || {}
|
||||
const oldOn = oldVnode.data.on || {}
|
||||
target = vnode.elm
|
||||
// vnode is empty when removing all listeners,
|
||||
// and use old vnode dom element
|
||||
target = vnode.elm || oldVnode.elm
|
||||
normalizeEvents(on)
|
||||
updateListeners(on, oldOn, add, remove, createOnceHandler, vnode.context)
|
||||
target = undefined
|
||||
@ -120,4 +123,6 @@ function updateDOMListeners(oldVnode: VNodeWithData, vnode: VNodeWithData) {
|
||||
export default {
|
||||
create: updateDOMListeners,
|
||||
update: updateDOMListeners,
|
||||
// @ts-expect-error emptyNode has actually data
|
||||
destroy: (vnode: VNodeWithData) => updateDOMListeners(vnode, emptyNode)
|
||||
}
|
||||
|
@ -25,11 +25,11 @@ export function createInstanceContext(
|
||||
instanceId,
|
||||
config: weex.config,
|
||||
document: weex.document,
|
||||
data,
|
||||
})
|
||||
data
|
||||
}
|
||||
|
||||
// Each instance has a independent `Vue` module instance
|
||||
const Vue = (instance.Vue = createVueModuleInstance(instanceId, weex))
|
||||
// Each instance has an independent `Vue` module instance
|
||||
const Vue = instance.Vue = createVueModuleInstance(instanceId, weex)
|
||||
|
||||
// DEPRECATED
|
||||
const timerAPIs = getInstanceTimer(instanceId, weex.requireModule)
|
||||
|
67
src/server/webpack-plugin/client.js
Normal file
67
src/server/webpack-plugin/client.js
Normal file
@ -0,0 +1,67 @@
|
||||
const hash = require('hash-sum')
|
||||
const uniq = require('lodash.uniq')
|
||||
import { isJS, isCSS, getAssetName, onEmit, stripModuleIdHash } from './util'
|
||||
|
||||
export default class VueSSRClientPlugin {
|
||||
constructor (options = {}) {
|
||||
this.options = Object.assign({
|
||||
filename: 'vue-ssr-client-manifest.json'
|
||||
}, options)
|
||||
}
|
||||
|
||||
apply (compiler) {
|
||||
const stage = 'PROCESS_ASSETS_STAGE_ADDITIONAL'
|
||||
onEmit(compiler, 'vue-client-plugin', stage, (compilation, cb) => {
|
||||
const stats = compilation.getStats().toJson()
|
||||
|
||||
const allFiles = uniq(stats.assets
|
||||
.map(a => a.name))
|
||||
|
||||
const initialFiles = uniq(Object.keys(stats.entrypoints)
|
||||
.map(name => stats.entrypoints[name].assets)
|
||||
.reduce((assets, all) => all.concat(assets), [])
|
||||
.map(getAssetName)
|
||||
.filter((file) => isJS(file) || isCSS(file)))
|
||||
|
||||
const asyncFiles = allFiles
|
||||
.filter((file) => isJS(file) || isCSS(file))
|
||||
.filter(file => initialFiles.indexOf(file) < 0)
|
||||
|
||||
const manifest = {
|
||||
publicPath: stats.publicPath,
|
||||
all: allFiles,
|
||||
initial: initialFiles,
|
||||
async: asyncFiles,
|
||||
modules: { /* [identifier: string]: Array<index: number> */ }
|
||||
}
|
||||
|
||||
const assetModules = stats.modules.filter(m => m.assets.length)
|
||||
const fileToIndex = asset => manifest.all.indexOf(getAssetName(asset))
|
||||
stats.modules.forEach(m => {
|
||||
// ignore modules duplicated in multiple chunks
|
||||
if (m.chunks.length === 1) {
|
||||
const cid = m.chunks[0]
|
||||
const chunk = stats.chunks.find(c => c.id === cid)
|
||||
if (!chunk || !chunk.files) {
|
||||
return
|
||||
}
|
||||
const id = stripModuleIdHash(m.identifier)
|
||||
const files = manifest.modules[hash(id)] = chunk.files.map(fileToIndex)
|
||||
// find all asset modules associated with the same chunk
|
||||
assetModules.forEach(m => {
|
||||
if (m.chunks.some(id => id === cid)) {
|
||||
files.push.apply(files, m.assets.map(fileToIndex))
|
||||
}
|
||||
})
|
||||
}
|
||||
})
|
||||
|
||||
const json = JSON.stringify(manifest, null, 2)
|
||||
compilation.assets[this.options.filename] = {
|
||||
source: () => json,
|
||||
size: () => json.length
|
||||
}
|
||||
cb()
|
||||
})
|
||||
}
|
||||
}
|
@ -1,34 +1,36 @@
|
||||
const hash = require('hash-sum')
|
||||
const uniq = require('lodash.uniq')
|
||||
import { isJS, isCSS, onEmit } from './util'
|
||||
const hash = require("hash-sum");
|
||||
const uniq = require("lodash.uniq");
|
||||
import { isJS, isCSS, getAssetName, onEmit, stripModuleIdHash } from "./util";
|
||||
|
||||
export default class VueSSRClientPlugin {
|
||||
constructor(options = {}) {
|
||||
//@ts-expect-error
|
||||
//@ts-expect-error no type on options
|
||||
this.options = Object.assign(
|
||||
{
|
||||
filename: 'vue-ssr-client-manifest.json',
|
||||
filename: "vue-ssr-client-manifest.json",
|
||||
},
|
||||
options
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
apply(compiler) {
|
||||
onEmit(compiler, 'vue-client-plugin', (compilation, cb) => {
|
||||
const stats = compilation.getStats().toJson()
|
||||
const stage = "PROCESS_ASSETS_STAGE_ADDITIONAL";
|
||||
onEmit(compiler, "vue-client-plugin", stage, (compilation, cb) => {
|
||||
const stats = compilation.getStats().toJson();
|
||||
|
||||
const allFiles = uniq(stats.assets.map((a) => a.name))
|
||||
const allFiles = uniq(stats.assets.map((a) => a.name));
|
||||
|
||||
const initialFiles = uniq(
|
||||
Object.keys(stats.entrypoints)
|
||||
.map((name) => stats.entrypoints[name].assets)
|
||||
.reduce((assets, all) => all.concat(assets), [])
|
||||
.map(getAssetName)
|
||||
.filter((file) => isJS(file) || isCSS(file))
|
||||
)
|
||||
);
|
||||
|
||||
const asyncFiles = allFiles
|
||||
.filter((file) => isJS(file) || isCSS(file))
|
||||
.filter((file) => initialFiles.indexOf(file) < 0)
|
||||
.filter((file) => initialFiles.indexOf(file) < 0);
|
||||
|
||||
const manifest = {
|
||||
publicPath: stats.publicPath,
|
||||
@ -38,38 +40,37 @@ export default class VueSSRClientPlugin {
|
||||
modules: {
|
||||
/* [identifier: string]: Array<index: number> */
|
||||
},
|
||||
}
|
||||
};
|
||||
|
||||
const assetModules = stats.modules.filter((m) => m.assets.length)
|
||||
const fileToIndex = (file) => manifest.all.indexOf(file)
|
||||
const assetModules = stats.modules.filter((m) => m.assets.length);
|
||||
const fileToIndex = (asset) => manifest.all.indexOf(getAssetName(asset));
|
||||
stats.modules.forEach((m) => {
|
||||
// ignore modules duplicated in multiple chunks
|
||||
if (m.chunks.length === 1) {
|
||||
const cid = m.chunks[0]
|
||||
const chunk = stats.chunks.find((c) => c.id === cid)
|
||||
const cid = m.chunks[0];
|
||||
const chunk = stats.chunks.find((c) => c.id === cid);
|
||||
if (!chunk || !chunk.files) {
|
||||
return
|
||||
return;
|
||||
}
|
||||
const id = m.identifier.replace(/\s\w+$/, '') // remove appended hash
|
||||
const files = (manifest.modules[hash(id)] = chunk.files.map(
|
||||
fileToIndex
|
||||
))
|
||||
const id = stripModuleIdHash(m.identifier);
|
||||
const files = (manifest.modules[hash(id)] =
|
||||
chunk.files.map(fileToIndex));
|
||||
// find all asset modules associated with the same chunk
|
||||
assetModules.forEach((m) => {
|
||||
if (m.chunks.some((id) => id === cid)) {
|
||||
files.push.apply(files, m.assets.map(fileToIndex))
|
||||
files.push.apply(files, m.assets.map(fileToIndex));
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
})
|
||||
});
|
||||
|
||||
const json = JSON.stringify(manifest, null, 2)
|
||||
//@ts-expect-error
|
||||
const json = JSON.stringify(manifest, null, 2);
|
||||
//@ts-expect-error no type on options
|
||||
compilation.assets[this.options.filename] = {
|
||||
source: () => json,
|
||||
size: () => json.length,
|
||||
}
|
||||
cb()
|
||||
})
|
||||
};
|
||||
cb();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { validate, isJS, onEmit } from './util'
|
||||
import { validate, isJS, getAssetName, onEmit } from './util'
|
||||
|
||||
export default class VueSSRServerPlugin {
|
||||
constructor(options = {}) {
|
||||
@ -14,7 +14,8 @@ export default class VueSSRServerPlugin {
|
||||
apply(compiler) {
|
||||
validate(compiler)
|
||||
|
||||
onEmit(compiler, 'vue-server-plugin', (compilation, cb) => {
|
||||
const stage = 'PROCESS_ASSETS_STAGE_OPTIMIZE_TRANSFER'
|
||||
onEmit(compiler, 'vue-server-plugin', stage, (compilation, cb) => {
|
||||
const stats = compilation.getStats().toJson()
|
||||
const entryName = Object.keys(stats.entrypoints)[0]
|
||||
const entryInfo = stats.entrypoints[entryName]
|
||||
@ -24,7 +25,9 @@ export default class VueSSRServerPlugin {
|
||||
return cb()
|
||||
}
|
||||
|
||||
const entryAssets = entryInfo.assets.filter(isJS)
|
||||
const entryAssets = entryInfo.assets
|
||||
.map(getAssetName)
|
||||
.filter(isJS)
|
||||
|
||||
if (entryAssets.length > 1) {
|
||||
throw new Error(
|
||||
@ -46,16 +49,14 @@ export default class VueSSRServerPlugin {
|
||||
maps: {},
|
||||
}
|
||||
|
||||
stats.assets.forEach((asset) => {
|
||||
if (isJS(asset.name)) {
|
||||
bundle.files[asset.name] = compilation.assets[asset.name].source()
|
||||
} else if (asset.name.match(/\.js\.map$/)) {
|
||||
bundle.maps[asset.name.replace(/\.map$/, '')] = JSON.parse(
|
||||
compilation.assets[asset.name].source()
|
||||
)
|
||||
Object.keys(compilation.assets).forEach(name => {
|
||||
if (isJS(name)) {
|
||||
bundle.files[name] = compilation.assets[name].source()
|
||||
} else if (name.match(/\.js\.map$/)) {
|
||||
bundle.maps[name.replace(/\.map$/, '')] = JSON.parse(compilation.assets[name].source())
|
||||
}
|
||||
// do not emit anything else for server
|
||||
delete compilation.assets[asset.name]
|
||||
delete compilation.assets[name]
|
||||
})
|
||||
|
||||
const json = JSON.stringify(bundle, null, 2)
|
||||
|
@ -1,31 +1,51 @@
|
||||
const { red, yellow } = require('chalk')
|
||||
const webpack = require('webpack')
|
||||
|
||||
const prefix = `[vue-server-renderer-webpack-plugin]`
|
||||
const warn = (exports.warn = (msg) => console.error(red(`${prefix} ${msg}\n`)))
|
||||
const tip = (exports.tip = (msg) => console.log(yellow(`${prefix} ${msg}\n`)))
|
||||
const warn = exports.warn = msg => console.error(red(`${prefix} ${msg}\n`))
|
||||
const tip = exports.tip = msg => console.log(yellow(`${prefix} ${msg}\n`))
|
||||
|
||||
export const validate = (compiler) => {
|
||||
const isWebpack5 = !!(webpack.version && webpack.version[0] > 4)
|
||||
|
||||
export const validate = compiler => {
|
||||
if (compiler.options.target !== 'node') {
|
||||
warn('webpack config `target` should be "node".')
|
||||
}
|
||||
|
||||
if (
|
||||
compiler.options.output &&
|
||||
compiler.options.output.libraryTarget !== 'commonjs2'
|
||||
) {
|
||||
warn('webpack config `output.libraryTarget` should be "commonjs2".')
|
||||
if (compiler.options.output) {
|
||||
if (compiler.options.output.library) {
|
||||
// Webpack >= 5.0.0
|
||||
if (compiler.options.output.library.type !== 'commonjs2') {
|
||||
warn('webpack config `output.library.type` should be "commonjs2".')
|
||||
}
|
||||
} else if (compiler.options.output.libraryTarget !== 'commonjs2') {
|
||||
// Webpack < 5.0.0
|
||||
warn('webpack config `output.libraryTarget` should be "commonjs2".')
|
||||
}
|
||||
}
|
||||
|
||||
if (!compiler.options.externals) {
|
||||
tip(
|
||||
'It is recommended to externalize dependencies in the server build for ' +
|
||||
'better build performance.'
|
||||
'better build performance.'
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export const onEmit = (compiler, name, hook) => {
|
||||
if (compiler.hooks) {
|
||||
export const onEmit = (compiler, name, stageName, hook) => {
|
||||
if (isWebpack5) {
|
||||
// Webpack >= 5.0.0
|
||||
compiler.hooks.compilation.tap(name, compilation => {
|
||||
if (compilation.compiler !== compiler) {
|
||||
// Ignore child compilers
|
||||
return
|
||||
}
|
||||
const stage = webpack.Compilation[stageName]
|
||||
compilation.hooks.processAssets.tapAsync({ name, stage }, (assets, cb) => {
|
||||
hook(compilation, cb)
|
||||
})
|
||||
})
|
||||
} else if (compiler.hooks) {
|
||||
// Webpack >= 4.0.0
|
||||
compiler.hooks.emit.tapAsync(name, hook)
|
||||
} else {
|
||||
@ -34,4 +54,20 @@ export const onEmit = (compiler, name, hook) => {
|
||||
}
|
||||
}
|
||||
|
||||
export const stripModuleIdHash = id => {
|
||||
if (isWebpack5) {
|
||||
// Webpack >= 5.0.0
|
||||
return id.replace(/\|\w+$/, '')
|
||||
}
|
||||
// Webpack < 5.0.0
|
||||
return id.replace(/\s\w+$/, '')
|
||||
}
|
||||
|
||||
export const getAssetName = asset => {
|
||||
if (typeof asset === 'string') {
|
||||
return asset
|
||||
}
|
||||
return asset.name
|
||||
}
|
||||
|
||||
export { isJS, isCSS } from '../util'
|
||||
|
@ -34,7 +34,7 @@ export function isPrimitive(value: any): boolean {
|
||||
|
||||
/**
|
||||
* Quick object check - this is primarily used to tell
|
||||
* Objects from primitive values when we know the value
|
||||
* objects from primitive values when we know the value
|
||||
* is a JSON-compliant type.
|
||||
*/
|
||||
export function isObject(obj: any): boolean {
|
||||
|
@ -52,7 +52,7 @@ describe('SSR: basicRenderer', () => {
|
||||
})
|
||||
|
||||
// #5941
|
||||
it('should work peoperly when accessing $ssrContext in root component', done => {
|
||||
it('should work properly when accessing $ssrContext in root component', done => {
|
||||
let ssrContext
|
||||
renderToString(new Vue({
|
||||
template: `
|
||||
|
@ -694,6 +694,34 @@ describe('SSR: renderToString', () => {
|
||||
})
|
||||
})
|
||||
|
||||
// #11963, #10391
|
||||
it('renders async children passed in slots', done => {
|
||||
const Parent = {
|
||||
template: `<div><slot name="child"/></div>`
|
||||
}
|
||||
const Child = {
|
||||
template: `<p>child</p>`
|
||||
}
|
||||
renderVmWithOptions({
|
||||
template: `
|
||||
<Parent>
|
||||
<template #child>
|
||||
<Child/>
|
||||
</template>
|
||||
</Parent>
|
||||
`,
|
||||
components: {
|
||||
Parent,
|
||||
Child: () => Promise.resolve(Child)
|
||||
}
|
||||
}, result => {
|
||||
expect(result).toContain(
|
||||
`<div data-server-rendered="true"><p>child</p></div>`
|
||||
)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
||||
it('everything together', done => {
|
||||
renderVmWithOptions({
|
||||
template: `
|
||||
@ -1323,7 +1351,7 @@ describe('SSR: renderToString', () => {
|
||||
</div>
|
||||
`
|
||||
}, result => {
|
||||
expect(result).toContain(`<div class="a\nb"></div>`)
|
||||
expect(result).toContain(`<div class="a b"></div>`)
|
||||
done()
|
||||
})
|
||||
})
|
||||
|
@ -7,7 +7,7 @@ describe('Component async', () => {
|
||||
const oldClearTimeout = window.clearTimeout;
|
||||
|
||||
// will contain pending timeouts set during the test iteration
|
||||
// will contain the id of the timeout as the key, and the the millisecond timeout as the value
|
||||
// will contain the id of the timeout as the key, and the millisecond timeout as the value
|
||||
// this helps to identify the timeout that is still pending
|
||||
let timeoutsPending = {};
|
||||
|
||||
|
@ -572,6 +572,73 @@ describe('Component keep-alive', () => {
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
it('max=1', done => {
|
||||
const spyA = jasmine.createSpy()
|
||||
const spyB = jasmine.createSpy()
|
||||
const spyC = jasmine.createSpy()
|
||||
const spyAD = jasmine.createSpy()
|
||||
const spyBD = jasmine.createSpy()
|
||||
const spyCD = jasmine.createSpy()
|
||||
|
||||
function assertCount (calls) {
|
||||
expect([
|
||||
spyA.calls.count(),
|
||||
spyAD.calls.count(),
|
||||
spyB.calls.count(),
|
||||
spyBD.calls.count(),
|
||||
spyC.calls.count(),
|
||||
spyCD.calls.count()
|
||||
]).toEqual(calls)
|
||||
}
|
||||
|
||||
const vm = new Vue({
|
||||
template: `
|
||||
<keep-alive max="1">
|
||||
<component :is="n"></component>
|
||||
</keep-alive>
|
||||
`,
|
||||
data: {
|
||||
n: 'aa'
|
||||
},
|
||||
components: {
|
||||
aa: {
|
||||
template: '<div>a</div>',
|
||||
created: spyA,
|
||||
destroyed: spyAD
|
||||
},
|
||||
bb: {
|
||||
template: '<div>bbb</div>',
|
||||
created: spyB,
|
||||
destroyed: spyBD
|
||||
},
|
||||
cc: {
|
||||
template: '<div>ccc</div>',
|
||||
created: spyC,
|
||||
destroyed: spyCD
|
||||
}
|
||||
}
|
||||
}).$mount()
|
||||
|
||||
assertCount([1, 0, 0, 0, 0, 0])
|
||||
vm.n = 'bb'
|
||||
waitForUpdate(() => {
|
||||
// should prune A because max cache reached
|
||||
assertCount([1, 1, 1, 0, 0, 0])
|
||||
vm.n = 'cc'
|
||||
}).then(() => {
|
||||
// should prune B because max cache reached
|
||||
assertCount([1, 1, 1, 1, 1, 0])
|
||||
vm.n = 'bb'
|
||||
}).then(() => {
|
||||
// B is recreated
|
||||
assertCount([1, 1, 2, 1, 1, 1])
|
||||
vm.n = 'aa'
|
||||
}).then(() => {
|
||||
// B is destroyed and A recreated
|
||||
assertCount([2, 1, 2, 2, 1, 1])
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
it('should warn unknown component inside', () => {
|
||||
new Vue({
|
||||
template: `<keep-alive><foo/></keep-alive>`
|
||||
@ -1182,5 +1249,37 @@ describe('Component keep-alive', () => {
|
||||
}).then(done)
|
||||
}
|
||||
})
|
||||
|
||||
// #10083
|
||||
it('should not attach event handler repeatedly', done => {
|
||||
const vm = new Vue({
|
||||
template: `
|
||||
<keep-alive>
|
||||
<btn v-if="showBtn" @click.native="add" />
|
||||
</keep-alive>
|
||||
`,
|
||||
data: { showBtn: true, n: 0 },
|
||||
methods: {
|
||||
add () {
|
||||
this.n++
|
||||
}
|
||||
},
|
||||
components: {
|
||||
btn: { template: '<button>add 1</button>' }
|
||||
}
|
||||
}).$mount()
|
||||
|
||||
const btn = vm.$el
|
||||
expect(vm.n).toBe(0)
|
||||
btn.click()
|
||||
expect(vm.n).toBe(1)
|
||||
vm.showBtn = false
|
||||
waitForUpdate(() => {
|
||||
vm.showBtn = true
|
||||
}).then(() => {
|
||||
btn.click()
|
||||
expect(vm.n).toBe(2)
|
||||
}).then(done)
|
||||
})
|
||||
}
|
||||
})
|
||||
|
@ -1325,4 +1325,28 @@ describe('Component scoped slot', () => {
|
||||
expect(vm.$el.textContent).toMatch(`1`)
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
// #11652
|
||||
it('should update when switching between two components with slot and without slot', done => {
|
||||
const Child = {
|
||||
template: `<div><slot/></div>`
|
||||
}
|
||||
|
||||
const parent = new Vue({
|
||||
template: `<div>
|
||||
<child v-if="flag"><template #default>foo</template></child>
|
||||
<child v-else></child>
|
||||
</div>`,
|
||||
data: {
|
||||
flag: true
|
||||
},
|
||||
components: { Child }
|
||||
}).$mount()
|
||||
|
||||
expect(parent.$el.textContent).toMatch(`foo`)
|
||||
parent.flag=false
|
||||
waitForUpdate(()=>{
|
||||
expect(parent.$el.textContent).toMatch(``)
|
||||
}).then(done)
|
||||
})
|
||||
})
|
||||
|
@ -109,6 +109,47 @@ describe('Component slot', () => {
|
||||
expect(child.$el.children[1].textContent).toBe('slot b')
|
||||
})
|
||||
|
||||
it('it should work with previous versions of the templates', () => {
|
||||
const Test = {
|
||||
render() {
|
||||
var _vm = this;
|
||||
var _h = _vm.$createElement;
|
||||
var _c = _vm._self._c || vm._h;
|
||||
return _c('div', [_vm._t("default", [_c('p', [_vm._v("slot default")])])], 2)
|
||||
}
|
||||
}
|
||||
let vm = new Vue({
|
||||
template: `<test/>`,
|
||||
components: { Test }
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe('slot default')
|
||||
vm = new Vue({
|
||||
template: `<test>custom content</test>`,
|
||||
components: { Test }
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe('custom content')
|
||||
})
|
||||
|
||||
it('fallback content should not be evaluated when the parent is providing it', () => {
|
||||
const test = jasmine.createSpy('test')
|
||||
const vm = new Vue({
|
||||
template: '<test>slot default</test>',
|
||||
components: {
|
||||
test: {
|
||||
template: '<div><slot>{{test()}}</slot></div>',
|
||||
methods: {
|
||||
test () {
|
||||
test()
|
||||
return 'test'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}).$mount()
|
||||
expect(vm.$el.textContent).toBe('slot default')
|
||||
expect(test).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('selector matching multiple elements', () => {
|
||||
mount({
|
||||
childTemplate: '<div><slot name="t"></slot></div>',
|
||||
@ -945,4 +986,18 @@ describe('Component slot', () => {
|
||||
expect(vm.$el.firstChild.innerHTML).toBe('<span><b>2</b></span>')
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
// #12102
|
||||
it('v-if inside scoped slot', () => {
|
||||
const vm = new Vue({
|
||||
template: `<test><template #custom><span v-if="false">a</span><span>b</span></template></test>`,
|
||||
components: {
|
||||
test: {
|
||||
template: `<div><slot name="custom"/></div>`
|
||||
}
|
||||
}
|
||||
}).$mount()
|
||||
|
||||
expect(vm.$el.innerHTML).toBe(`<!----><span>b</span>`)
|
||||
})
|
||||
})
|
||||
|
@ -152,6 +152,39 @@ describe('Directive v-bind:class', () => {
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
// css static classes should only contain a single space in between,
|
||||
// as all the text inside of classes is shipped as a JS string
|
||||
// and this could lead to useless spacing in static classes
|
||||
it('condenses whitespace in staticClass', done => {
|
||||
const vm = new Vue({
|
||||
template: '<div class=" test1\ntest2\ttest3 test4 test5 \n \n \ntest6\t"></div>',
|
||||
}).$mount()
|
||||
expect(vm.$el.className).toBe('test1 test2 test3 test4 test5 test6')
|
||||
done()
|
||||
})
|
||||
|
||||
it('condenses whitespace in staticClass merge in a component', done => {
|
||||
const vm = new Vue({
|
||||
template: `
|
||||
<component1 class="\n\t staticClass \t\n" :class="componentClass1">
|
||||
</component1>
|
||||
`,
|
||||
data: {
|
||||
componentClass1: 'componentClass1',
|
||||
},
|
||||
components: {
|
||||
component1: {
|
||||
template: '<div class="\n\t test \t\n"></div>'
|
||||
},
|
||||
}
|
||||
}).$mount()
|
||||
expect(vm.$el.className).toBe('test staticClass componentClass1')
|
||||
vm.componentClass1 = 'c1'
|
||||
waitForUpdate(() => {
|
||||
expect(vm.$el.className).toBe('test staticClass c1')
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
// a vdom patch edge case where the user has several un-keyed elements of the
|
||||
// same tag next to each other, and toggling them.
|
||||
it('properly remove staticClass for toggling un-keyed children', done => {
|
||||
|
@ -31,7 +31,7 @@ describe('Directive v-on', () => {
|
||||
expect(event.type).toBe('click')
|
||||
})
|
||||
|
||||
it('should bind event to a inline statement', () => {
|
||||
it('should bind event to an inline statement', () => {
|
||||
vm = new Vue({
|
||||
el,
|
||||
template: '<div v-on:click="foo(1,2,3,$event)"></div>',
|
||||
@ -218,7 +218,7 @@ describe('Directive v-on', () => {
|
||||
})
|
||||
|
||||
// ctrl, shift, alt, meta
|
||||
it('should support system modifers', () => {
|
||||
it('should support system modifiers', () => {
|
||||
vm = new Vue({
|
||||
el,
|
||||
template: `
|
||||
@ -976,6 +976,17 @@ describe('Directive v-on', () => {
|
||||
expect(value).toBe(1)
|
||||
})
|
||||
|
||||
it('should not execute callback if modifiers are present', () => {
|
||||
vm = new Vue({
|
||||
el,
|
||||
template: '<input @keyup.?="foo">',
|
||||
methods: { foo: spy }
|
||||
})
|
||||
// simulating autocomplete event (Event object with type keyup but without keyCode)
|
||||
triggerEvent(vm.$el, 'keyup')
|
||||
expect(spy.calls.count()).toBe(0)
|
||||
})
|
||||
|
||||
describe('dynamic arguments', () => {
|
||||
it('basic', done => {
|
||||
const spy = jasmine.createSpy()
|
||||
|
@ -127,25 +127,25 @@ describe('Error handling', () => {
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
it('should recover from errors in user watcher callback', done => {
|
||||
const vm = createTestInstance(components.userWatcherCallback)
|
||||
vm.n++
|
||||
waitForUpdate(() => {
|
||||
expect(`Error in callback for watcher "n"`).toHaveBeenWarned()
|
||||
expect(`Error: userWatcherCallback`).toHaveBeenWarned()
|
||||
}).thenWaitFor(next => {
|
||||
assertBothInstancesActive(vm).end(next)
|
||||
}).then(done)
|
||||
})
|
||||
;[
|
||||
['userWatcherCallback', 'watcher'],
|
||||
['userImmediateWatcherCallback', 'immediate watcher']
|
||||
].forEach(([type, description]) => {
|
||||
it(`should recover from errors in user ${description} callback`, done => {
|
||||
const vm = createTestInstance(components[type])
|
||||
assertBothInstancesActive(vm).then(() => {
|
||||
expect(`Error in callback for ${description} "n"`).toHaveBeenWarned()
|
||||
expect(`Error: ${type} error`).toHaveBeenWarned()
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
it('should recover from errors in user immediate watcher callback', done => {
|
||||
const vm = createTestInstance(components.userImmediateWatcherCallback)
|
||||
waitForUpdate(() => {
|
||||
expect(`Error in callback for immediate watcher "n"`).toHaveBeenWarned()
|
||||
expect(`Error: userImmediateWatcherCallback error`).toHaveBeenWarned()
|
||||
}).thenWaitFor(next => {
|
||||
assertBothInstancesActive(vm).end(next)
|
||||
}).then(done)
|
||||
it(`should recover from promise errors in user ${description} callback`, done => {
|
||||
const vm = createTestInstance(components[`${type}Async`])
|
||||
assertBothInstancesActive(vm).then(() => {
|
||||
expect(`Error in callback for ${description} "n" (Promise/async)`).toHaveBeenWarned()
|
||||
expect(`Error: ${type} error`).toHaveBeenWarned()
|
||||
}).then(done)
|
||||
})
|
||||
})
|
||||
|
||||
it('config.errorHandler should capture render errors', done => {
|
||||
@ -359,6 +359,33 @@ function createErrorTestComponents () {
|
||||
}
|
||||
}
|
||||
|
||||
components.userWatcherCallbackAsync = {
|
||||
props: ['n'],
|
||||
watch: {
|
||||
n () {
|
||||
return Promise.reject(new Error('userWatcherCallback error'))
|
||||
}
|
||||
},
|
||||
render (h) {
|
||||
return h('div', this.n)
|
||||
}
|
||||
}
|
||||
|
||||
components.userImmediateWatcherCallbackAsync = {
|
||||
props: ['n'],
|
||||
watch: {
|
||||
n: {
|
||||
immediate: true,
|
||||
handler () {
|
||||
return Promise.reject(new Error('userImmediateWatcherCallback error'))
|
||||
}
|
||||
}
|
||||
},
|
||||
render (h) {
|
||||
return h('div', this.n)
|
||||
}
|
||||
}
|
||||
|
||||
// event errors
|
||||
components.event = {
|
||||
beforeCreate () {
|
||||
|
@ -14,7 +14,7 @@ describe('Global API: set/delete', () => {
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
it('should update a observing object', done => {
|
||||
it('should update an observing object', done => {
|
||||
const vm = new Vue({
|
||||
template: '<div>{{foo.x}}</div>',
|
||||
data: { foo: { x: 1 }}
|
||||
@ -26,7 +26,7 @@ describe('Global API: set/delete', () => {
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
it('should update a observing array', done => {
|
||||
it('should update an observing array', done => {
|
||||
const vm = new Vue({
|
||||
template: '<div><div v-for="v,k in list">{{k}}-{{v}}</div></div>',
|
||||
data: { list: ['a', 'b', 'c'] }
|
||||
|
@ -206,6 +206,18 @@ describe('Options computed', () => {
|
||||
expect(`computed property "a" is already defined as a prop`).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('warn conflict with methods', () => {
|
||||
new Vue({
|
||||
computed: {
|
||||
a: () => 2
|
||||
},
|
||||
methods: {
|
||||
a: () => {}
|
||||
}
|
||||
})
|
||||
expect(`computed property "a" is already defined as a method`).toHaveBeenWarned()
|
||||
})
|
||||
|
||||
it('rethrow computed error', () => {
|
||||
const vm = new Vue({
|
||||
computed: {
|
||||
|
@ -247,4 +247,152 @@ describe('Options errorCaptured', () => {
|
||||
expect(store.errors[0]).toEqual(new Error('render error'))
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
it('should capture error from watcher', done => {
|
||||
const spy = jasmine.createSpy()
|
||||
|
||||
let child
|
||||
let err
|
||||
const Child = {
|
||||
data () {
|
||||
return {
|
||||
foo: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
foo () {
|
||||
err = new Error('userWatcherCallback error')
|
||||
throw err
|
||||
}
|
||||
},
|
||||
created () {
|
||||
child = this
|
||||
},
|
||||
render () {}
|
||||
}
|
||||
|
||||
new Vue({
|
||||
errorCaptured: spy,
|
||||
render: h => h(Child)
|
||||
}).$mount()
|
||||
|
||||
child.foo = 'bar'
|
||||
|
||||
waitForUpdate(() => {
|
||||
expect(spy).toHaveBeenCalledWith(err, child, 'callback for watcher "foo"')
|
||||
expect(globalSpy).toHaveBeenCalledWith(err, child, 'callback for watcher "foo"')
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
it('should capture promise error from watcher', done => {
|
||||
const spy = jasmine.createSpy()
|
||||
|
||||
let child
|
||||
let err
|
||||
const Child = {
|
||||
data () {
|
||||
return {
|
||||
foo: null
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
foo () {
|
||||
err = new Error('userWatcherCallback error')
|
||||
return Promise.reject(err)
|
||||
}
|
||||
},
|
||||
created () {
|
||||
child = this
|
||||
},
|
||||
render () {}
|
||||
}
|
||||
|
||||
new Vue({
|
||||
errorCaptured: spy,
|
||||
render: h => h(Child)
|
||||
}).$mount()
|
||||
|
||||
child.foo = 'bar'
|
||||
|
||||
child.$nextTick(() => {
|
||||
waitForUpdate(() => {
|
||||
expect(spy).toHaveBeenCalledWith(err, child, 'callback for watcher "foo" (Promise/async)')
|
||||
expect(globalSpy).toHaveBeenCalledWith(err, child, 'callback for watcher "foo" (Promise/async)')
|
||||
}).then(done)
|
||||
})
|
||||
})
|
||||
|
||||
it('should capture error from immediate watcher', done => {
|
||||
const spy = jasmine.createSpy()
|
||||
|
||||
let child
|
||||
let err
|
||||
const Child = {
|
||||
data () {
|
||||
return {
|
||||
foo: 'foo'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
foo: {
|
||||
immediate: true,
|
||||
handler () {
|
||||
err = new Error('userImmediateWatcherCallback error')
|
||||
throw err
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
child = this
|
||||
},
|
||||
render () {}
|
||||
}
|
||||
|
||||
new Vue({
|
||||
errorCaptured: spy,
|
||||
render: h => h(Child)
|
||||
}).$mount()
|
||||
|
||||
waitForUpdate(() => {
|
||||
expect(spy).toHaveBeenCalledWith(err, child, 'callback for immediate watcher "foo"')
|
||||
expect(globalSpy).toHaveBeenCalledWith(err, child, 'callback for immediate watcher "foo"')
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
it('should capture promise error from immediate watcher', done => {
|
||||
const spy = jasmine.createSpy()
|
||||
|
||||
let child
|
||||
let err
|
||||
const Child = {
|
||||
data () {
|
||||
return {
|
||||
foo: 'foo'
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
foo: {
|
||||
immediate: true,
|
||||
handler () {
|
||||
err = new Error('userImmediateWatcherCallback error')
|
||||
return Promise.reject(err)
|
||||
}
|
||||
}
|
||||
},
|
||||
created () {
|
||||
child = this
|
||||
},
|
||||
render () {}
|
||||
}
|
||||
|
||||
new Vue({
|
||||
errorCaptured: spy,
|
||||
render: h => h(Child)
|
||||
}).$mount()
|
||||
|
||||
waitForUpdate(() => {
|
||||
expect(spy).toHaveBeenCalledWith(err, child, 'callback for immediate watcher "foo" (Promise/async)')
|
||||
expect(globalSpy).toHaveBeenCalledWith(err, child, 'callback for immediate watcher "foo" (Promise/async)')
|
||||
}).then(done)
|
||||
})
|
||||
})
|
||||
|
@ -196,7 +196,7 @@ describe('codegen', () => {
|
||||
it('generate slot fallback content', () => {
|
||||
assertCodegen(
|
||||
'<div><slot><div>hi</div></slot></div>',
|
||||
`with(this){return _c('div',[_t("default",[_c('div',[_v("hi")])])],2)}`
|
||||
`with(this){return _c('div',[_t("default",function(){return [_c('div',[_v("hi")])]})],2)}`
|
||||
)
|
||||
})
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
import Vue from 'vue'
|
||||
import { SSR_ATTR } from 'shared/constants'
|
||||
|
||||
describe('vdom patch: edge cases', () => {
|
||||
// exposed by #3406
|
||||
@ -432,4 +433,22 @@ describe('vdom patch: edge cases', () => {
|
||||
expect(vm.$el.textContent).not.toMatch('Infinity')
|
||||
}).then(done)
|
||||
})
|
||||
|
||||
it('should not throw when hydrated pending async component is patched by v-if="false"', done => {
|
||||
const PendingAsyncComponent = () => new Promise(() => {})
|
||||
const ssrAsyncComponent = document.createElement('div')
|
||||
ssrAsyncComponent.setAttribute(SSR_ATTR, 'true')
|
||||
const vm = new Vue({
|
||||
data: {
|
||||
visible: true
|
||||
},
|
||||
components: {
|
||||
PendingAsyncComponent
|
||||
},
|
||||
template: '<pending-async-component v-if="visible"></pending-async-component>'
|
||||
}).$mount(ssrAsyncComponent)
|
||||
|
||||
vm.visible = false
|
||||
vm.$nextTick(done)
|
||||
})
|
||||
})
|
||||
|
15
types/options.d.ts
vendored
15
types/options.d.ts
vendored
@ -12,9 +12,10 @@ export type Component<Data=DefaultData<never>, Methods=DefaultMethods<never>, Co
|
||||
| FunctionalComponentOptions<Props>
|
||||
| ComponentOptions<never, Data, Methods, Computed, Props>
|
||||
|
||||
interface EsModuleComponent {
|
||||
default: Component
|
||||
}
|
||||
type EsModule<T> = T | { default: T }
|
||||
|
||||
type ImportedComponent<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps>
|
||||
= EsModule<Component<Data, Methods, Computed, Props>>
|
||||
|
||||
export type AsyncComponent<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps>
|
||||
= AsyncComponentPromise<Data, Methods, Computed, Props>
|
||||
@ -23,12 +24,12 @@ export type AsyncComponent<Data=DefaultData<never>, Methods=DefaultMethods<never
|
||||
export type AsyncComponentPromise<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps> = (
|
||||
resolve: (component: Component<Data, Methods, Computed, Props>) => void,
|
||||
reject: (reason?: any) => void
|
||||
) => Promise<Component | EsModuleComponent> | void;
|
||||
) => Promise<ImportedComponent<Data, Methods, Computed, Props>> | void;
|
||||
|
||||
export type AsyncComponentFactory<Data=DefaultData<never>, Methods=DefaultMethods<never>, Computed=DefaultComputed, Props=DefaultProps> = () => {
|
||||
component: AsyncComponentPromise<Data, Methods, Computed, Props>;
|
||||
loading?: Component | EsModuleComponent;
|
||||
error?: Component | EsModuleComponent;
|
||||
component: Promise<ImportedComponent<Data, Methods, Computed, Props>>;
|
||||
loading?: ImportedComponent;
|
||||
error?: ImportedComponent;
|
||||
delay?: number;
|
||||
timeout?: number;
|
||||
}
|
||||
|
44
types/test/async-component-test.ts
Normal file
44
types/test/async-component-test.ts
Normal file
@ -0,0 +1,44 @@
|
||||
import Vue, { AsyncComponent, Component } from "../index";
|
||||
|
||||
const a: AsyncComponent = () => ({
|
||||
component: new Promise<Component>((res, rej) => {
|
||||
res({ template: "" })
|
||||
})
|
||||
})
|
||||
|
||||
const b: AsyncComponent = () => ({
|
||||
// @ts-expect-error component has to be a Promise that resolves to a component
|
||||
component: () =>
|
||||
new Promise<Component>((res, rej) => {
|
||||
res({ template: "" })
|
||||
})
|
||||
})
|
||||
|
||||
const c: AsyncComponent = () =>
|
||||
new Promise<Component>((res, rej) => {
|
||||
res({
|
||||
template: ""
|
||||
})
|
||||
})
|
||||
|
||||
const d: AsyncComponent = () =>
|
||||
new Promise<{ default: Component }>((res, rej) => {
|
||||
res({
|
||||
default: {
|
||||
template: ""
|
||||
}
|
||||
})
|
||||
})
|
||||
|
||||
const e: AsyncComponent = () => ({
|
||||
component: new Promise<{ default: Component }>((res, rej) => {
|
||||
res({
|
||||
default: {
|
||||
template: ""
|
||||
}
|
||||
})
|
||||
})
|
||||
})
|
||||
|
||||
// Test that Vue.component accepts any AsyncComponent
|
||||
Vue.component("async-compponent1", a)
|
2
types/vue.d.ts
vendored
2
types/vue.d.ts
vendored
@ -26,7 +26,7 @@ export interface Vue {
|
||||
readonly $parent: Vue;
|
||||
readonly $root: Vue;
|
||||
readonly $children: Vue[];
|
||||
readonly $refs: { [key: string]: Vue | Element | Vue[] | Element[] };
|
||||
readonly $refs: { [key: string]: Vue | Element | (Vue | Element)[] | undefined };
|
||||
readonly $slots: { [key: string]: VNode[] | undefined };
|
||||
readonly $scopedSlots: { [key: string]: NormalizedScopedSlot | undefined };
|
||||
readonly $isServer: boolean;
|
||||
|
2
typescript/component.d.ts
vendored
2
typescript/component.d.ts
vendored
@ -110,7 +110,7 @@ declare class Component {
|
||||
_render: () => VNode;
|
||||
|
||||
__patch__: (
|
||||
a: Element | VNode | void,
|
||||
a: Element | VNode | void | null,
|
||||
b: VNode | null,
|
||||
hydrating?: boolean,
|
||||
removeOnly?: boolean,
|
||||
|
Loading…
Reference in New Issue
Block a user